EternalWindows
DDE / データの設定

今回のプログラムは、Excelのセルにデータを設定します。 プログラムを起動する前に、sample.xlsxを開いたExcelを起動しておいてください。

#include <windows.h>

BOOL PostDDEMessage(HWND hwndServerDDE, UINT uMsg, HWND hwndClientDDE, UINT uLow, UINT uHigh);
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	TCHAR      szAppName[] = TEXT("sample");
	HWND       hwnd;
	MSG        msg;
	WNDCLASSEX wc;

	wc.cbSize        = sizeof(WNDCLASSEX);
	wc.style         = 0;
	wc.lpfnWndProc   = WindowProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = hinst;
	wc.hIcon         = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
	wc.hCursor       = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED);
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = szAppName;
	wc.hIconSm       = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
	
	if (RegisterClassEx(&wc) == 0)
		return 0;

	hwnd = CreateWindowEx(0, szAppName, szAppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinst, NULL);
	if (hwnd == NULL)
		return 0;

	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);
	
	while (GetMessage(&msg, NULL, 0, 0) > 0) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return (int)msg.wParam;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	static HWND hwndServerDDE = NULL;
	
	switch (uMsg) {

	case WM_CREATE: {
		ATOM atomApp, atomTopic;

		atomApp = GlobalAddAtom(TEXT("Excel"));
		atomTopic = GlobalAddAtom(TEXT("[sample.xlsx]Sheet1"));
		SendMessage((HWND)HWND_BROADCAST, WM_DDE_INITIATE, (WPARAM)hwnd, MAKELONG(atomApp, atomTopic));
		GlobalDeleteAtom(atomApp);
		GlobalDeleteAtom(atomTopic);

		if (hwndServerDDE == NULL) {
			MessageBox(NULL, TEXT("DDE対話の確立に失敗しました。"), NULL, MB_ICONWARNING);
			return -1;
		}

		return 0;
	}

	case WM_LBUTTONDOWN: {
		ATOM    atomItem;
		DDEPOKE *pPoke;
		HANDLE  hData;
		CHAR    szData[] = "data";
		DWORD   dwSize = lstrlenA(szData) + 1;

		hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(DDEPOKE) + dwSize);
		pPoke = (DDEPOKE *)GlobalLock(hData);
		pPoke->fRelease = TRUE;
		pPoke->cfFormat = CF_TEXT;
		CopyMemory(pPoke->Value, szData, dwSize);
		GlobalUnlock(hData);

		atomItem = GlobalAddAtom(TEXT("R2C1"));
		if (!PostDDEMessage(hwndServerDDE, WM_DDE_POKE, hwnd, (UINT)hData, atomItem)) {
			GlobalDeleteAtom(atomItem);
			GlobalFree(hData);
		}

		return 0;
	}

	case WM_DDE_ACK: {
		if (hwndServerDDE == NULL)
			hwndServerDDE = (HWND)wParam;
		else {
			ULONG uData;
			ATOM  atomItem;
			TCHAR szBuf[256];

			UnpackDDElParam(WM_DDE_ACK, lParam, (PUINT)&uData, (PUINT)&atomItem);
			wsprintf(szBuf, TEXT("%x"), uData);
		//	MessageBox(NULL, szBuf, TEXT("OK"), MB_OK);

			GlobalDeleteAtom(atomItem);
			FreeDDElParam(WM_DDE_ACK, lParam);
		}
		return 0;
	}

	case WM_DESTROY:
		if (hwndServerDDE != NULL)
			PostMessage(hwndServerDDE, WM_DDE_TERMINATE, (WPARAM)hwnd, 0);
		PostQuitMessage(0);
		return 0;

	default:
		break;

	}

	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

BOOL PostDDEMessage(HWND hwndServerDDE, UINT uMsg, HWND hwndClientDDE, UINT uLow, UINT uHigh)
{
	LPARAM lParam = PackDDElParam(uMsg, uLow, uHigh);
	BOOL   bResult;

	bResult = PostMessage(hwndServerDDE, uMsg, (WPARAM)hwndClientDDE, lParam);
	if (!bResult)
		FreeDDElParam(uMsg, lParam);

	return bResult;
}

データの設定に使用するメッセージは、WM_DDE_POKEです。 WM_LBUTTONDOWNでは、このメッセージをサーバーに送っています。

case WM_LBUTTONDOWN: {
	ATOM    atomItem;
	DDEPOKE *pPoke;
	HANDLE  hData;
	CHAR    szData[] = "data";
	DWORD   dwSize = lstrlenA(szData) + 1;

	hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(DDEPOKE) + dwSize);
	pPoke = (DDEPOKE *)GlobalLock(hData);
	pPoke->fRelease = TRUE;
	pPoke->cfFormat = CF_TEXT;
	CopyMemory(pPoke->Value, szData, dwSize);
	GlobalUnlock(hData);

	atomItem = GlobalAddAtom(TEXT("R2C1"));
	if (!PostDDEMessage(hwndServerDDE, WM_DDE_POKE, hwnd, (UINT)hData, atomItem)) {
		GlobalDeleteAtom(atomItem);
		GlobalFree(hData);
	}

	return 0;
}

WM_DDE_POKEのLPARAMにはDDEPOKE構造体を含めておかなければならないため、GlobalAllocでこれを確保しています。 第1引数の定数は現在では無視されることになっていますが、昔の名残として指定しています。 第2引数には確保するメモリのサイズを指定しますが、 ここには設定するデータのサイズも含めるようにします。 fReleaseにはデータを受け取った側がメモリを開放するかどうかを指定します。 TRUEを指定した場合は、受け取った側がメモリを開放することになります。 cfFormatには設定するデータの形式を指定することができ、CF_TEXTはデータがテキスト形式であることを意味します。 Valueには実際に設定したいデータを指定します。 データはszDataとして初期化されているため、これをValueにコピーしています。 GlobalAddAtomに指定しているのはアイテム名であり、これはデータを設定したいセル名を表しています。

WM_DDE_POKEを送った場合は、データの設定が成功しているかに関わらずWM_DDE_ACKが返されることになります。 uDataの値が0x8000である場合はデータの設定が成功したことを意味し、 0の場合は失敗したことを意味します。


戻る