VBAからGDI+を使う資料集
inet上の達人の方々から御教示いただいたコードを少しアレンジさせてもらっています(切り貼りとも言います)。
  1. ホーム
  2. Win32SDK
  3. listview


Excelへのコピペツール

結合行数・列数が異なるエクセルの結合セル間でコピペをしようとして、「この操作には、同じサイズの結合セルが必要です。」というエラーメッセージに悩まされ、UserFormを用いたコピペツールを作成して、アドイン化して使用しておりますが、エクセルと独立したツールが出来れば便利かなと思って作成してみました。
エクセルその他のアプリからクリップボードにコピーしたデータをListViewにスプレッドシート風に表示し、Wクリックで目的アプリ(標準はエクセルですが、他アプリも可)に貼り付けます。

プログラムの機能(メニュー)
--------------------------
ファイル(F)    終了のみ
更新(R)    クリップボードのデータの再読込
切替(H)    他アプリのハンドルを取得して、貼り付け先に指定
改行(E)    確定時の改行の個数設定(0, 1, 2)


☆Cソース
//Libraryの在処
//C:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\Lib\ComCtl32.Lib

//これを入れないとINPUT構造体が有効にならない
#define _WIN32_WINNT 0x0500

#define STRICT
#define ID_LISTVIEW 100
#define ID_MYCHILD 110
#define T_BUFFER 1024
#define COLUMN_WIDTH 120
//クリップボードから読みこむ文字列の最大サイズ
#define MAX_READCB 1024 * 64
//文字列の動的配列の際に確保する個々のサイズ
#define MALLOC_UNIT 1024

//ユーザ領域のメッセージを定義
#define WM_START_CAPTURE (WM_APP + 1)

#include "resource.h"
#include <windows.h>
#include <commctrl.h>
#include <tchar.h>
#include <string.h>
//マルチバイト→Unicodeに必要
#include <locale.h>
//IMEの名前制御用 imm32.libをプロジェクトに参加要→結局IMEの判別は64bitOSでうまくいかず断念している
#include <imm.h>

/////////////////////////////////////////////////////////////////////////////
// プロトタイプ宣言

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ChildProc(HWND, UINT, WPARAM, LPARAM);

BOOL InitApp(HINSTANCE, WNDPROC, LPCTSTR);
BOOL InitInstance(HINSTANCE, int, LPCTSTR);

////////////////////////////////////////////////////////
// ユーザー関数

int PasteFromCB(HWND hWnd, char *szStr, int &szSize);
int ReadClip(HWND hwnd, char *str);
//文字列の配列渡しの例(*cells)[256]の形でプロトタイプ宣言する必要がある
//実際に引数で渡すときはcellsで良い。
//int SplitTAB(char *row, char (**cells)[256], int &cellscount);
int SplitTAB(char *row, char **cells, int &cellscount);
int WriteClip(HWND hWnd, char *str);
int ReadClip(HWND, char *);
int PasteFromCB(HWND hWnd);
void KeyInput(char *,HWND);
void VKeyInput(int  , int);
int myActivateWindow(HWND hWnd);
void listview_delallcoloumn(HWND hlistview);
int set_listview(HWND hWnd, HWND hlist);
HWND MakeMyList(HWND hWnd);
void ShowMyText(HWND hWnd);

//////////////////////////////////////////////////////////////
// グローバル変数

HINSTANCE hInst;

//ファイルの各行を読みこむ文字列の動的配列
char **mylist;
int mylistcount = 0;

//セル情報の動的配列
char **mycell;
int mycellcount = 0;

//マウスキャプチャー中のフラグ
BOOL bCap = FALSE;

//改行コード送信回数設定
int CRcount = 0;

bool IsEmpty = true;

HWND hXl; //エクセルのハンドル
HWND hKeep;

/////////////////////////////////////////////////////////////////////////
int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst,
                   LPSTR lpsCmdLine, int nCmdShow)
{
    MSG msg;
    LPCTSTR szClassName = "listView01";
    
    if (!hPrevInst) {
        if (!InitApp(hCurInst, WndProc, szClassName))
            return FALSE;
    }
    if (!InitInstance(hCurInst, nCmdShow, szClassName)) {
        return FALSE;
    }
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return (int)msg.wParam;
}

/////////////////////////////////////////////////////////////////////////
//ウィンドウ・クラスの登録

BOOL InitApp(HINSTANCE hInst, WNDPROC WndProc, LPCTSTR szClassName)
{
    WNDCLASS wc;
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInst;
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName = "MYMENU";
    wc.lpszClassName = (LPCSTR)szClassName;
    return (RegisterClass(&wc));
}

/////////////////////////////////////////////////////////////////////////
//ウィンドウの生成

BOOL InitInstance(HINSTANCE hInst, int nCmdShow, LPCTSTR szClassName)
{
    HWND hWnd;

    hWnd = CreateWindow(szClassName,
            "エクセルデータ転記",
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            200,
            100,
            NULL,
            NULL,
            hInst,
            NULL);
    if (!hWnd)
        return FALSE;
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
	//最前面表示
	SetWindowPos(hWnd , HWND_TOPMOST ,0 , 0 , 0 , 0 ,SWP_NOMOVE | SWP_NOSIZE );

    return TRUE;
}

/////////////////////////////////////////////////////////////////////////
//ウィンドウプロシージャ

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
    static HWND hList;
	static HWND hChdWnd;

	HINSTANCE hInst;

    LV_ITEM item;//リストビューのアイテム設定用
	LV_HITTESTINFO	lvhti;//HITTEST設定用
    LV_DISPINFO *lvinfo;
    char buf[T_BUFFER];
    static HWND hEdit;
	//カスタムドロー(一行おきに行の着色)
    //LPNMLISTVIEW lplv;
    LPNMLVCUSTOMDRAW lplvcd;
    static HFONT hCustomFont, hOrgFont;
	//マウスキャプチャー中かのフラグ
	static bool captureFlag;
	int ret;

	//かな漢字変換情報取得用 - 結局使っていません
	HKL hKl;
	char szName[1024];
	//IMEの名前比較用
	char    *sp;

    switch (msg) {
        case WM_CREATE:

			//エクセルのハンドル取得
			//ここで取得できなかったとき、いつ取得するかという問題があるので
			//エクセルのハンドルが取得できなければ終了する様にしてある
			hXl = FindWindow(TEXT("XLMAIN"),NULL);
			if (hXl == NULL){
				MessageBox(hXl, "エクセルが起動されていません", "OK", MB_OK);
				DestroyWindow(hWnd);
				break;
			}
			hKeep = hXl; // エクセルのハンドルを保存
			hInst = ((LPCREATESTRUCT)lp)->hInstance;
					InitApp(hInst,
						ChildProc,
						"child");
					hChdWnd = CreateWindow("child",
					"他アプリのハンドル取得",//タイトルバーにこの名前が表示されます
					WS_CHILD | WS_SYSMENU | WS_THICKFRAME | WS_CAPTION ,    //ウィンドウの種類
					CW_USEDEFAULT,    //X座標
					CW_USEDEFAULT,    //Y座標
					200,    //幅
					100,    //高さ
					hWnd,            //親ウィンドウのハンドル、親を作るときはNULL
					(HMENU)ID_MYCHILD, //メニューハンドル、子供のID
					hInst,            //インスタンスハンドル
					NULL);
					
			ShowWindow(hChdWnd, SW_HIDE);
			UpdateWindow(hChdWnd);
			SetWindowPos(hChdWnd , HWND_TOPMOST ,0 , 0 , 0 , 0 ,SWP_NOMOVE | SWP_NOSIZE );

			SetCursor(LoadCursor(NULL, IDC_ARROW));
			//メニューの操作
			CRcount = 0;
			EnableMenuItem(GetMenu(hWnd), ID_CR1, MF_ENABLED);
			EnableMenuItem(GetMenu(hWnd), ID_CR2, MF_ENABLED);
            EnableMenuItem(GetMenu(hWnd), ID_CR0, MF_GRAYED);
            InvalidateRect(hWnd, NULL, TRUE);

			/*
			//IMEがATOKか否か調査 - 64bitOSでうまくいかないので没
			ret = GetWindowThreadProcessId(hXl,NULL);
			if (ret == 0) MessageBox(hXl, "ProcessID取得失敗", "OK", MB_OK);
			long long ret2;

			hKl =  GetKeyboardLayout(GetWindowThreadProcessId(hXl,NULL));
			if (!ImmIsIME(hKl)) {
				MessageBox(hXl, "IMEを持っていません", "OK", MB_OK);
				return FALSE;
			}
			ImmGetDescription(hKl, szName, 64);
			//ATOK または Microsoft IME standard
			MessageBox(hWnd, szName, "IMEの種類", MB_OK);
			sp = strstr(szName,"ATOK");
			if (sp != NULL)
			{
				IsATOK = true;
				MessageBox(hWnd, "IMEはATOKです", "IMEの種類", MB_OK);
			}else{
				IsATOK = false;
			}
			*/

			InitCommonControls();
			hList = MakeMyList(hWnd);

			//文字列の動的配列の初期化 100個分を確保
			mylist=(char**)malloc(sizeof(char*) * 100);
			mylistcount = 100;
			
			//クリップボードから文字列を読みこみ、改行とTABでSplitしてlistviewに設定
			ret = set_listview(hWnd, hList);
            break;

		case WM_COMMAND:
            switch (LOWORD(wp)) {
				//改行送信の有無切り替え
				case ID_CR0:
					CRcount = 0;//IsCRLF = false;
					EnableMenuItem(GetMenu(hWnd), ID_CR1, MF_ENABLED);
					EnableMenuItem(GetMenu(hWnd), ID_CR2, MF_ENABLED);
                    EnableMenuItem(GetMenu(hWnd), ID_CR0, MF_GRAYED);
                    InvalidateRect(hWnd, NULL, TRUE);
					break;

				case ID_CR1:
					CRcount = 1;//IsCRLF = false;
					EnableMenuItem(GetMenu(hWnd), ID_CR0, MF_ENABLED);
					EnableMenuItem(GetMenu(hWnd), ID_CR2, MF_ENABLED);
                    EnableMenuItem(GetMenu(hWnd), ID_CR1, MF_GRAYED);
                    InvalidateRect(hWnd, NULL, TRUE);
					break;

				case ID_CR2:
					CRcount = 2;//IsCRLF = false;
					EnableMenuItem(GetMenu(hWnd), ID_CR0, MF_ENABLED);
					EnableMenuItem(GetMenu(hWnd), ID_CR1, MF_ENABLED);
                    EnableMenuItem(GetMenu(hWnd), ID_CR2, MF_GRAYED);
                    InvalidateRect(hWnd, NULL, TRUE);
					break;
		
				case IDM_XL:
					MessageBox(hWnd, "貼付先をエクセルに戻します", "Excel", MB_OK);
					hXl = hKeep;
					break;
                case IDM_END:
                    SendMessage(hWnd, WM_CLOSE, 0, 0);
                    break;
				//クリップボードから再取得
                case IDM_DEL:
					//全アイテムを消す
					ListView_DeleteAllItems(hList);
					//カラムを全て削除。全アイテム削除と一緒に使わないとゴミが残るらしい
					listview_delallcoloumn(hList);
					//クリップボードから文字列を読みこみ、改行とTABでSplitしてlistviewに設定
					ret = set_listview(hWnd,hList);
					break;
				//子ウィンドウを表示し、マウスキャプチャーで他アプリのハンドル取得
				case IDM_HWD:
					ShowWindow(hChdWnd, SW_SHOW);
					SendMessage(hChdWnd,WM_START_CAPTURE,0,0);
					break;
					
			}
			break;

		case WM_NOTIFY:
            if ((int)wp == ID_LISTVIEW) {
                lvinfo = (LV_DISPINFO *)lp;
                switch (lvinfo->hdr.code) {
					//http://bu-nyan.m.to/sdk/sdk18.htm
					case NM_DBLCLK://項目をダブルクリックしたときに!NM_DBLCLK
							//マウスカーソルの座標を取得します。
							GetCursorPos((LPPOINT)&lvhti.pt);
							//ScreenToClient(((LPNMLISTVIEW)lP)->hdr.hwndFrom, &lvhti.pt);
							ScreenToClient(lvinfo->hdr.hwndFrom ,&lvhti.pt);
							//ListView_HitTest(((LPNMLISTVIEW)lP)->hdr.hwndFrom, &lvhti);

							//マウスカーソルがリストビューの項目上にあるかどうかを判定します。
							//サブアイテムも取得したいときは、下記を使う
							ListView_SubItemHitTest(lvinfo->hdr.hwndFrom, &lvhti);

							if (lvhti.flags & LVHT_ONITEM){
								item.mask = TVIF_HANDLE | TVIF_TEXT;
								item.iItem = lvhti.iItem;//取得アイテムの番号
								item.iSubItem = lvhti.iSubItem;
								item.pszText=buf;//格納するテキストバッファ
								item.cchTextMax=T_BUFFER;//バッファ容量
								ListView_GetItem(lvinfo->hdr.hwndFrom, &item);
								WriteClip(hWnd, buf);

								//エクセルをアクティブにする
								myActivateWindow(hXl);
								//エクセルに選択されたデータとRETURNを送る
								//複数のエクセルが開いているときは?未検証。
								//今回動作しているが、1文字ずつ送って、間にSleepを入れないと取りこぼすという記事あり
								KeyInput(buf,hWnd);
								for (int i = 0; i < CRcount; i++){
									Sleep(50);
									VKeyInput(VK_RETURN , 1);
									}
							}
							break;

					case NM_CUSTOMDRAW :
						// カスタムドローで、Listviewの色を設定。
						//http://www.kumei.ne.jp/c_lang/sdk3/sdk_261.htm

							lplvcd = (LPNMLVCUSTOMDRAW)lp;
							if (lplvcd->nmcd.dwDrawStage == CDDS_PREPAINT)
								return CDRF_NOTIFYITEMDRAW;
							if (lplvcd->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) {
								if (lplvcd->nmcd.dwItemSpec % 2){
									SelectObject(lplvcd->nmcd.hdc, hCustomFont);
									lplvcd->clrTextBk = RGB(204, 255, 204);
									lplvcd->clrText = RGB(0, 0, 102);
									return CDRF_NEWFONT;
								}
							}
							break;
                }
            }
            break;

        case WM_SIZE:
            MoveWindow(hList, 0, 0, LOWORD(lp), HIWORD(lp), TRUE);
            break;
        case WM_CLOSE:
            //id = MessageBox(hWnd,
            //    "終了してもよいですか",
            //    "終了確認",
            //    MB_YESNO | MB_ICONQUESTION);
            //if (id == IDYES) {
            //    DestroyWindow(hWnd);
            //}

			if (IsEmpty != true)
			{
				//文字列の動的配列用に確保したメモリの解放
				for ( int i = 0; i < mylistcount; i++)
					free(mylist[i]);
				free(mylist);
			}
            DestroyWindow(hWnd);
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return (DefWindowProc(hWnd, msg, wp, lp));
    }
    return 0L;
}

//listviewに追加する箇所の統一化
int set_listview(HWND hWnd, HWND hList)
{
	LV_COLUMN lvcol;//リストビューのカラム設定用
    LV_ITEM item;//リストビューのアイテム設定用
	
	RECT rcf;
	RECT rcc;
	SIZE fsize;
	//クリップボードから読みこんだ文字列を収納する配列
    char szStr[MAX_READCB];
	//同配列に納められたデータ数
	int szSize;
	int cellcount; //一行のセル数
	int ret;
	int totalColumnWidth = 0;
	int maxTotalColWidth = 0;
    char buf[T_BUFFER];

	//クリップボードから読み出し
	ret = PasteFromCB(hWnd , szStr, szSize);
	if (ret != 0 ) return 0;
	else IsEmpty = false;

	//セルの個数を取得
	//クリップボード空からの再読込でアクセス違反発生
	//mycellcount=0のため追加->Debugモードだと、各変数の値が確認できる
	mycell = (char**)malloc(sizeof(char*) * 100);
	mycellcount = 100;

	ret = SplitTAB( mylist[0], mycell, cellcount);
	for ( int i = 0; i < mycellcount; i++)
		free(mycell[i]);
	free(mycell);
	//見出しの生成
	lvcol.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
	lvcol.fmt = LVCFMT_LEFT;

	for (int i = 0; i <= cellcount; i++){
		lvcol.cx = COLUMN_WIDTH;
		wsprintf( buf, "F%d", i + 1 );
		lvcol.pszText = buf;
		lvcol.iSubItem = i;
		ListView_InsertColumn(hList, i, &lvcol);

	}
	item.mask = LVIF_TEXT;

	//リストビューに追加
	for (int i = 0; i <= szSize; i++){
		mycell = (char**)malloc(sizeof(char*) * 100);
		mycellcount = 100;

		ret = SplitTAB( mylist[i], mycell, cellcount);
			//タブ区切り文字列の個数だけ繰り返し
			for (int j = 0; j <=cellcount; j++){
				item.pszText = mycell[j];
				if (j == 0){
					item.iItem = i;
					item.iSubItem = 0;
					ListView_InsertItem(hList, &item);
				}
				else{
				//SubItem
					item.iItem = i;
					item.iSubItem = j;
					ListView_SetItem(hList, &item);
				}
			}
		for ( int i = 0; i < mycellcount; i++)		free(mycell[i]);
		free(mycell);
		//列幅の自動設定
		totalColumnWidth = 0;
		for (int i = 0; i <= cellcount; i++){
			ListView_SetColumnWidth(hList, i, LVSCW_AUTOSIZE) ;
			totalColumnWidth = totalColumnWidth + ListView_GetColumnWidth(hList, i);
		}
		if (maxTotalColWidth < totalColumnWidth )
			maxTotalColWidth = totalColumnWidth;
	}
	//読みこんだ列数、行数に合わせてフォームのサイズを変更
	GetWindowRect(hWnd, (LPRECT)&rcf);
	GetClientRect(hWnd, (LPRECT)&rcc);
	//Windowの枠サイズ取得
	fsize.cx = (rcf.bottom - rcf.top) - (rcc.bottom - rcc.top );
	fsize.cy = (rcf.right - rcf.left ) - (rcc.right - rcc.left );
	//zオーダーを変更しないオプションを指定してみた
	SetWindowPos(hWnd , HWND_TOP ,0 , 0 , maxTotalColWidth + fsize.cx , (szSize + 1) * 18 + fsize.cy + 38 ,SWP_NOMOVE | SWP_NOZORDER );
	return 0;
}

//リストビューのカラムを全て消す
//http://bluefish.orz.hm/sdoc/winprog_memo.html#リストビューの削除
void listview_delallcoloumn(HWND hlistview)
{
        int i,count;

        //カラム数を求める
        count = Header_GetItemCount(ListView_GetHeader(hlistview));

        for (i=0; i<count ;i++) {
                ListView_DeleteColumn(hlistview,0);
        }
}

//文字列をタブ区切り分解して文字列配列に収納して戻す
//int SplitTAB(char *row, char (*cells)[256], int &cellscount)
int SplitTAB(char *row, char **cells, int &cellscount)
{
	DWORD dwAccBytes;
	dwAccBytes = strlen(row);
	//一行の文字列を読みこむバッファ
	char buf[MALLOC_UNIT];
	int j = 0;
	int k = 0;
	for (int i = 0; i < (dwAccBytes ); i++)
	{
		buf[j] = row[i];
		j++;

		//先頭に結合セルがあるとき最初の文字がTABになるため配置が崩れる対策
		if (row[i] == 0x09){
			if (i > 0) {
				buf[j - 1] = 0;
			}
			else{
				buf[0]=0;
			}
			mycell[k] = (char*)calloc(MALLOC_UNIT,sizeof(char));
			strcpy_s(mycell[k],MALLOC_UNIT,buf);
			k++;
			if(k >= mycellcount){
				mycellcount = mycellcount + 100;
				mycell = (char**)realloc(mycell, sizeof(char*) * mycellcount);
			}
			j = 0;
		}
	}
	buf[j] = 0;
	mycell[k] = (char*)calloc(MALLOC_UNIT,sizeof(char));
	strcpy_s(mycell[k],MALLOC_UNIT,buf);
	mycellcount = k + 1;
	cellscount = k;
	return 0;
}

//クリップボードから文字列を読みこみ、CRLFで行毎に分離し、
//グローバル宣言した文字列の配列mylist[]に書き込む
int PasteFromCB(HWND hWnd , char *szStr, int &szSize)
{
    DWORD dwAccBytes;
    char *szTitle_org = TEXT("テキスト一行転送");
	//一行の文字列を読みこむバッファ
	char buf[MAX_READCB];
	int ret;
	ret = ReadClip(hWnd, szStr);
	if (ret != 0) return -1;

	dwAccBytes = strlen(szStr);
	int j = 0;
	int k = 0;
	for (int i = 0; i < (dwAccBytes ); i++)
	{
		buf[j] = szStr[i];
		j++;
		//最初の文字でなく、0x0aすなわち\nであるとき
		//最後の行は出力されない。EOFであって、改行コードが無い。
		
		if ((i > 0) && (szStr[i] == 0x0a)){
			if( szStr[i - 1] == 0x0d){
				buf[j - 2] = 0;
				//MessageBox(hWnd, buf, TEXT("モニタ"),MB_OK);
				mylist[k]=(char*)calloc(MALLOC_UNIT,sizeof(char));
				strcpy_s(mylist[k],MALLOC_UNIT,buf);
				//strcpy(mylist[k], buf);
				//strcpy_s(mylist[k], _countof(mylist[k]), buf);
				k++;
				//確保した配列サイズを超過する時は拡張
				if (k >= mylistcount){
					mylistcount = mylistcount + 100;
					mylist = (char**)realloc(mylist, sizeof(char*) * mylistcount);
				}
				j = 0;
			}
		}
	}
	buf[j] = 0;
	mylist[k] = (char*)calloc(MALLOC_UNIT, sizeof(char));
	strcpy_s(mylist[k],MALLOC_UNIT,buf);
	//freeの際に使用するためリザーブ
	mylistcount = k + 1;
	szSize = k;
    return 0;
}

//クリップボードからテキスト形式データ取得
int ReadClip(HWND hwnd, char *str)
{
    HGLOBAL hGlobal;
    LPSTR lpStr;
    int iLength, i;

    if(!IsClipboardFormatAvailable(CF_TEXT)) {
        MessageBox(hwnd, "クリップボードにテキストがありません", "Message", MB_OK);
        return -1;
    }
    OpenClipboard(hwnd);
    hGlobal = (HGLOBAL)GetClipboardData(CF_TEXT);
    if (hGlobal == NULL) {
        CloseClipboard();
        return -2;
    }
    lpStr = (LPSTR)GlobalLock(hGlobal);
    iLength = lstrlen(lpStr) + 1;
    if (iLength > MAX_READCB)
        iLength = MAX_READCB;
    for (i = 0; i < iLength; i++)
        str[i] = lpStr[i];
	GlobalUnlock(hGlobal);
    CloseClipboard();
    InvalidateRect(hwnd, NULL, TRUE);
    return 0;
}

//Clipboardにテキスト書き込み
int WriteClip(HWND hwnd, char *str)
{
    HGLOBAL hGlobal;
    int iLength;
    LPSTR lpStr;
    int i;
    iLength = lstrlen(str);
    if (iLength > 1024)
        iLength = 1024;
    hGlobal = GlobalAlloc(GHND, iLength + 1);
    if (hGlobal == NULL)
        return -1;
    lpStr = (LPSTR)GlobalLock(hGlobal);
    for (i = 0; i < iLength; i++)
        *lpStr++ = *str++;
    GlobalUnlock(hGlobal);
    if (OpenClipboard(hwnd) == 0) {
        GlobalFree(hGlobal);
        return -2;
    }
    EmptyClipboard();
    SetClipboardData(CF_TEXT, hGlobal);
    CloseClipboard();
    return 0;
}

//SendKeys代替APIを使用するための関数
//適宜sleepを入れないと誤動作することがあるらしい

//http://blogs.wankuma.com/youchi/archive/2010/07/26/191637.aspx
//Vectorを使用しない様に改造してみた
// マルチバイト文字用(CP_ACP固定w)
void KeyInput( char *Text_ ,HWND hWnd)
{
	//変換文字列格納バッファ
	WCHAR	wStrW[MALLOC_UNIT * 2];
	size_t wLen = 0;
	errno_t err = 0;
	INPUT *myinputs;

	//ロケール指定
	setlocale(LC_ALL,"japanese");
	//変換
	err = mbstowcs_s(&wLen, wStrW, MALLOC_UNIT, Text_, _TRUNCATE);
	//MessageBoxW(hWnd, wStrW, (LPCWSTR)TEXT("モニタ"),MB_OK);
  //std::vector<INPUT>  inputs;
  myinputs = (INPUT *)malloc(sizeof(INPUT) * wLen * 2);
  for( int i = 0; i < wLen; i++ )
  {
    for( int j = 0; j < 2; j++ )
    {
      INPUT input;
	  input.type        = INPUT_KEYBOARD;
      input.ki.wVk      = 0;
      input.ki.wScan      = wStrW[ i ];
      input.ki.time     = 0;
      input.ki.dwExtraInfo  = 0;
      input.ki.dwFlags    = KEYEVENTF_UNICODE;
      if( j != 0 )
      {
        input.ki.dwFlags  |= KEYEVENTF_KEYUP;
      }
      //inputs.push_back( input );
	  myinputs[i * 2 + j] = input;
    }
  }
  //SendInput( wLen * 2, &inputs[ 0 ], sizeof( INPUT ) );
  SendInput( wLen * 2, myinputs, sizeof( INPUT ) );
  free(myinputs);
  return;
}

// VK_xxx 用
void VKeyInput( int VKeys_, int Count_ )
{
  //std::vector<INPUT>  inputs;
  INPUT *myinputs;
  myinputs = (INPUT *)malloc(sizeof(INPUT) * Count_ * 2);
  for( int i = 0; i < Count_; i++, VKeys_++ )
  {
    for( int j = 0; j < 2; j++ )
    {
      INPUT input;
      input.type        = INPUT_KEYBOARD;
      input.ki.wVk      = VKeys_;
      input.ki.wScan    = ::MapVirtualKey( VKeys_, 0 );
      input.ki.time     = 0;
      input.ki.dwExtraInfo  = 0;
      input.ki.dwFlags    = KEYEVENTF_SCANCODE;
      if( j != 0 )
      {
        input.ki.dwFlags  |= KEYEVENTF_KEYUP;
      }
      //inputs.push_back( input );
	  myinputs[i * 2 + j] = input;
    }
  }
  //::SendInput( Count_ * 2, &inputs[ 0 ], sizeof( INPUT ) );
  SendInput( Count_ * 2, myinputs, sizeof( INPUT ) );
  free(myinputs);
  return;
}

//指定ウィンドウ(他アプリ)をアクティブにしてSendInputの前準備
int myActivateWindow(HWND hWnd)
{
	int lngThreadTop;
	int lngThreadMe;
	int lngResult;
	int lngResult2;
	HWND lngHandle;

	//現在のアクティブのWindowハンドルを取得
	lngHandle = GetForegroundWindow();
	//現在のアクティブWindowのスレッドIDを取得
	if (lngHandle)
		lngThreadTop = GetWindowThreadProcessId(lngHandle,0);
	//アクティブにしようとしているWindowハンドルのスレッドを取得
	if (lngThreadTop)
		lngThreadMe = GetWindowThreadProcessId(hWnd,0);
	//スレッドをアタッチする
	if (lngThreadMe)
		lngResult = AttachThreadInput(lngThreadMe, lngThreadTop, 1);
	//隠れている場合手前に表示する
	if (lngResult)
		lngResult = BringWindowToTop(hWnd);
	//アクティブ(フォアグラウンド)にする
	if (lngResult)
		lngResult2 = SetForegroundWindow(hWnd);
	//スレッドをデタッチする
	if (lngResult2)
		lngResult = AttachThreadInput(lngThreadMe, lngThreadTop, 0);
	return lngResult;
	
}

//リストビューを作成。リストビューのハンドルを戻す。
//拡張設定を行っている。
//http://www.kumei.ne.jp/c_lang/sdk2/sdk_198.htm
HWND MakeMyList(HWND hWnd)
{
    HWND hList;
    DWORD dwStyle;

    hList = CreateWindowEx(0,
        WC_LISTVIEW, "",
        WS_CHILD | WS_VISIBLE | LVS_REPORT | WS_CLIPSIBLINGS,
        0, 0, 0, 0,
        hWnd,
        (HMENU)ID_LISTVIEW,
        hInst,
        NULL);

    dwStyle = ListView_GetExtendedListViewStyle(hList);
    //dwStyle |= LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT |
    //    LVS_EX_GRIDLINES | LVS_EX_HEADERDRAGDROP;
    dwStyle |= LVS_EX_GRIDLINES;
    ListView_SetExtendedListViewStyle(hList, dwStyle);
    return hList;
}

LRESULT CALLBACK ChildProc(HWND hChdWnd, UINT msg, WPARAM wp, LPARAM lp)
{
    //int id;
	POINTS pts;
	POINT pt;
    HWND hTarget;
	HWND hWnd;
	HWND hRoot;
	char appliname[256];

	hWnd = GetParent(hChdWnd);
    switch (msg) {
		case WM_START_CAPTURE:
			//MessageBox(hChdWnd,"子ウィンドウから目的アプリにドラッグしてください","他アプリのハンドル取得",MB_OK);
			break;
		case WM_LBUTTONDOWN:
			bCap = TRUE;
			SetCapture(hChdWnd);
			pts = MAKEPOINTS(lp);
			break;
		case WM_MOUSEMOVE:
			if (bCap) {
				SetCursor(LoadCursor(NULL, IDC_CROSS));
				pts = MAKEPOINTS(lp);
			} else
				SetCursor(LoadCursor(NULL, IDC_ARROW));
			break;
		case WM_LBUTTONUP:
			if (bCap)
			{
				SetCursor(LoadCursor(NULL, IDC_ARROW));
				pts = MAKEPOINTS(lp);
				pt.x = pts.x;
				pt.y = pts.y;
				ClientToScreen(hWnd, &pt);
				hTarget = WindowFromPoint(pt);
				if (hTarget == NULL) {
					MessageBox(hWnd, "失敗です", "失敗", MB_OK);
					return (DefWindowProc(hWnd, msg, wp, lp));
				}
				hRoot = GetAncestor(hTarget,GA_ROOT);
				hXl = hRoot;
				GetWindowText(hRoot,(LPSTR)appliname,256);
				MessageBox(hWnd, appliname, "ハンドル取得", MB_OK);
				ReleaseCapture();
				bCap = FALSE;
				ShowWindow(hChdWnd, SW_HIDE);
			}
			break;

			case WM_PAINT:
				ShowMyText(hChdWnd);
				break;

			//CLOSEはやめて隠すだけとした
			case WM_CLOSE:
				ShowWindow(hChdWnd, SW_HIDE);
				break;
        default:
            return (DefWindowProc(hChdWnd, msg, wp, lp));
    }
    return 0L;
}

//ウィンドウにテキストを表示する
void ShowMyText(HWND hWnd)
{
    HDC hdc;
    //char *str_org = "left=%d top=%d right=%d bottom=%d";
    //char strx[256];
    PAINTSTRUCT paint;
    RECT rt;
    LPCSTR str = "ここから目的アプリに\n"
        "ドラッグして下さい";
    
    GetClientRect(hWnd, &rt);
    /*wsprintf((LPSTR)strx, (LPCSTR)str_org, rt.left, rt.top, rt.right, rt.bottom); 
    rt.top += 40;
    rt.bottom -= 40;
    rt.right -= 40;
    rt.left += 40;*/
    hdc = BeginPaint(hWnd, &paint);
    SetTextColor(hdc, RGB(0, 0, 255));
    DrawText(hdc, str, -1, &rt, DT_WORDBREAK);
    EndPaint(hWnd, &paint);
    return;
}

☆ヘッダーファイル
// Microsoft Visual C++ generated include file.
// Used by listvew_dat1a.rc
//
#define IDM_END                         101
#define IDM_INSCOLUMN                   102
#define IDM_INSITEM                     103
#define IDM_SETSUB                      104
#define IDI_ICON1                       104
#define IDM_DEL                         105
#define IDM_HWD                         40002
#define IDM_XL                         40003
#define ID_CR0							40004
#define ID_CR1							40005
#define ID_CR2							40006

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        105
#define _APS_NEXT_COMMAND_VALUE         40003
#define _APS_NEXT_CONTROL_VALUE         1001
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

☆リソースファイル
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"

#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// Generated from the TEXTINCLUDE 2 resource.

#include "afxres.h"

/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS

/////////////////////////////////////////////////////////////////////////////
// 日本語 resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_JPN)
#ifdef _WIN32
LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT
#pragma code_page(932)
#endif //_WIN32

#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
// TEXTINCLUDE

1 TEXTINCLUDE 
BEGIN
    "resource.h\0"
END

2 TEXTINCLUDE 
BEGIN
    "#include ""afxres.h""\r\n"
    "\0"
END

3 TEXTINCLUDE 
BEGIN
    "\r\n"
    "\0"
END

#endif    // APSTUDIO_INVOKED

/////////////////////////////////////////////////////////////////////////////
// Menu

MYMENU MENU 
BEGIN
    POPUP "ファイル(&F)"
    BEGIN
        MENUITEM "終了(&X)",                      IDM_END
    END
    MENUITEM "更新(&R)",                      IDM_DEL
    POPUP "切替(&H)"
    BEGIN
        MENUITEM "変更(&A)",                      IDM_HWD
        MENUITEM "戻す(&X)",                      IDM_XL
    END
    POPUP "改行(&E)"
    BEGIN
        MENUITEM "0(&0)",                       ID_CR0
        MENUITEM "1-ATOK(&1)",                  ID_CR1
        MENUITEM "2-MSIME(&2)",                 ID_CR2
    END
END

/////////////////////////////////////////////////////////////////////////////
// Icon

IDI_ICON1               ICON                    "271.ico"
#endif    // 日本語 resources
/////////////////////////////////////////////////////////////////////////////

#ifndef APSTUDIO_INVOKED

#endif    // not APSTUDIO_INVOKED
	

お世話になっている参考書
・猫でも分かるWindowsプログラミング 粂井康隆著 ソフトバンクパブリッシング
・Win32API完璧マスタ 土井/那須/上田著 CQ出版社