1. 程式人生 > >windows程式設計用WM_COPYDATA進行兩程序間傳輸大量資料

windows程式設計用WM_COPYDATA進行兩程序間傳輸大量資料

現在有個需求需要在兩程序間大量傳遞資料,而在windows程式下兩個程序間進行通訊 可以有多個方法:

1、管道(未命名管道、命名管道)

2、共享記憶體

3、訊息佇列

不過上述實現起來比較麻煩,現在我們來講解如何使用sendMessage來傳輸大量資料。

LRESULT SendMessage(
  HWND   hWnd,
  UINT   Msg,
  WPARAM wParam,
  LPARAM lParam
);

sendmessage如上所述,可以知道其中wParam 以及lParam兩個引數可以傳遞少量資料,要用來傳遞大量資料,我們只需要把Msg變數指定為WM_COPYDATA就可以了。

其中WM_COPYDATA傳遞的是一個結構體資料為:

typedef struct tagCOPYDATASTRUCT {
  ULONG_PTR dwData;//一個整數,可以用來充當標識
  DWORD     cbData;//lpData大小
  PVOID     lpData;//要傳輸的資料
} COPYDATASTRUCT, *PCOPYDATASTRUCT;

為了我們可以在接收端容易處理傳遞的大量資料。我們可以傳輸一個規範化的結構體,然後再賦值給lpData成員變數。

例如我們可以定義一個一般的結構體資料(主要要規劃好結構體的成員變數):

typedef struct __MessageContent
{
	DWORD dwAttribute;
	BOOL  bDisplay;
	BOOL  bTrim;
	TCHAR lpszText[MAX_PATH];
	TCHAR lpszDescribe[MAX_PATH];
	TCHAR lpszUrl[MAX_PATH];
	TCHAR lpszImage[MAX_PATH];
} MessageContent;

資訊接收方一般要先於資訊傳送方存在,否則資訊傳送方無法找到需要傳送資料的物件。

資訊接收方程式碼 示例:

/*
資訊接收方,並處理資料
*/
#include<windows.h>
#include<tchar.h>


LPCTSTR g_szWindowClassName = __TEXT("ExampleDemo");
LPCTSTR g_szWindowClassTitle = __TEXT("Hello");

typedef struct __MessageContent
{
	DWORD dwAttribute;
	BOOL  bDisplay;
	BOOL  bTrim;
	TCHAR lpszText[MAX_PATH];
	TCHAR lpszDescribe[MAX_PATH];
	TCHAR lpszUrl[MAX_PATH];
	TCHAR lpszImage[MAX_PATH];
} MessageContent;

MessageContent* g_mcMessageContent = NULL;

LRESULT CALLBACK HiddenWindowProcess(__in HWND hwnd, __in UINT uMsg, __in WPARAM wParam, __in LPARAM lParam);

/**
* @brief  應用程式主函式
* @param  hInstance		模組
* @param  cmdLineArgs	命令列引數
*/
int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE, _In_ LPWSTR cmdLineArgs, _In_ int)
{
	WNDCLASS wcWindowClass = { 0 };
	wcWindowClass.style = CS_HREDRAW | CS_VREDRAW;
	wcWindowClass.lpfnWndProc = HiddenWindowProcess;
	wcWindowClass.cbClsExtra = 0;
	wcWindowClass.cbWndExtra = 0;
	wcWindowClass.hInstance = hInstance;
	wcWindowClass.hIcon = NULL;
	wcWindowClass.hCursor = ::LoadCursor(NULL, IDC_ARROW);
	wcWindowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wcWindowClass.lpszMenuName = NULL;
	wcWindowClass.lpszClassName = g_szWindowClassName;
	if (::RegisterClass(&wcWindowClass) == 0)
		return -1;
	::CreateWindow(g_szWindowClassName, g_szWindowClassTitle, WS_OVERLAPPED, 0, 0, 1, 1, NULL, NULL, hInstance, NULL);
	MSG msg = { 0 };
	while (::GetMessage(&msg, NULL, 0, 0))
	{
		::TranslateMessage(&msg);
		::DispatchMessage(&msg);
	}
	return -1;
}

/**
* @brief  處理通知視窗訊息
* @param  uMsg包含傳送的訊息
*/
LRESULT CALLBACK HiddenWindowProcess(__in HWND hwnd, __in UINT uMsg, __in WPARAM wParam, __in LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_COPYDATA:
	{
		COPYDATASTRUCT * cdsMessageDataStruct = (COPYDATASTRUCT*)lParam;
		if (!cdsMessageDataStruct || sizeof(cdsMessageDataStruct) == 0)
			return E_FAIL;
		g_mcMessageContent = (MessageContent *)cdsMessageDataStruct->lpData;
		MessageBox(NULL, sizeof(*g_mcMessageContent) > 0 ? L"TRUE":L"FALSE",L"Title",MB_OK);
		//////////////////
		//現在可以處理傳過來的資料或者呼叫寫好的函式進行處理。
	}
	break;
	default:
		return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
	}
	return S_OK;
}

資訊傳送方程式碼示例:

/*
資訊傳送方
*/
#include<windows.h>
#include<tchar.h>

typedef struct __MessageContent
	{
		DWORD dwAttribute;
		BOOL  bDisplay;
		BOOL  bTrim;
		TCHAR lpszText[MAX_PATH];
		TCHAR lpszDescribe[MAX_PATH];
		TCHAR lpszUrl[MAX_PATH];
		TCHAR lpszImage[MAX_PATH];
	} MessageContent;


int WINAPI wWinMain(_In_ HINSTANCE hInstance , _In_opt_ HINSTANCE , _In_ LPWSTR cmdLineArgs , _In_ int)
{
	//測試用例,可以從服務端獲取
	DWORD dwAttribute = 10;
	BOOL isDisplay =FALSE;
	BOOL isTrim = FALSE;
	LPCTSTR lpszText = _T("熱點");
	LPCTSTR lpszDescribe = _T("實時新聞");
	LPCTSTR lpszUrl = _T("http://www.baidu.com");
	LPCTSTR lpszImage = _T("http://www.nipic.com/topic/show_27085_1.html");

	MessageContent messageContent	= { 0 };
	messageContent.dwAttribute		= 10;
	messageContent.bDisplay			= isDisplay;
	messageContent.bTrim			= isTrim;
	_tcscpy_s(messageContent.lpszText,MAX_PATH,lpszText);
	_tcscpy_s(messageContent.lpszDescribe,MAX_PATH,lpszDescribe);
	_tcscpy_s(messageContent.lpszUrl,MAX_PATH,lpszUrl);
	_tcscpy_s(messageContent.lpszImage,MAX_PATH,lpszImage);

	COPYDATASTRUCT toastContentMessage = { 0 };
	toastContentMessage.lpData = (PVOID)&messageContent;
	toastContentMessage.cbData = sizeof(messageContent);

    //需要確定對方(資訊接收方)的視窗名稱與標題
	HWND hToastWin = ::FindWindow(__TEXT("ExampleDemo") , __TEXT("Hello"));
	if (hToastWin == NULL)
	{
		return false;
	}
	::SendMessage(hToastWin , WM_COPYDATA , 0 , (LPARAM)&toastContentMessage);

	return 0;
}

使用結構體不僅擴大了傳送資料的量,而且還解決了傳輸資料處理的問題,規範化了傳輸資料的格式。