我的解决方案下有两个项目,一个是C++的MFC项目,一个是C#的WPF项目。
出于工作需要我要在C++项目中打开C#项目的exe文件,然后在C++端找到该exe的主窗口句柄,从而利用SendMessage()将C++的消息发送到该exe。
毫无疑问,当需要找窗口句柄时,首先想到的自然是FindWindow(),这个函数能够在系统中帮我们找到所需窗口的句柄。该函数的参数有两个,第一个是所找窗口的类名,第二个是所找窗口的名字。一般来说,第一个参数可以填NULL,但是第二个参数一般不要省略。
但是,当我生成项目的exe放到Surface上面,然后在Surface低电量(大约10%)重开机运行时,发现消息竟然发送不出去!debug发现,是FindWindow()这个API在作怪!查询网上相关资料,发现也有人说在重开机后FindWindow找不到相应窗口的概率会变大,但是又找不到解决方法。于是经过一天的摸索,针对我的项目,我给出如下解决方案:
直接在打开exe文件时将C++的窗口句柄传过去,然后在C#端接收获得C++的窗口句柄,再在C#端利用C++的窗口句柄将C#的主窗口句柄回传给C++!
//Dlg.cpp
//Send the HWND to C# program
std::string hwnd = std::to_string((WPARAM)this->GetSafeHwnd()); //这里利用WPARAM将窗口句柄转化一次之后再使用to_string()将句柄转化为string
printf("%s\n", hwnd.c_str());
ShellExecuteA(this->GetSafeHwnd(), "open", exePath + "PalmServer.exe", hwnd.c_str(), NULL, 1);
//App.xml
<Application x:Class="PalmServer.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PalmServer"
Startup="Application_Startup" //定义程序入口
>
<Application.Resources>
</Application.Resources>
</Application>
//App.xml.cs
public partial class App : Application
{
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hwnd, uint wMsg, IntPtr wParam, int lParam);
// Send C++ program the C# mainwindow HWND
private const uint WM_PS_HWND = 9034; // Tell client the HWND of this window
//程序入口
private void Application_Startup(object sender, StartupEventArgs e)
{
MainWindow wnd = new MainWindow();
wnd.Show();
if (e.Args.Length == 1)
{
int a = Convert.ToInt32(e.Args[0]); //将包含C++的窗口句柄的string转化为int
IntPtr proxyHandleByShellExec = (IntPtr)a; //MFC中的HWND类型等同于WPF中的IntPtr类型
Console.WriteLine(proxyHandleByShellExec.ToString()); //输出看看句柄的数字是什么
if (proxyHandleByShellExec != (IntPtr)0)
{
var mainWindowHandle = new System.Windows.Interop.WindowInteropHelper(wnd).Handle; //C#获得窗口句柄
Console.WriteLine(mainWindowHandle.ToString());
SendMessage(proxyHandleByShellExec, WM_PS_HWND, mainWindowHandle, 0); //将MainWindow的窗口句柄发送给C++端
}
}
else
Console.WriteLine(e.Args.Length.ToString());
}
}
}
//Dlg.h
// PalmServer HWND
class CDlgPalmProbe : public CDialogEx
{
private:
HWND hProbeServerBySendMessage;
afx_msg LRESULT OnPalmServerHWND(WPARAM wParam, LPARAM lParam); //消息处理函数
}
//Dlg.cpp
// PalmServer HWND
#define WM_PS_HWND 9034 //定义消息
BEGIN_MESSAGE_MAP(CDlgPalmProbe, CDialogEx)
ON_MESSAGE(WM_PS_HWND, &CDlgPalmProbe::OnPalmServerHWND) //绑定消息和消息处理函数
END_MESSAGE_MAP()
//Receive the PalmProbe HWND from C# program
LRESULT CDlgPalmProbe::OnPalmServerHWND(WPARAM wParam, LPARAM lParam)
{
hProbeServerBySendMessage = (HWND)wParam;
long a = (WPARAM)hProbeServerBySendMessage;
_cprintf("C# HWND: %ld\n", a);
return 0;
}