EternalWindows
DDE / DDE監視

DDEMLは、他のアプリケーションのDDE対話を監視する機能を持っています。 この機能を使用すれば、他のアプリケーションがDDEに関する動作を行った際に、 DdeInitializeに指定したコールバック関数に通知が送られるようになります。 次に、監視機能を使用する例を示します。

DdeInitialize(&dwInst, DdeCallback, APPCLASS_MONITOR | MF_CALLBACKS | MF_CONV | MF_ERRORS | MF_HSZ_INFO | MF_LINKS | MF_POSTMSGS | MF_SENDMSGS, 0);	

第3引数にAPPCLASS_MONITORを指定すれば、DDE対話を監視するようになります。 具体的にどのような動作を監視するかはMF_XXXという定数で指定でき、 次のような種類があります。

定数 hdata 意味
MF_CALLBACKS MONCBSTRUCT構造体 トランザクションが開始された場合に通知を受け取る。
MF_CONV MONCONVSTRUCT構造体 DDE対話を確立した場合や終了した場合に通知を受け取る。
MF_ERRORS MONERRSTRUCT構造体 DDEエラーが発生した場合に通知を受け取る。
MF_HSZ_INFO MONHSZSTRUCT構造体 文字列ハンドルが作成された場合や開放された場合に通知を受け取る。
MF_LINKS MONLINKSTRUCT構造体 アドバイズループの開始または終了の場合に通知を受け取る。
MF_POSTMSGS MONMSGSTRUCT構造体 DDEメッセージがポストされた場合に通知を受け取る。

hdataは、コールバック関数のHDDEDATA型の変数です。 コールバック関数のdwData2を確認すれば通知の種類を確認でき、 これがたとえばMF_CONVの場合は、hdataがMONCONVSTRUCT構造体になります。

今回のプログラムは、DDEアプリケーションの対話を監視します。 今回のプログラムを起動した後に、前節のプログラムを実行すればウインドウの内容が変化するはずです。

#include <windows.h>

HWND  g_hwndListBox;
DWORD g_dwInst = 0;

HDDEDATA CALLBACK DdeCallback(UINT uType, UINT uFmt, HCONV hconv, HSZ hsz1, HSZ hsz2, HDDEDATA hdata, DWORD dwData1, DWORD dwData2);
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)
{
	switch (uMsg) {

	case WM_CREATE: {
		ULONG uResult;

		uResult = DdeInitialize(&g_dwInst, DdeCallback, APPCLASS_MONITOR | MF_CONV | MF_POSTMSGS, 0);
		if (uResult != DMLERR_NO_ERROR)
			return -1;
		g_hwndListBox = CreateWindowEx(0, TEXT("LISTBOX"), NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hwnd, (HMENU)1, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
		return 0;
	}
	
	case WM_SIZE:
		MoveWindow(g_hwndListBox, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
		return 0;

	case WM_DESTROY:
		if (g_dwInst != 0)
			DdeUninitialize(g_dwInst);
		PostQuitMessage(0);
		return 0;

	default:
		break;

	}

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

HDDEDATA CALLBACK DdeCallback(UINT uType, UINT uFmt, HCONV hconv, HSZ hsz1, HSZ hsz2, HDDEDATA hdata, DWORD dwData1, DWORD dwData2)
{
	switch (uType) {

	case XTYP_MONITOR: {
		LPVOID lpData;
		DWORD  dwSize;

		lpData = DdeAccessData(hdata, &dwSize);
		if (lpData == NULL)
			break;

		if (dwData2 == MF_CONV) {
			MONCONVSTRUCT *lpMonConv = (MONCONVSTRUCT *)lpData;
			TCHAR         szService[256];
			TCHAR         szTopic[256];
			TCHAR         szBuf[2048];
			
			DdeQueryString(g_dwInst, lpMonConv->hszSvc, szService, sizeof(szService) / sizeof(TCHAR), CP_WINNEUTRAL);
			DdeQueryString(g_dwInst, lpMonConv->hszTopic, szTopic, sizeof(szTopic) / sizeof(TCHAR), CP_WINNEUTRAL);

			wsprintf(szBuf, TEXT("AppName : %s Topic : %s Connect : &d"), szService, szTopic, lpMonConv->fConnect);
			SendMessage(g_hwndListBox, LB_ADDSTRING, 0, (LPARAM)szBuf);
		}
		else if (dwData2 == MF_POSTMSGS) {
			MONMSGSTRUCT *lpMonMsg = (MONMSGSTRUCT *)lpData;
			TCHAR        szBuf[256];

			if (lpMonMsg->wMsg == WM_DDE_TERMINATE)
				lstrcpy(szBuf, TEXT("WM_DDE_TERMINATE"));
			else if (lpMonMsg->wMsg == WM_DDE_ACK)
				lstrcpy(szBuf, TEXT("WM_DDE_ACK"));
			else if (lpMonMsg->wMsg == WM_DDE_DATA)
				lstrcpy(szBuf, TEXT("WM_DDE_DATA"));
			else if (lpMonMsg->wMsg == WM_DDE_REQUEST)
				lstrcpy(szBuf, TEXT("WM_DDE_REQUEST"));
			else if (lpMonMsg->wMsg == WM_DDE_POKE)
				lstrcpy(szBuf, TEXT("WM_DDE_POKE"));
			else if (lpMonMsg->wMsg == WM_DDE_EXECUTE)
				lstrcpy(szBuf, TEXT("WM_DDE_EXECUTE"));
			else
				wsprintf(szBuf, TEXT("%x"), lpMonMsg->wMsg);

			SendMessage(g_hwndListBox, LB_ADDSTRING, 0, (LPARAM)szBuf);
		}
		else
			;
		DdeUnaccessData(hdata);
	}

	default:
		break;

	}
	
	return (HDDEDATA)FALSE;
}

既に述べたように、アプリケーションがDDE対話を監視したい場合は、DdeInitializeにAPPCLASS_MONITORを指定します。 このときには、監視の対象とする動作を示す定数も指定可能であり、 MF_CONVとMF_POSTMSGSを指定していることから、DDE対話が確立された場合やメッセージがポストされた場合に通知が送られます。 通知は、第2引数に指定したコールバック関数で受け取ります。

HDDEDATA CALLBACK DdeCallback(UINT uType, UINT uFmt, HCONV hconv, HSZ hsz1, HSZ hsz2, HDDEDATA hdata, DWORD dwData1, DWORD dwData2)
{
	switch (uType) {

	case XTYP_MONITOR: {
		LPVOID lpData;
		DWORD  dwSize;

		lpData = DdeAccessData(hdata, &dwSize);
		if (lpData == NULL)
			break;

		if (dwData2 == MF_CONV) {
			MONCONVSTRUCT *lpMonConv = (MONCONVSTRUCT *)lpData;
			TCHAR         szService[256];
			TCHAR         szTopic[256];
			TCHAR         szBuf[2048];
			
			DdeQueryString(g_dwInst, lpMonConv->hszSvc, szService, sizeof(szService) / sizeof(TCHAR), CP_WINNEUTRAL);
			DdeQueryString(g_dwInst, lpMonConv->hszTopic, szTopic, sizeof(szTopic) / sizeof(TCHAR), CP_WINNEUTRAL);

			wsprintf(szBuf, TEXT("AppName : %s Topic : %s Connect : &d"), szService, szTopic, lpMonConv->fConnect);
			SendMessage(g_hwndListBox, LB_ADDSTRING, 0, (LPARAM)szBuf);
		}
		else if (dwData2 == MF_POSTMSGS) {
			MONMSGSTRUCT *lpMonMsg = (MONMSGSTRUCT *)lpData;
			TCHAR        szBuf[256];

			if (lpMonMsg->wMsg == WM_DDE_TERMINATE)
				lstrcpy(szBuf, TEXT("WM_DDE_TERMINATE"));
			else if (lpMonMsg->wMsg == WM_DDE_ACK)
				lstrcpy(szBuf, TEXT("WM_DDE_ACK"));
			else if (lpMonMsg->wMsg == WM_DDE_DATA)
				lstrcpy(szBuf, TEXT("WM_DDE_DATA"));
			else if (lpMonMsg->wMsg == WM_DDE_REQUEST)
				lstrcpy(szBuf, TEXT("WM_DDE_REQUEST"));
			else if (lpMonMsg->wMsg == WM_DDE_POKE)
				lstrcpy(szBuf, TEXT("WM_DDE_POKE"));
			else if (lpMonMsg->wMsg == WM_DDE_EXECUTE)
				lstrcpy(szBuf, TEXT("WM_DDE_EXECUTE"));
			else
				wsprintf(szBuf, TEXT("%x"), lpMonMsg->wMsg);

			SendMessage(g_hwndListBox, LB_ADDSTRING, 0, (LPARAM)szBuf);
		}
		else
			;
		DdeUnaccessData(hdata);
	}

	default:
		break;

	}
	
	return (HDDEDATA)FALSE;
}

uTypeには、どのような通知が送られたのかを示す定数が格納されており、 これがXTYP_MONITORの場合は、監視に関する通知が送られたことを意味します。 uTypeによってhsz1からdwData2までの内容は変化しますが、 XTYP_MONITORの場合は、hdataに通知の内容を示す構造体が格納され、 dwData2には監視した動作を表す定数が格納されます。 構造体にアクセスするためにはDdeAccessDataを呼び出すようにし、 MF_CONVかMF_POSTMSGSによって適切にキャストしています。 MF_CONVにおけるMONCONVSTRUCT構造体には、サーバーのサービス名とトピック名を表す文字列ハンドルが含まれるため、 DdeQueryStringによって関連する文字列を取得しています。 MF_POSTMSGSの場合は、ポストされたメッセージがMONMSGSTRUCT構造体から分かるため、 それを文字列としてリストボックスに追加しています。


戻る