Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/261.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/12.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设置TreeViewItem复选框状态_C#_Pinvoke - Fatal编程技术网

C# 使用SendMessage设置TreeViewItem复选框状态

C# 使用SendMessage设置TreeViewItem复选框状态,c#,pinvoke,C#,Pinvoke,我需要更改外部应用程序拥有的TreeView(确切地说是“SystemReview32”)项中的复选框状态,以实现自动化。我已经有了TreeView手柄和TreeView项目手柄。我还找到了一些示例,说明如何设置复选框状态,但由于某些原因,它不起作用(SendMessage返回0或使整个应用程序崩溃)。但要遵守守则。我已经尝试过的是: TVITEM结构: [StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Auto)]

我需要更改外部应用程序拥有的TreeView(确切地说是“SystemReview32”)项中的复选框状态,以实现自动化。我已经有了TreeView手柄和TreeView项目手柄。我还找到了一些示例,说明如何设置复选框状态,但由于某些原因,它不起作用(SendMessage返回0或使整个应用程序崩溃)。但要遵守守则。我已经尝试过的是:

TVITEM结构:

[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Auto)]
internal struct TVITEM
{
    public int mask;
    public IntPtr hItem;
    public int state;
    public int stateMask;
    [MarshalAs(UnmanagedType.LPTStr)]
    public string pszText;
    public int cchTextMax;
    public int iImage;
    public int iSelectedImage;
    public int cChildren;
    public IntPtr lParam;
 }
SendMessage的pinvoke:

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int SendMessage(IntPtr hWnd, int msg, IntPtr wParam, ref TVITEM lParam);
我的方法是:

internal static void SetTreeNodeState(int treeViewHandler, int treeViewItemHandler, bool state)
{
    TVITEM tvItem = new TVITEM();
    tvItem.mask = TVIF_STATE | TVIF_HANDLE;
    tvItem.hItem = (IntPtr)treeViewItemHandler;
    tvItem.stateMask = TVIS_STATEIMAGEMASK;
    tvItem.state = (state ? 2 : 1) << 12;
    var result = SendMessage((IntPtr)treeViewHandler, TVM_SETITEMW, IntPtr.Zero, ref tvItem);
}
内部静态void SetTreeNodeState(int-treeViewHandler、int-treeViewItemHandler、bool状态)
{
TVITEM TVITEM=新的TVITEM();
tvItem.mask=TVIF_状态| TVIF_句柄;
tviItem.hItem=(IntPtr)treeViewItemHandler;
tviItem.stateMask=TVIS\u StateMimageMask;

tvItem.state=(状态?2:1)当您发送此特定消息时,您需要提供结构的地址。由于该窗口属于其他进程,因此您提供的地址无效。Windows进程具有隔离的虚拟内存地址空间。您提供的地址在进程中有效,但仅在进程中有效

为了避免此问题并发送此消息,您需要使用
VirtualAllocEx
在目标进程中分配内存。您还需要使用
WriteProcessMemory
来填充结构。如果您的进程和目标进程广告不同的比特数。你需要对像
pszText
这样的成员使用相同的技巧,它们本身就是指针

这里已经有很多问题涉及到跨进程消息编组的主题。我相信您将能够找到它们。同样,现在您已经意识到这个问题,可以在web上找到大量教程


也许一个更大的问题是,另一个进程的响应方式可能与您期望的被外界以这种方式戳到的方式不同。如果您发现编写自己的跨进程自动化非常具有挑战性,请不要感到惊讶。与其这样做,为什么不使用UI自动化呢?

当您发送此特定消息时,您是应提供结构的地址。由于窗口由其他进程拥有,因此您提供的地址无效。Windows进程具有独立的虚拟内存地址空间。您提供的地址在进程中有效,但仅在进程中有效

为了避免此问题并发送此消息,您需要使用
VirtualAllocEx
在目标进程中分配内存。您还需要使用
WriteProcessMemory
来填充结构。如果您的进程和目标进程广告不同的比特数。你需要对像
pszText
这样的成员使用相同的技巧,它们本身就是指针

这里已经有很多问题涉及到跨进程消息编组的主题。我相信您将能够找到它们。同样,现在您已经意识到这个问题,可以在web上找到大量教程


也许一个更大的问题是,另一个进程可能不会像你期望的那样以这种方式受到外界的攻击。如果你发现编写自己的跨进程自动化非常具有挑战性,请不要感到惊讶。与其这样做,为什么不使用UI自动化?

好的,多亏了David Heffernan,我想到了这一点我已经为SendMessage创建了重载,它接受lParam作为引用的对象:

[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, uint nSize, out UIntPtr lpNumberOfBytesWritten);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] buffer, Int32 nSize, out IntPtr lpNumberOfBytesRead);

[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
private static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, AllocationType flAllocationType, MemoryProtection flProtect);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
private static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, AllocationType dwFreeType);

private static IntPtr SendMessage<T>(Process process, IntPtr hWnd, int msg, int wParam, ref T lParam)
{
    uint size = (uint)Marshal.SizeOf(lParam);
    byte[] buffer = new byte[size];
    IntPtr processHandle = process.Handle;

    IntPtr pPointer = VirtualAllocEx(processHandle, IntPtr.Zero, size, AllocationType.Commit | AllocationType.Reserve, MemoryProtection.ReadWrite);

    IntPtr inputPtr = Marshal.AllocHGlobal((int)size);
    IntPtr outputPtr = Marshal.AllocHGlobal((int)size);

    Marshal.StructureToPtr(lParam, inputPtr, false);

    WriteProcessMemory(processHandle, pPointer, inputPtr, size, out UIntPtr nNbBytesWritten);
    IntPtr resultPtr = SendMessage(hWnd, msg, wParam, pPointer);
    ReadProcessMemory(processHandle, pPointer, buffer, buffer.Length, out IntPtr nNbBytesRead);

    Marshal.Copy(buffer, 0, outputPtr, (int)size);
    T result = Marshal.PtrToStructure<T>(outputPtr);
    lParam = result;

    Marshal.FreeHGlobal(inputPtr);
    Marshal.FreeHGlobal(outputPtr);
    VirtualFreeEx(processHandle, pPointer, 0, AllocationType.Release);
    return resultPtr;
}
电视节目:

[StructLayout(LayoutKind.Sequential)]
internal struct TVITEM
{
    public uint mask;
    public IntPtr hItem;
    public uint state;
    public uint stateMask;
    public IntPtr pszText;
    public int cchTextMax;
    public int iImage;
    public int iSelectedImage;
    public int cChildren;
    public IntPtr lParam;
}

好的,多亏了David Heffernan,我解决了这个问题。我已经为SendMessage创建了重载,它接受lParam作为引用的对象:

[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, uint nSize, out UIntPtr lpNumberOfBytesWritten);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] buffer, Int32 nSize, out IntPtr lpNumberOfBytesRead);

[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
private static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, AllocationType flAllocationType, MemoryProtection flProtect);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
private static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, AllocationType dwFreeType);

private static IntPtr SendMessage<T>(Process process, IntPtr hWnd, int msg, int wParam, ref T lParam)
{
    uint size = (uint)Marshal.SizeOf(lParam);
    byte[] buffer = new byte[size];
    IntPtr processHandle = process.Handle;

    IntPtr pPointer = VirtualAllocEx(processHandle, IntPtr.Zero, size, AllocationType.Commit | AllocationType.Reserve, MemoryProtection.ReadWrite);

    IntPtr inputPtr = Marshal.AllocHGlobal((int)size);
    IntPtr outputPtr = Marshal.AllocHGlobal((int)size);

    Marshal.StructureToPtr(lParam, inputPtr, false);

    WriteProcessMemory(processHandle, pPointer, inputPtr, size, out UIntPtr nNbBytesWritten);
    IntPtr resultPtr = SendMessage(hWnd, msg, wParam, pPointer);
    ReadProcessMemory(processHandle, pPointer, buffer, buffer.Length, out IntPtr nNbBytesRead);

    Marshal.Copy(buffer, 0, outputPtr, (int)size);
    T result = Marshal.PtrToStructure<T>(outputPtr);
    lParam = result;

    Marshal.FreeHGlobal(inputPtr);
    Marshal.FreeHGlobal(outputPtr);
    VirtualFreeEx(processHandle, pPointer, 0, AllocationType.Release);
    return resultPtr;
}
电视节目:

[StructLayout(LayoutKind.Sequential)]
internal struct TVITEM
{
    public uint mask;
    public IntPtr hItem;
    public uint state;
    public uint stateMask;
    public IntPtr pszText;
    public int cchTextMax;
    public int iImage;
    public int iSelectedImage;
    public int cChildren;
    public IntPtr lParam;
}

我想指出的是,您的代码中有一些奇怪之处。您使用术语“handler”来表示“handle”。您对这些句柄使用类型
int
,但您应该使用
IntPtr
。如果这样做,您将不会发现自己将值强制转换为
IntPtr
。这些强制转换是错误的信号。使用
Pack=8
肯定是错误的。我猜您在尝试和出错时添加了这一点模式。在进入该模式之前,最好先发布代码。您使用
TVM\U SETITEMW
,但是
CharSet.Auto
。应该是
CharSet.Unicode
。是的,的确如此。感谢您指出这一点。我设法清除了我的代码。您的代码中有一些奇怪之处,我想指出。您使用的术语是“处理程序”为了一个“把手”。您对这些句柄使用类型
int
,但您应该使用
IntPtr
。如果这样做,您将不会发现自己将值强制转换为
IntPtr
。这些强制转换是错误的信号。使用
Pack=8
肯定是错误的。我猜您在尝试和出错时添加了这一点模式。在进入该模式之前,最好先发布代码。使用
TVM\U SETITEMW
,然后使用
CharSet.Auto
。应该是
CharSet.Unicode
。是的,的确如此。谢谢你指出这一点。我成功地清除了我的代码。非常感谢你!感谢你的提示,我设法解决了这个问题。我随时都会发布我的解决方案ute now:)非常感谢!多亏了你的提示,我终于找到了答案。我现在随时都会发布我的解决方案:)