2011年1月4日 星期二

使用剪貼簿的方式將 ANSI 字串轉成 Unicode 字串

作者: spider391 (小乖) 看板: C_and_CPP
標題: [心得] 使用剪貼簿的方式將 ANSI 字串轉成 Unicode 字串
時間: Thu Sep 24 16:13:01 2009


VC6.0 的 programmer 使用 Visual Studio 2005 常常會遇到 unicode 的問題,
尤其是將 C runtime library 與 win32 API 混用的情況。

C runtime library 接收的字串是使用 ANSI 字元集,
而 win32 API 接受的是 unicode。

解決方法很多種:
1. 在 visual studio 2005 的 compiler 選項中不定義 UNICODE
   (參考 http://mqjing.blogspot.com/2008/05/c-fprintf-unicode.html)
2. 利用 MultiByteToWideChar or WideCharToMultiByte 轉換
   (這兩個函式有點複雜,我一直沒有弄懂過@@)
3. 使用一些高級的函式庫如: boost
   (還沒試過,不過聽說這個很好用...)
4. 使用 C 程式庫的寬字元版本

5. 剪貼簿


最近看到剪貼簿 (Clipboard) 的使用方式,看到了其中一段

"我有一些好消息,在處理您所想要的文字格式時,您只需要呼叫  SetClipboardData 和
 GetClipboardData,
 Winodws 將處理剪貼簿中所有的文字轉換..."  (by Programming Windows 中文版)

看到這一段時,我馬上跳了起來,想說利用剪貼簿做 ANSI 和 Unicode 的轉換應該是有
點搞頭!!
我利用以下的程式案例說明:


案例:

在 current 目錄下,新增一個文字檔,檔名由使用者輸入。

程式流程:
1. 取得目前目錄 path
2. 使用者輸入檔名
3. 將使用者檔名加入 path
4. 開啟檔案 檔案處理 關閉檔案

VC 6.0
=====================================================
#include
#include

        int main()
        {
        //1. 取得目前目錄 path
        char pszBuffer[MAX_PATH];
        ::GetCurrentDirectory(MAX_PATH,pszBuffer);

        //2. 使用者輸入檔名
        printf("please input file name:\n");
        char pszFileName[32];
        scanf("%s",pszFileName);

        //3. 將使用者檔名加入 path
        sprintf(pszBuffer,"%s\\%s",pszBuffer,pszFileName);

        //4. 開啟檔案 檔案處理 關閉檔案
        FILE *fptr =  fopen(pszBuffer , "w");
        fprintf(fptr,"我想要變身西裝\n");
        fclose(fptr);
        }
=======================================================

此段 code 在 VC6.0 跑是沒問題 可是轉換成 visual studio 2005 的時候,
因為 win32 API 接受 unicode 所以要想辦法將 ANSI 字串轉成 unicode 字串。

以下利用剪貼簿來實作字串的轉換

Visual Studio 2005
=======================================================
#include
#include
int _tmain(int argc, _TCHAR* argv[])
{
        //1. 取得目前目錄 path
        TCHAR pszBuffer[MAX_PATH];
        ::GetCurrentDirectory(MAX_PATH,pszBuffer);

        //2. 使用者輸入檔名
        printf("please input file name:\n");
        char pszFileName[32];
        scanf("%s",pszFileName);

        //3. 將使用者檔名加入 path

        //把 ANSI 字串複製到剪貼簿
        HGLOBAL hGlobal = GlobalAlloc (GHND | GMEM_SHARE,
                (strlen (pszFileName) + 1) * sizeof (char)) ;
        PTSTR pGlobal = (PTSTR)GlobalLock (hGlobal) ;
        strcpy ((char*)pGlobal, pszFileName) ;
        GlobalUnlock (hGlobal) ;

        OpenClipboard (NULL) ;
        EmptyClipboard () ;
        SetClipboardData (CF_TEXT, hGlobal) ;
        CloseClipboard () ;


        //從剪貼簿取得 Unicode 字串
        OpenClipboard (NULL) ;
        hGlobal = GetClipboardData (CF_UNICODETEXT);
        pGlobal = (PTSTR)GlobalLock (hGlobal) ;
        TCHAR* pText = (TCHAR*)malloc (GlobalSize (hGlobal)) ;
        lstrcpy (pText, pGlobal) ;
        CloseClipboard () ;

        //將使用者檔名加入 path
        wsprintf(pszBuffer,TEXT("%s\\%s"),pszBuffer,pText);

        //4. 開啟檔案 檔案處理 關閉檔案
        FILE *fptr =  _tfopen(pszBuffer , L"w");
        fprintf(fptr,"輪不到你\n");
        fclose(fptr);
        return 0;
}
==================================================================

其中最重要的兩段

//把 ANSI 字串送到剪貼簿
SetClipboardData (CF_TEXT, hGlobal) ;

//從剪貼簿取得 Unicode 字串
hGlobal = GetClipboardData (CF_UNICODETEXT);

這種中間我並沒有作任何字串的轉換,因為  Windows 幫我做好了 XD


不過此方法我不知道會不會讓效能變差,
還有剪貼簿被別的 process 改掉可能會導致程式出錯。

這是我的一些心得,請各位大大給一些意見。









--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 115.81.197.99
[1;37m推 [33midleidle [m [33m:先推再看                                              [m 09/24 16:18

沒有留言:

張貼留言

您好.本資料庫並非第一手資料.如果你有對文章作者的詢問,意見與需求,請自行找尋文章作者並提供意見,謝謝.