调用 SendMessage (P/Invoke) 不断崩溃
我必须编写一个与第三方程序通信的应用程序(AOL,我'抱歉。:()
做了很多研究,我发现了一些方法可以使用 P/Invoke,并且在大多数情况下它都可以正常工作,但是在随后的试验中它会崩溃,特别是在使用 SendMessage
时,我在下面概述了
所有这些 崩溃的代码。从旧的 Visual Basic 文件移植到 .NET 它可能是过时的,我理解如果这是不可行的 - 我只是希望有一个比 Visual Basic 4.0 更好的方法来完成这个任务。
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr hwndParent,
IntPtr hwndChildAfter,
string lpszClass,
string lpszWindow);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle,
IntPtr childAfter,
string className,
IntPtr windowTitle);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(HandleRef hWnd,
UInt32 Msg,
IntPtr wParam,
IntPtr lParam);
[DllImport("user32.dll", EntryPoint="SendMessageW")]
public static extern IntPtr SendMessageByString(HandleRef hWnd,
UInt32 Msg,
IntPtr wParam,
StringBuilder lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode , EntryPoint = "SendMessageW")]
public static extern IntPtr SendMessageByString(HandleRef hWnd,
UInt32 Msg,
IntPtr wParam,
String lParam);
public IntPtr FindClientWindow()
{
IntPtr aol = IntPtr.Zero;
IntPtr mdi = IntPtr.Zero;
IntPtr child = IntPtr.Zero;
IntPtr rich = IntPtr.Zero;
IntPtr aollist = IntPtr.Zero;
IntPtr aolicon = IntPtr.Zero;
IntPtr aolstatic = IntPtr.Zero;
aol = Invoke.FindWindow("AOL Frame25", null);
mdi = Invoke.FindWindowEx(aol, IntPtr.Zero, "MDIClient", null);
child = Invoke.FindWindowEx(mdi, IntPtr.Zero, "AOL Child", null);
rich = Invoke.FindWindowEx(child, IntPtr.Zero, "RICHCNTL", null);
aollist = Invoke.FindWindowEx(child, IntPtr.Zero, "_AOL_Listbox", null);
aolicon = Invoke.FindWindowEx(child, IntPtr.Zero, "_AOL_Icon", null);
aolstatic = Invoke.FindWindowEx(child, IntPtr.Zero, "_AOL_Static", null);
if (rich != IntPtr.Zero &&
aollist != IntPtr.Zero &&
aolicon != IntPtr.Zero &&
aolstatic != IntPtr.Zero)
return child;
do
{
child = Invoke.FindWindowEx(mdi, child, "AOL Child", null);
rich = Invoke.FindWindowEx(child, IntPtr.Zero, "RICHCNTL", null);
aollist = Invoke.FindWindowEx(child, IntPtr.Zero, "_AOL_Listbox", null);
aolicon = Invoke.FindWindowEx(child, IntPtr.Zero, "_AOL_Icon", null);
aolstatic = Invoke.FindWindowEx(child, IntPtr.Zero, "_AOL_Static", null);
if (rich != IntPtr.Zero &&
aollist != IntPtr.Zero &&
aolicon != IntPtr.Zero &&
aolstatic != IntPtr.Zero)
return child;
}
while (child != IntPtr.Zero)
;
return child;
}
IntPtr room = IntPtr.Zero;
IntPtr child = IntPtr.Zero;
IntPtr length = IntPtr.Zero;
IntPtr roomHandle = IntPtr.Zero;
child = FindClientWindow();
room = FindChildByClass(child, "RICHCNTLREADONLY");
HandleRef n = new HandleRef(IntPtr.Zero, room);
length = SendMessage(n, 0x000E, IntPtr.Zero, IntPtr.Zero);
// This is the line that keeps crashing on me.
SendMessageByString(n, 0x000D, new IntPtr( length.ToInt32() + 1 ), str);
public IntPtr FindChildByClass(IntPtr parent, string child)
{
return Invoke.FindWindowEx(parent, IntPtr.Zero, child, null);
}
I am having to write an application that communicates with a third-party program (AOL, I'm sorry. :()
Doing a lot of research I found some ways to do this with P/Invoke, and for the most part it works okay, but it crashes upon subsequent trials, specifically with SendMessage
. I'm outlining the crashing code below.
All of this was ported to .NET from old, old Visual Basic files. It's archaic as it can be, and I understand if it's not doable - I was just hoping there was a better way than Visual Basic 4.0 to get this done.
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr hwndParent,
IntPtr hwndChildAfter,
string lpszClass,
string lpszWindow);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle,
IntPtr childAfter,
string className,
IntPtr windowTitle);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(HandleRef hWnd,
UInt32 Msg,
IntPtr wParam,
IntPtr lParam);
[DllImport("user32.dll", EntryPoint="SendMessageW")]
public static extern IntPtr SendMessageByString(HandleRef hWnd,
UInt32 Msg,
IntPtr wParam,
StringBuilder lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode , EntryPoint = "SendMessageW")]
public static extern IntPtr SendMessageByString(HandleRef hWnd,
UInt32 Msg,
IntPtr wParam,
String lParam);
public IntPtr FindClientWindow()
{
IntPtr aol = IntPtr.Zero;
IntPtr mdi = IntPtr.Zero;
IntPtr child = IntPtr.Zero;
IntPtr rich = IntPtr.Zero;
IntPtr aollist = IntPtr.Zero;
IntPtr aolicon = IntPtr.Zero;
IntPtr aolstatic = IntPtr.Zero;
aol = Invoke.FindWindow("AOL Frame25", null);
mdi = Invoke.FindWindowEx(aol, IntPtr.Zero, "MDIClient", null);
child = Invoke.FindWindowEx(mdi, IntPtr.Zero, "AOL Child", null);
rich = Invoke.FindWindowEx(child, IntPtr.Zero, "RICHCNTL", null);
aollist = Invoke.FindWindowEx(child, IntPtr.Zero, "_AOL_Listbox", null);
aolicon = Invoke.FindWindowEx(child, IntPtr.Zero, "_AOL_Icon", null);
aolstatic = Invoke.FindWindowEx(child, IntPtr.Zero, "_AOL_Static", null);
if (rich != IntPtr.Zero &&
aollist != IntPtr.Zero &&
aolicon != IntPtr.Zero &&
aolstatic != IntPtr.Zero)
return child;
do
{
child = Invoke.FindWindowEx(mdi, child, "AOL Child", null);
rich = Invoke.FindWindowEx(child, IntPtr.Zero, "RICHCNTL", null);
aollist = Invoke.FindWindowEx(child, IntPtr.Zero, "_AOL_Listbox", null);
aolicon = Invoke.FindWindowEx(child, IntPtr.Zero, "_AOL_Icon", null);
aolstatic = Invoke.FindWindowEx(child, IntPtr.Zero, "_AOL_Static", null);
if (rich != IntPtr.Zero &&
aollist != IntPtr.Zero &&
aolicon != IntPtr.Zero &&
aolstatic != IntPtr.Zero)
return child;
}
while (child != IntPtr.Zero)
;
return child;
}
IntPtr room = IntPtr.Zero;
IntPtr child = IntPtr.Zero;
IntPtr length = IntPtr.Zero;
IntPtr roomHandle = IntPtr.Zero;
child = FindClientWindow();
room = FindChildByClass(child, "RICHCNTLREADONLY");
HandleRef n = new HandleRef(IntPtr.Zero, room);
length = SendMessage(n, 0x000E, IntPtr.Zero, IntPtr.Zero);
// This is the line that keeps crashing on me.
SendMessageByString(n, 0x000D, new IntPtr( length.ToInt32() + 1 ), str);
public IntPtr FindChildByClass(IntPtr parent, string child)
{
return Invoke.FindWindowEx(parent, IntPtr.Zero, child, null);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您正在使用宽字节 SendMessage..ie 来表示宽字符,您是否尝试过普通的 Sendmessage..
public static extern int SendMessage(IntPtr hWnd, UInt32 Msg, Int32 wParam, Int32 lParam);
我还注意到,就像您试图根据 RichTextBox 控件的句柄更改值一样,因此在另一个进程中查找 AOL 的客户端窗口...这是正确的吗?
这可能是问题的根源,直接修改属于不属于您的窗口的控件(您的程序是托管的,修改非托管进程的窗口)......这可以解释它崩溃的原因。您能澄清一下十六进制常量的用途吗?
编辑:当您使用 WM_GETTEXTLENGTH 和 WM_GETTEXT 时,它们是 Windows 消息的一部分,用于从控件中检索文本长度和实际文本。如果您查看此处,看看 pinvoke.net 需要做什么说说它们..当您使用 WM_GETTEXTLENGTH 和 WM_GETTEXT 发出“SendMessage”时,您是在告诉 Windows - '嘿,请告诉我我在参数
n 中给您的关联句柄中文本的长度
。我突然想到,值得尝试...我会摆脱那些 SendMessage pinvokes 并只使用这个...尝试一下然后回到这里...:)
希望这会有所帮助,
此致,
汤姆.
You are using the Wide byte SendMessage..ie for Wide Characters, have you tried the normal Sendmessage..
public static extern int SendMessage(IntPtr hWnd, UInt32 Msg, Int32 wParam, Int32 lParam);
I also notice it's like as if you are trying to change the value based on the handle of the richtextbox's control hence the looking around for the AOL's client window in another process...is that correct?
That could be the source of the problem, directly modifying a control that belongs to a window that is not yours (your program is managed, modifying a unmanaged process's window)...that could explain why it crashed. Can you clarify what is the hex constants for?
Edit: When you use the WM_GETTEXTLENGTH and WM_GETTEXT, they are part of the Windows Messages to retrieve the text length and the actual text from the control. If you look here and see what pinvoke.net has to say about them..When you issue a 'SendMessage', with WM_GETTEXTLENGTH and WM_GETTEXT, you are telling Windows - 'Hey, get me the length of the text in that associated handle which I've given you in the parameter
n
. Just occurred to me, worth trying out...I would get rid of those SendMessage pinvokes and use just this one..Try that and get back here ... :)
Hope this helps,
Best regards,
Tom.
您是否设法解决“尝试读取或写入受保护的内存”问题。错误? t0mm13b的答案似乎分配了一个
StringBuilder 的缓冲区太小了一个字符(无法容纳尾随的 '\0')。
这是适合我的代码:
Did you manage to solve the "Attempted to read or write protected memory." error? t0mm13b's answer seems to allocate a
StringBuilder
whose buffer is one character too small (to accommodate the trailing '\0').Here's code that works for me:
在类似的情况下,我从
Marshal.PtrToStringUni(bf)
语句中崩溃,其中SendMessage
使用WM_GETTEXTLENGTH
返回文本长度的“错误大小” code> 参数(控制类为“RICHEDIT50W”;多行文本)。我曾尝试添加 1、10、100(到文本长度查询结果),但仍然会收到错误,即使(稍后)文本长度等于第一次调用返回的长度 (
WM_GETTEXTLENGTH
) 。我的解决方案是:我将结果乘以 2,然后进行修剪。
我确实使用了
Marshal.AllocHGlobal(sz)
,然后使用Marshal.Release(bf)< /code>,所以内存效率没有问题。我的猜测是,对于多行文本,即使文本大小精确 (+1),
Marshal.AllocHGlobal(sz)
也没有在内存中留出足够的空间。也许文本中的返回字符(vbCr,vbLf)需要更多内存:我没有找到任何东西可以解释这个问题,但是加倍大小对我有用。
I was getting a crash from
Marshal.PtrToStringUni(bf)
statement in similar situation whereSendMessage
was returning a "wrong size" for a text length withWM_GETTEXTLENGTH
argument (the control class was "RICHEDIT50W"; multi-line text).I had tried adding 1, 10, 100 (to text length query result) and still would get an error even though (later on) the text length was equal what was returned from the first call (
WM_GETTEXTLENGTH
).My solution was: I multiplied the result with 2 then I trimmed it.
I did use
Marshal.AllocHGlobal(sz)
and thenMarshal.Release(bf)
, so there was no problem with memory efficiency. My guess is that for multi-line textsMarshal.AllocHGlobal(sz)
wasn't making enough space in the memory even with exact text size (+1).Maybe the return character within the text (vbCr, vbLf) requires more memory: I found nothing to explain this isue, but doubling the size worked for me.