Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/301.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 调用SendMessage(P/Invoke)不断崩溃_C#_Pinvoke - Fatal编程技术网

C# 调用SendMessage(P/Invoke)不断崩溃

C# 调用SendMessage(P/Invoke)不断崩溃,c#,pinvoke,C#,Pinvoke,我必须编写一个与第三方程序通信的应用程序(,对不起:) 我做了大量的研究,发现了一些方法可以做到这一点,在大多数情况下,它工作正常,但在随后的试验中崩溃了,特别是在SendMessage中。我在下面概述了崩溃的代码 所有这些都是从古老的Visual Basic文件移植到的。它可能是过时的,我理解如果它不可行的话——我只是希望有一种比Visual Basic 4.0更好的方法来完成这项工作 [DllImport("kernel32.dll", SetLastError = true)] [retu

我必须编写一个与第三方程序通信的应用程序(,对不起:)

我做了大量的研究,发现了一些方法可以做到这一点,在大多数情况下,它工作正常,但在随后的试验中崩溃了,特别是在
SendMessage
中。我在下面概述了崩溃的代码

所有这些都是从古老的Visual Basic文件移植到的。它可能是过时的,我理解如果它不可行的话——我只是希望有一种比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);
}

您正在使用宽字节SendMessage..ie对于宽字符,您是否尝试过普通SendMessage。。
公共静态外部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 Pinvoke,只使用这一个

[DllImport("user32.dll", CharSet = CharSet.Auto)] static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, StringBuilder lParam); //If you use '[Out] StringBuilder', initialize the string builder with proper length first. [DllImport(“user32.dll”,CharSet=CharSet.Auto)] 静态外部IntPtr发送消息(IntPtr hWnd、UInt32消息、IntPtr wParam、StringBuilder LPRAM); //如果使用“[Out]StringBuilder”,请先用适当的长度初始化字符串生成器。 child=FindClientWindow(); 房间=FindChildByClass(child,“RICHCNTLREADONLY”); 长度=发送消息(n,0x000E,IntPtr.Zero,IntPtr.Zero); StringBuilder sbBuf=新StringBuilder(长度); SendMessageByString(room,0x000D,new IntPtr(length.ToInt32()+1),out sbBuf);//这是一条让我不断崩溃的线路。 试试看,然后回到这里……:)

希望这有帮助, 顺致敬意,
Tom。

您是否解决了“尝试读取或写入受保护内存”错误?似乎分配了一个
StringBuilder
,其缓冲区太小一个字符(无法容纳尾随的“\0”)

下面是对我有用的代码:

[DllImport("user32.dll", EntryPoint = "SendMessage", SetLastError = true)]
private static extern Int32 SendMessageByString(IntPtr wnd, UInt32 msg, Int32 WParam, StringBuilder output);
const int WM_GETTEXTLENGTH = 0x000e;
const int WM_GETTEXT = 0x000d;

public static string GetText(IntPtr hWnd)
{
    int len = SendMessageByString(hWnd, WM_GETTEXTLENGTH, 0, null);
    var sb = new StringBuilder(len + 1);  // +1 is for the trailing '\0'
    SendMessageByString(hWnd, WM_GETTEXT, sb.Capacity, sb);
    return sb.ToString();
}

在类似的情况下,
SendMessage
使用
WM_GETTEXTLENGTH
参数返回文本长度的“错误大小”(控件类为“RICHEDIT50W”;多行文本),我从
marshall.PtrToStringUni(bf)
语句中得到一个崩溃

我曾尝试添加1、10、100(到文本长度查询结果中),但仍然会得到一个错误,即使(稍后)文本长度与第一次调用返回的文本长度相等(
WM_GETTEXTLENGTH

我的解决方案是:将结果乘以2,然后对其进行修剪。

我确实使用了
Marshal.AllocHGlobal(sz)
,然后使用了
Marshal.Release(bf)
,所以内存效率没有问题。我的猜测是,对于多行文本
Marshal.AllocHGlobal(sz)
,即使使用精确的文本大小(+1),内存中也没有足够的空间


可能文本中的返回字符(vbCr,vbLf)需要更多的内存:我找不到任何东西来解释这一问题,但将大小增加一倍对我来说很有用。

您能添加更多代码吗,具体来说,n是多少,十六进制数,长度和字符串?你看了吗?当然,我给你加了所有的。我还将添加其他pinvoke。是的,pinvoke.net是我最初获得签名的地方。我正在模拟的前一个代码中存在十六进制常量-这是旧的visual basic 4代码-因此它很有可能不起作用。它们分别代表WM_GETTEXTLENGTH(0x000E)和WM_GETTEXT(0x000D)。我不完全知道这些是干什么用的——我对这方面很陌生。我很抱歉数据太弱,我通常在pinvoke方面很差。这给了我一个错误:“试图读取或写入受保护的内存。这通常表明其他内存已损坏。”嗯……您能否在实际窗口上运行spy++以查看句柄是什么,并将其与例程
FindClientWindow
在句柄上下文中返回的内容进行比较?另一件事…也许AOL已经锁定了进程本身的保护,以防止它被黑客攻击?另外,字符串“RICHCNTLREADONLY”可能是您试图访问的控件是只读的或锁定的…句柄匹配-我认为它没有被锁定。这种方法确实有效。它只工作一两次,然后就崩溃了。
[DllImport("user32.dll", EntryPoint = "SendMessage", SetLastError = true)]
private static extern Int32 SendMessageByString(IntPtr wnd, UInt32 msg, Int32 WParam, StringBuilder output);
const int WM_GETTEXTLENGTH = 0x000e;
const int WM_GETTEXT = 0x000d;

public static string GetText(IntPtr hWnd)
{
    int len = SendMessageByString(hWnd, WM_GETTEXTLENGTH, 0, null);
    var sb = new StringBuilder(len + 1);  // +1 is for the trailing '\0'
    SendMessageByString(hWnd, WM_GETTEXT, sb.Capacity, sb);
    return sb.ToString();
}