调用Message.GetLParam时收到间歇性错误,在进程之间发送消息。 我有两个进程,都是用C#(.Net 3.5)编写的。我正在使用Win32函数SendMessage()将数据从一个进程(源)发送到另一个进程(目标)。目标进程的主窗口(它是Windows窗体应用程序)会覆盖WndProc()函数以接收消息。 源进程通过使用Process.GetProcessesByName()函数定位另一个,然后使用Process.MainWindowHandle获取我要将消息发送到的窗口句柄。源代码如下所示:
Process[] procs = Process.GetProcessesByName("MyTargetProcess");
if (procs != null
&& procs.Length > 0)
{
IntPtr win = procs[0].MainWindowHandle;
var someData = new Win32.COPYDATASTRUCT // This is a struct that I defined
{
// Initialize fields of the struct
};
Win32.SendMessage(win,
Win32.MyMsgCode, // my custom message
IntPtr.Zero, // wParam = 0
ref someData);
}
目标流程代码如下所示:
protected override void WndProc(ref System.Windows.Forms.Message m)
{
if (m.Msg == Win32.MyMsgCode)
{
Win32.COPYDATASTRUCT ds;
try
{
ds = (Win32.COPYDATASTRUCT)m.GetLParam(typeof(Win32.COPYDATASTRUCT));
}
catch (Exception ex)
{
log.ErrorFormat("Got exception in WndProc", ex);
}
// Do something with the message
....
}
Win32是我定义的静态类,它获取我的所有P / Invoke定义。 我不明白为什么我在WndProc中捕获AccessViolationException。 有人知道为什么吗?为什么它只在某些时候发生?
感谢您的关注!
--------------------------------编辑-------------- ---------------------------- 令我感到困惑的另一件事是:COPYDATASTRUCT被声明为
public static readonly int WM_COPYDATA = 0x004a;
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
// Specifies data to be passed to the receiving application.
public string dwData;
// Specifies the size, in bytes, of the data pointed to by the lpData member.
public int cbData;
// Pointer to data to be passed to the receiving application. This member can be NULL.
public string lpData;
}
它初始化如下:
string payload = " some data ";
var someData = new Win32.COPYDATASTRUCT // This is a struct that I defined
{
dwData = "bogusData",
cbData = sizeof(char) * payload.Length,
lpData = payload
};
在目标代码中,我总是收到dwData = null。
-----------------------第二次编辑---------------------- ---------------- 我只是尝试添加零终止符,我仍然得到错误。 如果我更改编组代码以执行我自己的编组操作,如
IntPtr pcds = Marshal.AllocHGlobal(Marshal.SizeOf(someData));
Marshal.StructureToPtr(someData, pcds, true);
Win32.SendMessage(win, (uint)Win32.WM_COPYDATA, IntPtr.Zero, pcds);
然后错误一直发生!但是,如果我在catch块中重复GetLParam()调用,它会在第二次尝试时几乎一直成功。
答案 0 :(得分:0)
向我跳出来的是cbData
设置不正确。您需要考虑字符串末尾的零终结符。
cbData = sizeof(char) * (payload.Length+1)
这肯定会解释错误。当您发送消息时,WM_COPYDATA
编组不会复制零终止符,因此接收者将读取超出缓冲区末尾的未初始化值。
我也想知道sizeof(char)
。你在调用SendMessage的Unicode版本吗?如果没有,那么我希望在发送代码中看到访问冲突。
您还应该警惕收件人应用程序打开自己以缓冲溢出。因为它忽略了cbData
的值并将lpData
字段视为以空值终止的指针,所以攻击者可能会强制您的应用程序执行任意代码。为防止这种情况,您应该将数据cbData
字节复制到字节数组中,然后转换为字符串。
另一个问题是您需要将dwData
声明为UIntPtr
。您定义结构的方式,收件人代码将dwData
视为指向字符串的指针,该字符串将引发AV,因为您已跨越了进程边界。
我还要指出cbData
是无符号的,应该是uint
,但这是一个良性错误。