public void DoubleClickListview(IntPtr handle,int index)
        {
            AccessWin aw = new AccessWin();
            int vItemCount;
            int ColumnCount;
            IntPtr vHandle = handle;
            if (vHandle == IntPtr.Zero) return;           //选中Listview的某个Item 测试已工作,不过就是如果原来已经点中一个Item那么这次就变成复选了
            vItemCount = NativeMethods.SendMessageW(vHandle, NativeMethods.LVM_GETITEMCOUNT, 0, 0);
            IntPtr handleHeader = new IntPtr(NativeMethods.SendMessageW(vHandle, NativeMethods.LVM_GETHEADER, 0, 0));
            ColumnCount = NativeMethods.SendMessageW(handleHeader, NativeMethods.HDM_GETITEMCOUNT, 0, 0);
            uint vProcessId;
            NativeMethods.GetWindowThreadProcessId(vHandle, out vProcessId);
            IntPtr vProcess = NativeMethods.OpenProcess(NativeMethods.PROCESS_VM_OPERATION | NativeMethods.PROCESS_VM_READ | NativeMethods.PROCESS_VM_WRITE, false, vProcessId);
            IntPtr vPointer = NativeMethods.VirtualAllocEx(vProcess, IntPtr.Zero, 4096, NativeMethods.MEM_RESERVE | NativeMethods.MEM_COMMIT, NativeMethods.PAGE_READWRITE);
            NativeMethods.LVITEM[] vItem = new NativeMethods.LVITEM[1];
            vItem[0].state = NativeMethods.LVIS_SELECTED | NativeMethods.LVIS_FOCUSED | NativeMethods.LVIS_ACTIVATING;
            vItem[0].stateMask = NativeMethods.LVIS_SELECTED;
            uint vNumberOfBytesRead = 0;
            NativeMethods.WriteProcessMemory(vProcess, vPointer, Marshal.UnsafeAddrOfPinnedArrayElement(vItem, 0), Marshal.SizeOf(typeof(NativeMethods.LVITEM)), ref vNumberOfBytesRead);
            NativeMethods.SendMessageW(handle, NativeMethods.LVM_SETITEMSTATE, (uint)index, vPointer.ToInt32());            
            //伪造 WM_NOTIFY message并发给父窗口,这段完全不工作,也不报错误,不知道问题在哪,高人啊,快出来
            NativeMethods.NMHDR[] myNMHDR=new NativeMethods.NMHDR[1];
            IntPtr pNMHDR = NativeMethods.VirtualAllocEx(vProcess, IntPtr.Zero, (uint)Marshal.SizeOf(typeof(NativeMethods.NMHDR)), NativeMethods.MEM_COMMIT, NativeMethods.PAGE_READWRITE); 
    
            myNMHDR[0].code = NativeMethods.NM_DBLCLK;
            myNMHDR[0].hwndFrom = handle;
            myNMHDR[0].idFrom = (uint)NativeMethods.GetWindowLongW(handle, NativeMethods.GWL_ID);
            NativeMethods.WriteProcessMemory(vProcess, pNMHDR, Marshal.UnsafeAddrOfPinnedArrayElement(myNMHDR, 0), Marshal.SizeOf(typeof(NativeMethods.NMHDR)), ref vNumberOfBytesRead);
            IntPtr parenthwnd = NativeMethods.GetParent(handle);
            NativeMethods.SendMessageW(parenthwnd, NativeMethods.WM_NOTIFY, myNMHDR[0].idFrom, pNMHDR.ToInt32());            NativeMethods.CloseHandle(vProcess); 
            NativeMethods.VirtualFreeEx(vProcess, vPointer, 0, NativeMethods.MEM_RELEASE);
            NativeMethods.VirtualFreeEx(vProcess, pNMHDR,0, NativeMethods.MEM_RELEASE);        }

解决方案 »

  1.   

    现在我要控制另一个程序的ListView,打算用API的WM_NOTIFY实现,目前已经实现了选中某个Item,但无法双击它,双击的原理是通过进程注入一个NMHDR到目标程序,然后以伪造WM_NOTIFY消息以该ListView的名义发给父窗口,以实现响应的双击事件响应。这是基本思路...以下是我填充的NMHDR结构体
    myNMHDR[0].code = NativeMethods.NM_DBLCLK; 
    myNMHDR[0].hwndFrom = handle; //ListView的窗口句柄 
    myNMHDR[0].idFrom = (uint)NativeMethods.GetWindowLongW(handle,NativeMethods.GWL_ID);
    NativeMethods.SendMessageW(parenthwnd, NativeMethods.WM_NOTIFY, myNMHDR[0].idFrom, pNMHDR.ToInt32()); //这句是向ListView的父窗口发送WM_NOTIFY消息。  因为我要操作的ListView是Delphi的VCL控件 Class名字是TXPListview,不知道是不是不支持这个消息啊
      

  2.   


    你的代码没改好现在是双击啊,这是第一点错误。第二点我在vb版已经强调了,不能使用SendMessage发送消息,所以这句“NativeMethods.SendMessageW(parenthwnd, NativeMethods.WM_NOTIFY, myNMHDR[0].idFrom, pNMHDR.ToInt32());”要改成PostMessage来发送即可
      

  3.   

    谢谢,陈辉仁兄的耐心解答,可能我没有叙述清楚,我就是要双击一个item。关于PostMessage 和sendmessage我其实都试过,就是没反应。也没有任何报错信息以下是我按照PostMessage实现的代码,鉴于前面选中item的部分已经工作了,我就不重复贴了,再次严重感谢:            //伪造 WM_NOTIFY message并发给父窗口,这段完全不工作,也不报错误,不知道问题在哪,高人啊,快出来
                NativeMethods.NMHDR[] myNMHDR = new NativeMethods.NMHDR[1];
                IntPtr pNMHDR = NativeMethods.VirtualAllocEx(vProcess, IntPtr.Zero, (uint)Marshal.SizeOf(typeof(NativeMethods.NMHDR)), NativeMethods.MEM_COMMIT, NativeMethods.PAGE_READWRITE);            myNMHDR[0].code = NativeMethods.NM_DBLCLK;
                myNMHDR[0].hwndFrom = handle;
                myNMHDR[0].idFrom = (uint)NativeMethods.GetWindowLongW(handle, NativeMethods.GWL_ID);
                NativeMethods.WriteProcessMemory(vProcess, pNMHDR, Marshal.UnsafeAddrOfPinnedArrayElement(myNMHDR, 0), Marshal.SizeOf(typeof(NativeMethods.NMHDR)), ref vNumberOfBytesRead);
                IntPtr parenthwnd = NativeMethods.GetParent(NativeMethods.GetParent(handle));
                NativeMethods.PostMessageW(parenthwnd, NativeMethods.WM_NOTIFY, myNMHDR[0].idFrom, pNMHDR.ToInt32());            NativeMethods.VirtualFreeEx(vProcess, pNMHDR, 0, NativeMethods.MEM_RELEASE); //另外这句运行的时候,远程端程序会报一个内存访问冲突的错误            NativeMethods.CloseHandle(vProcess);
      

  4.   

    我现在一直在怀疑 TXPListview是不是不支持这个消息,Borland这个够呛的公司哦
      

  5.   

    this.SetStyle(ControlStyles.EnableNotifyMessage, true); 
      

  6.   


    看下你PostMessage怎么声明的,然后那句内存访问错误是因为PostMessage是立即返回函数,所以会这样建议把两句VirtualFreeEx注释下再试
      

  7.   

    那边vb没错是因为CloseHandle(hProcess);写在前面那样后面的VirtualFreeEx都无效了
      

  8.   


    我就用c#写过两个程序后就没碰了,现在没装.net不然可以帮你调试下,应该是可以通用的我估计是你哪里没转换好
      

  9.   

    已经试过标准的Listview控件(微软的Address Book,附件里的软件,我用的是英文版的XP),效果是一样的。也是不行。
      

  10.   

    这个问题实在有点麻烦,换个简单点的办法吧,一样可以达成我的目标:模拟按下F2到一个TreeView,这个简单吧,但我的代码也是没反应。试过给Text框送字母是OK的。代码如下:        public void SendKey(IntPtr handle, int keycode)
            {
                NativeMethods.PostMessageW(handle,NativeMethods.WM_KEYDOWN,NativeMethods.VK_F2,0);
            }调试OK,立马放分!
      

  11.   

    我怀疑你声明和转换代码时出错了,在c和vb程序中我都测试了没问题
      

  12.   

    我非常想装一个VB6自己试一下,但是的确没有,以下是声明:
    public const int NM_FIRST = 0;
    public const int NM_DBLCLK = (NM_FIRST - 3);
    public const int GWL_ID = -12;
    public const int WM_NOTIFY = 78;[System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "GetWindowLongW")]public static extern int GetWindowLongW([System.Runtime.InteropServices.InAttribute()] System.IntPtr hWnd, int nIndex);[System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "GetParent")]public static extern System.IntPtr GetParent([System.Runtime.InteropServices.InAttribute()] System.IntPtr hWnd);
    [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "GetDlgCtrlID")]public static extern int GetDlgCtrlID([System.Runtime.InteropServices.InAttribute()] System.IntPtr hWnd);用SPY++监视ListView窗口消息发送如下:
    <00396> 00010C74 S message:0x1004[用于定义:WM_USER+3076] wParam:00000000 IParam:00000000
    <00397> 00010C74 R message:0x1004[用户定义:WM_USER+3076] IResult 00000005
    <00398> 00010C74 S message:0x101F[用户定义:WM_USER+3103] wParam:00000000 IParam:00000000
    <00399> 0010C74 R message 0x101F[用户定义:WM_USER+3103] IRESULT=00010C78
      

  13.   

    麻烦陈辉兄,看看,我用的Getarent获得父句柄,并把消息发给他的原理是否正确,我对WM_NOTIFY并不太熟悉。从SPY++里面看到wparam和IParam都是空的,不知道是不是不正常,谢谢
      

  14.   

    消息要发给响应该键的窗体, 通常不会是ListView. 另外还应该再发一个键释放的消息.
      

  15.   

    问题找到了,今天特意回来报个信,顺便把分儿分了。parenthwnd,这个hwnd给弄错了,现在程序已经可以抓到MFC写的listview并实现双击了,不过对于TXPListView还是不工作,看来是不支持。没办法,已经绕路了,谢谢以上各位仁兄的热心帮助。