相关链接,这里谢谢几位大神:
https://www.cnblogs.com/caizl/p/4343199.html
http://bbs.csdn.net/topics/390919541
https://www.cnblogs.com/xiekeli/p/3994380.html
目的:主要用于C++内嵌C# 界面,便于MFC老程序增加插件,升级和维护新界面。
内容:
1、C++发送消息:
(1)、简单的抓取窗口发送:
CWnd *pWnd = CWnd::FindWindow(NULL, _T("窗口名称"));
pWnd->SendMessage(WM_USER+1001,0,0);
注:WM_USER为系统宏,0x400,因此以上语句发送值为2025的消息。
(2)、内嵌窗口:
//窗口句柄回调函数,其中apphWnd就是我们启动的exe内嵌窗口的句柄
HWND apphWnd = NULL;
int CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
DWORD pID;
DWORD tpID = GetWindowThreadProcessId(hwnd,&pID);
if(tpID == (DWORD)lParam)
{
apphWnd = hwnd;
return false;
}
return true;
}
//首先从exe文件的目录下查找需要的exe文件
CString strFilePath;
TCHAR szKVPathName[256];
memset(szKVPathName, 0, sizeof(szKVPathName));
HMODULE hModule = GetModuleHandle(NULL);
DWORD dwRes = GetModuleFileName(hModule, szKVPathName, sizeof(szKVPathName));
CString strKVPathName(szKVPathName);
int nIndex = strKVPathName.ReverseFind( _T('\\'));
CString cstrFilePath = strKVPathName.Left(nIndex + 1);
cstrFilePath = cstrFilePath + _T("需要内嵌的C#程序.exe");
//内嵌到MFC的某个窗口中,窗口句柄为hhwnd
CRect rect;
GetClientRect(hhwnd, &rect);
LPCTSTR args = _T("");
PROCESS_INFORMATION processInfo;
STARTUPINFO startupInfo;
::ZeroMemory(&startupInfo, sizeof(startupInfo));
startupInfo.cb = sizeof(startupInfo);
startupInfo.dwFlags = STARTF_USESHOWWINDOW;
startupInfo.wShowWindow = SW_HIDE;
if(::CreateProcess(cstrFilePath, (LPTSTR)args, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo))
{
//延迟0.5s,等待进程创建成功
Sleep(500);
while(true)
{
::EnumWindows(&EnumWindowsProc, processInfo.dwThreadId);//Iterate all windows
if(NULL != apphWnd)
{
break;
}
}
HANDLE hPro = processInfo.hProcess;
if(apphWnd!=NULL)
{
::SetParent(apphWnd,hhwnd);
SetWindowLong(apphWnd, GWL_STYLE, WS_VISIBLE);
::MoveWindow(apphWnd, 0, 0,rect.right, rect.bottom, true);
::UpdateWindow(apphWnd);
::ShowWindow(apphWnd,SW_SHOW);
}
}
//取得窗口句柄,发送消息:
CWnd *pWnd = CWnd::FromHandle(apphWnd);
pWnd->SendMessage(WM_USER+1001,0,0);
2、C#接收消息
Winform的请看附带链接,这里写的是WPF的
private void Grid_Loaded(object sender, RoutedEventArgs e)
{
HwndSource hWndSource;
WindowInteropHelper wih = new WindowInteropHelper(this);
hWndSource = HwndSource.FromHwnd(wih.Handle);
hWndSource.AddHook(MainWindowProc);
}
private IntPtr MainWindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case 2025: MessageBox.Show("收到"); break;
}
return IntPtr.Zero;
}
到这里,就接收完消息了。
3、发送字符串,直接考这个代码,可以把时间发过去,重点是COPYDATASTRUCT结构体,其不同于进程内调用
COPYDATASTRUCT CopyData;
char szSendBuf[100];
time_t timenow;
time(&timenow);
sprintf(szSendBuf, "%s", ctime(&timenow));//注意,ctime()返回的字符串后面带了'\n'
CopyData.dwData = 0;
CopyData.cbData = strlen(szSendBuf);
szSendBuf[CopyData.cbData - 1] = '\0';
CopyData.lpData = szSendBuf;
::SendMessage(pWnd->m_hWnd, WM_COPYDATA, 0, (LPARAM)&CopyData);
4、注意MFC的重绘
WPF窗口自身会重绘,父窗口如果二次重绘可能导致WPF窗口被刷新没了。