您的位置:首页 > 其它

进程间的通信以及发送消息

2017-12-19 22:05 579 查看
背景:公司一个程序(C++程序)启动另一个程序(C# 程序),启动时会有两三秒的空白时间,所以就需要先预先启动子程序渲染窗体(启动时隐藏窗体窗体),还有部分数据不确定所以要在正真启动的时候再向子程序发消息。

C#隐式启动并渲染窗体

//Application.Run(new Form1());此方法窗体不能直接隐藏
Application.Run(new HideOnStartupApplicationContext(new Form1()));


internal class HideOnStartupApplicationContext : ApplicationContext
{
private Form mainFormInternal;

public HideOnStartupApplicationContext(Form mainForm)
{
this.mainFormInternal = mainForm;
this.mainFormInternal.FormClosed += new FormClosedEventHandler(mainFormInternal_FormClosed);
}

void mainFormInternal_FormClosed(object sender, FormClosedEventArgs e)
{
Application.Exit();
}
}


C#进程间发消息

普通方法无法获取到无窗体的程序的窗体句柄

private void button1_Click(object sender, EventArgs e)
{
IntPtr ippp = GetCurrentWindowHandle();
SendMess(ippp.ToInt32(), "111");
}

[DllImport("user32.dll")]
public static extern IntPtr PostMessage(int hWnd, int Msg, IntPtr wParam, int lParam);
[DllImport("user32.dll")]
public static extern int SendMessage(int hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam);
public const int WM_USER = 0x0400;//用户自定义消息
public const int WM_POSTMESSAGE = WM_USER + 1000;//发送信息
public const int defaultlParam = 0;
public const int WM_COPYDATA = 0x004A;
public Int64 m_Handle;//发送消息的句柄

/// <summary>
/// 重载函数,只传递字符串
/// </summary>
/// <param name="Handle">目标句柄</param>
/// <param name="lParam">字符串</param>
public void SendMess(int Handle, string lParam)
{
byte[] chrs = Encoding.Default.GetBytes(lParam);
int size = chrs.Length;
COPYDATASTRUCT cds;
cds.dwData = (IntPtr)100;
cds.cbData = size + 1;
cds.lpData = lParam;
if (Handle > 0)
SendMessage(Handle, WM_COPYDATA, 0, ref cds);
}

/// <summary>
/// PostMessage方法发送消息
/// </summary>
/// <param name="Handle">目标句柄</param>
/// <param name="wParam">发送的消息</param>
public void PostMess(int Handle, string wParam)
{
IntPtr p = Marshal.StringToHGlobalAnsi(wParam);
if (Handle > 0)
PostMessage(Handle, WM_POSTMESSAGE, p, 0);
}
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
}

private static Hashtable processWnd = null;
public delegate bool WNDENUMPROC(IntPtr hwnd, uint lParam);

[DllImport("user32.dll", EntryPoint = "EnumWindows", SetLastError = true)]
public static extern bool EnumWindows(WNDENUMPROC lpEnumFunc, uint lParam);
[DllImport("user32.dll", EntryPoint = "GetParent", SetLastError = true)]
public static extern IntPtr GetParent(IntPtr hWnd);
[DllImport("user32.dll", EntryPoint = "GetWindowThreadProcessId")]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, ref uint lpdwProcessId);
[DllImport("user32.dll", EntryPoint = "IsWindow")]
public static extern bool IsWindow(IntPtr hWnd);
[DllImport("kernel32.dll", EntryPoint = "SetLastError")]
public static extern void SetLastError(uint dwErrCode);
public static IntPtr GetCurrentWindowHandle()
{
IntPtr ptrWnd = IntPtr.Zero;
if (processWnd == null)
{
processWnd = new Hashtable();
}
System.Diagnostics.Process[] procs = System.Diagnostics.Process.GetProcessesByName("FutureReport.Mars.Viewer.vshost");
System.Diagnostics.Process p = procs[0];
uint uiPid = (uint)p.Id;  // 当前进程 ID
object objWnd = processWnd[uiPid];
if (objWnd != null)
{
ptrWnd = (IntPtr)objWnd;
if (ptrWnd != IntPtr.Zero && IsWindow(ptrWnd))  // 从缓存中获取句柄
{
return ptrWnd;
}
else
{
ptrWnd = IntPtr.Zero;
}
}
bool bResult = EnumWindows(new WNDENUMPROC(EnumWindowsProc), uiPid);
// 枚举窗口返回 false 并且没有错误号时表明获取成功
if (!bResult && Marshal.GetLastWin32Error() == 0)
{
objWnd = processWnd[uiPid];
if (objWnd != null)
{
ptrWnd = (IntPtr)objWnd;
}
}
return ptrWnd;
}
private static bool EnumWindowsProc(IntPtr hwnd, uint lParam)
{
uint uiPid = 0;
if (GetParent(hwnd) == IntPtr.Zero)
{
GetWindowThreadProcessId(hwnd, ref uiPid);
if (uiPid == lParam)    // 找到进程对应的主窗口句柄
{
processWnd[uiPid] = hwnd;   // 把句柄缓存起来
SetLastError(0);    // 设置无错误
return false;   // 返回 false 以终止枚举窗口
}
}
return true;
}


GetCurrentWindowHandle()是获取隐藏窗体句柄的方法(程序无窗体,普通方法获取主线程句柄为空)

C#窗体接收消息

protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_POSTMESSAGE:
string str = Marshal.PtrToStringAnsi(m.WParam);
MessageBox.Show(str);
break;
case WM_COPYDATA:
COPYDATASTRUCT myStr = new COPYDATASTRUCT();
Type myType = myStr.GetType();
myStr = (COPYDATASTRUCT)m.GetLParam(myType);
MessageBox.show(myStr.lpData);
this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
this.Show();
break;
default:
base.WndProc(ref m);
break;
}
}

public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
}


虽然最后发现其实Mutex就能解决实际问题,但是这也算是一次完整的学习经验
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: