c#使用SendMessage, WM_COPYDATA的问题
本文关键字:COPYDATA 问题 WM 使用 SendMessage | 更新日期: 2023-09-27 18:03:07
我已经花了几天(或更多)的时间试图让这个工作。
手头的应用程序是FTPRush
,我知道有一个名为rush_cmdline.exe
的cmd行应用程序,它使用SendMessage
向FTPRush
发送请求。
从调试rush_cmdline.exe
我可以看到lParam
, wParam
, Message
和hWnd
。
我的代码如下(使用SendMessage,不是SendMessageW):
[DllImport("User32.dll", EntryPoint = "FindWindow")]
public static extern Int32 FindWindow(String lpClassName, String lpWindowName);
[DllImport("USER32.DLL", EntryPoint= "SendMessage")]
public static extern IntPtr SendMessage(int hWnd, int Msg, int wParam, IntPtr lParam);
我还尝试了另一种规格:
[DllImport("User32.dll", EntryPoint = "SendMessage")]
public static extern int SendMessage(int hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam);
句柄(hWnd
)不是问题,因为它工作:
int ftprush = FindWindow("TfmRush", null);
ShowWindow(ftprush, 8);
我没有粘贴dllimport,因为它在这里不重要。让我知道如果你想看到它)带来的窗口到前面。此外,我通过调试rush_cmdline.exe
进行了检查。所以句柄是一样的
两次尝试都失败(静默):
public const Int32 WM_COPYDATA = 0x4A;
string msg = "RushApp.FTP.Login('backup','',0); ";
// 1
byte[] array = Encoding.UTF8.GetBytes((string)msg);
int size = Marshal.SizeOf(array[0]) * array.Length + Marshal.SizeOf(array[0]);
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.Copy(array, 0, ptr, array.Length);
Marshal.WriteByte(ptr, size - 1, 0);
SendMessage(ftprush, WM_COPYDATA, 0, ptr);
// 2
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
}
COPYDATASTRUCT cds;
cds.dwData = (IntPtr)100;
cds.lpData = msg;
cds.cbData = sarr.Length + 1;
SendMessage(ftprush, WM_COPYDATA, 0, ref cds);
我希望至少第二个解决方案可以工作,因为它与这个匹配得很好:
任何启发都是非常感激的!
谢谢,
- 弗兰克
string msg = "RushApp.FTP.Login('backup','',0);'0";
var cds = new COPYDATASTRUCT
{
dwData = new IntPtr(3),
cbData = msg.Length + 1,
lpData = msg
};
IntPtr ftprush = FindWindow("TfmRush", null);
SendMessage(ftprush, WM_COPYDATA, IntPtr.Zero, ref cds);
My Definitions have
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, ref COPYDATASTRUCT lParam);
public struct COPYDATASTRUCT {
public int cbData;
public IntPtr dwData;
[MarshalAs(UnmanagedType.LPStr)] public string lpData;
}
var cds = new Win32.COPYDATASTRUCT {
dwData = new IntPtr(3),
cbData = str.Length + 1,
lpData = str
};
Win32.SendMessage(ftprush, Win32.WM_COPYDATA, IntPtr.Zero, ref cds);
当然,要确保str以null结尾"'0"
可以选择由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.
在上面的两个答案之间,我拼凑了一个工作示例。Bryce Wagner的类可以工作,所以我添加了一个方法来使用SendMessageTimeout发送数据。这是一个静态方法,你只需调用它来发送数据。这不是我真正的工作,只是把它们粘在一起,然后分享回来。
[StructLayout(LayoutKind.Sequential)]
public struct CopyData: IDisposable {
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint Msg, IntPtr wParam, ref CopyData target,
SendMessageTimeoutFlags fuFlags, uint uTimeout, out UIntPtr lpdwResult);
[Flags]
enum SendMessageTimeoutFlags: uint {
SMTO_NORMAL = 0x0,
SMTO_BLOCK = 0x1,
SMTO_ABORTIFHUNG = 0x2,
SMTO_NOTIMEOUTIFNOTHUNG = 0x8
}
const uint WM_COPYDATA = 0x4A;
public IntPtr dwData;
public int cbData;
public IntPtr lpData;
public void Dispose() {
if (lpData != IntPtr.Zero) {
Marshal.FreeCoTaskMem(lpData);
lpData = IntPtr.Zero;
cbData = 0;
}
}
public string AsAnsiString {
get { return Marshal.PtrToStringAnsi(lpData, cbData); }
}
public string AsUnicodeString {
get { return Marshal.PtrToStringUni(lpData); }
}
public static CopyData CreateForString(int dwData, string value, bool Unicode = false) {
var result = new CopyData();
result.dwData = (IntPtr) dwData;
result.lpData = Unicode ? Marshal.StringToCoTaskMemUni(value) : Marshal.StringToCoTaskMemAnsi(value);
result.cbData = value.Length + 1;
return result;
}
public static UIntPtr Send(IntPtr targetHandle, int dwData, string value, uint timeoutMs = 1000, bool Unicode = false) {
var cds = CopyData.CreateForString(dwData, value, Unicode);
UIntPtr result;
SendMessageTimeout(targetHandle, WM_COPYDATA, IntPtr.Zero, ref cds, SendMessageTimeoutFlags.SMTO_NORMAL, timeoutMs, out result);
cds.Dispose();
return result;
}
}
使用它:
CopyData.Send(targetHandle, 1234, "This is a test");
使用默认的1秒超时。
COPYDATASTRUCT中参数的顺序非常重要,而Bob Vale的答案中参数的顺序是错误的。http://msdn.microsoft.com/en-us/library/windows/desktop/ms649010(v=vs.85).aspx应该是这样的顺序:
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
public IntPtr lpData;
}
我还没有得到MarshalAs(UnmanagedType.LPStr)] public string lpData
的工作。我只是通过自己做编组来让它工作:
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT : IDisposable
{
public IntPtr dwData;
public int cbData;
public IntPtr lpData;
/// <summary>
/// Only dispose COPYDATASTRUCT if you were the one who allocated it
/// </summary>
public void Dispose()
{
if (lpData != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(lpData);
lpData = IntPtr.Zero;
cbData = 0;
}
}
public string AsAnsiString { get { return Marshal.PtrToStringAnsi(lpData, cbData); } }
public string AsUnicodeString { get { return Marshal.PtrToStringUni(lpData); } }
public static COPYDATASTRUCT CreateForString(int dwData, string value, bool Unicode = false)
{
var result = new COPYDATASTRUCT();
result.dwData = (IntPtr)dwData;
result.lpData = Unicode ? Marshal.StringToCoTaskMemUni(value) : Marshal.StringToCoTaskMemAnsi(value);
result.cbData = value.Length + 1;
return result;
}
}