DOBON.NET DOBON.NETプログラミング掲示板過去ログ

WindowsAPIで異プロセス間のやりとり(64bitOS)

環境/言語:[Windows7(64bit)、C#]
分類:[ASP.NET]

昨年こちらの掲示板で質問をして、解決までたどり着けたものです。
アプリケーションのツリービューのノードタイトルを取得するプログラムなのですで、メモリを介してデータの受け渡しをしています。
32bitPCで動作するプログラムを64bitPCで実行したところ
SendMessageの返り値が0となってしまうようになりました。(正常終了の場合は1が変えります)
コンパイルはAnyCPUを指定しています。
64bitになってから IntPtrのサイズが4→8になる等の変更がありサイズ指定されている場合は注意する 等の記事を読んだのですが、プログラム内に直接数字を指定しているような個所はありません。

どうにも困り果てております。
コードは以下の通りなのですが、64bitで動作させるに当たり まずい要素がありましたらご指摘いただけると大変うれしく思います。

どうぞよろしくお願いいたします。
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace VaultPanelControl
{
    public class VaultPNCTL
    {
        [StructLayout(LayoutKind.Sequential)]
        public 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;
            public int iIntegral;
            public uint uStateEx;
            public IntPtr hwnd;
            public int iExpandedImage;
            public int iReserved;
        }

        [DllImport("User32.dll", CharSet = CharSet.Unicode)]
        static extern IntPtr FindWindow(string lpszClass, string lpszWindow);
        [DllImport("user32.dll")]
        static extern IntPtr FindWindowEx(IntPtr hWnd, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
        [DllImport("User32.dll", CharSet = CharSet.Unicode)]
        public static extern IntPtr SendMessage(IntPtr hWnd, Int32 Msg, IntPtr wParam, IntPtr lParam);
        [DllImport("user32.dll")]
        public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
        [DllImport("kernel32.dll")]
        public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
        [DllImport("kernel32.dll")]
        public static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint dwFreeType);
        [DllImport("kernel32.dll")]
        public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, int nSize, ref uint lpNumberOfBytesRead);
        [DllImport("kernel32.dll")]
        public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, int nSize, ref uint lpNumberOfBytesWritten);
        [DllImport("kernel32.dll")]
        public static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CloseHandle(IntPtr hObject);
        [DllImport("kernel32.dll")]
        static extern void MoveMemory(IntPtr dst, IntPtr src, int size);

        private static uint PROCESS_VM_OPERATION = 0x00000008;
        private static uint PROCESS_VM_READ = 0x00000010;
        private static uint PROCESS_VM_WRITE = 0x00000020;
        private static uint MEM_RESERVE = 0x2000;
        private static uint MEM_COMMIT = 0x1000;
        private static uint MEM_RELEASE = 0x8000;
        private static uint PAGE_READWRITE = 0x0040;

        //TreeViewのメッセージコード
        public static int TVM_EXPAND = 0x1102; //アイテムを開く・閉じる 
        public static int TV_FIRST = 0x1100;
        public static int TVM_GETITEM = TV_FIRST + 62; 
        public static int TVM_GETNEXTITEM = 0x110A; //指定されたアイテムを取得 

        //TVM_GETNEXTITEM に指定する wParam = flag
        public static int TVGN_ROOT = 0x0000; //ツリービューのルート(最も上の階層)のアイテムを取得します。
        public static int TVGN_NEXT = 0x0001; //指定されたアイテムの同じグループ内の次のアイテムを取得します。
        public static int TVGN_CARET = 0x0009; //現在選択されているアイテムを取得します。

        //TVM_EXPANDに指定するwParam = flag
        public static int TVE_EXPAND = 0x1102; //子アイテムのツリーを開きます

        //TVITEMEXのmask 
        public static uint TVIF_TEXT = 0x0001; //pszText, cchTextMax

        static void Main(string[] args)
        {
            uint pid = 0x1234;                       // 相手アプリケーションのプロセスID(直接指定)
            IntPtr treewindow = (IntPtr)0x20834;    // ツリーウィンドウのハンドル(直接指定)
            IntPtr hwindow = (IntPtr)0x106E6;       //親ウィンドウハンドル直接指定

            uint result = GetWindowThreadProcessId(hwindow, out pid);
            Process p = Process.GetProcessById((int)pid);

            //カレントのハンドル
            IntPtr lItemWnd = SendMessage(treewindow, TVM_GETNEXTITEM, (IntPtr)TVGN_CARET, IntPtr.Zero);

            //ツリーを開く
            SendMessage(treewindow, TVM_EXPAND, (IntPtr)TVE_EXPAND, lItemWnd);

            //ノードの名称を取得******************************************
            //相手プロセスのオープン

            IntPtr pProcessH = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, false, pid);
            if (pProcessH.Equals(IntPtr.Zero))
            {
                return;
            }
            try
            {
                //pszText設定用の文字列領域確保
                int MAX_STR = 260;

                //TVITEM構造体を宣言 初期化
                TVITEM tvitem = new TVITEM();

                int tvitemSize = Marshal.SizeOf(tvitem);
                int dwSize = tvitemSize + MAX_STR;

                //自プロセスの共有メモリ確保
                //TVITEM格納分
                IntPtr pLocalShared = Marshal.AllocHGlobal(tvitemSize);
                try
                {
                    //タイトルバッファ格納分
                    IntPtr pLocalShared_Buf = Marshal.AllocCoTaskMem(MAX_STR);
                    try
                    {
                        //相手側プロセスの共有メモリ確保
                        //TVITEM格納分
                        IntPtr pSysShared = VirtualAllocEx(pProcessH, IntPtr.Zero, (uint)tvitemSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
                        if (pSysShared.Equals(IntPtr.Zero))
                        {
                            return;
                        }
                        try
                        {
                            //タイトルバッファ格納分
                            IntPtr pSysShared_Buf = VirtualAllocEx(pProcessH, IntPtr.Zero, (uint)MAX_STR, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
                            if (pSysShared_Buf.Equals(IntPtr.Zero))
                            {
                                return;
                            }
                            try
                            {
                                //構造体の初期化
                                tvitem.mask = TVIF_TEXT;
                                tvitem.hItem = lItemWnd;
                                tvitem.pszText = pSysShared_Buf;
                                tvitem.cchTextMax = MAX_STR;

                                //構造体のポインタを確保したアドレスに移動
                                Marshal.StructureToPtr(tvitem, pLocalShared, false);

                                //相手プロセス内にTVITEM構造体をコピー
                                uint retWrite = 0;
                                bool bRet = false;
                                bRet = WriteProcessMemory(pProcessH, pSysShared, pLocalShared, tvitemSize, ref retWrite);
                                if (bRet == false)
                                {
                                    return;
                                }

                                //SendMessage発行
                                IntPtr pRet;
                                pRet = SendMessage(treewindow, TVM_GETITEM, IntPtr.Zero, pSysShared);
                                if (pRet == IntPtr.Zero)
                                {
                                    return;
                                }

                                //共有メモリから情報取得
                                uint retRead = 0;
                                bRet = ReadProcessMemory(pProcessH, pSysShared_Buf, pLocalShared_Buf, MAX_STR, ref retRead);
                                if (bRet == false)
                                {
                                    return;
                                }

                                MessageBox.Show(Marshal.PtrToStringUni(pLocalShared_Buf));
                            }
                            finally
                            {
                                //相手プロセス内の共有メモリを解放する
                                VirtualFreeEx(pProcessH, pSysShared_Buf, (uint)dwSize, MEM_RELEASE);
                            }
                        }
                        finally
                        {
                            //相手プロセス内の共有メモリを解放する
                            VirtualFreeEx(pProcessH, pSysShared, (uint)dwSize, MEM_RELEASE);
                        }
                    }
                    finally
                    {
                        //自プロセス内共有メモリを解放する
                        Marshal.FreeHGlobal(pLocalShared_Buf);
                    }
                }
                finally
                {
                    //自プロセス内共有メモリを解放する
                    Marshal.FreeHGlobal(pLocalShared);
                }
            }
            finally
            {
                //相手プロセスのクローズ
                CloseHandle(pProcessH);
            }
        }
    }
}
ソースコード中にSendMessageが複数存在しているので、どこで転けているのか分かりませんが。
プロジェクトプロパティのプラットフォームターゲットを、目的のプロセスと同じものに明示してやれば良いんじゃないですかね。
ご回答いただき、どうも有難うございました。
エラー個所を書き忘れてしまいました。大変申し訳ありません。
下記コードのところです。

//SendMessage発行
IntPtr pRet;
pRet = SendMessage(treewindow, TVM_GETITEM, IntPtr.Zero, pSysShared);

↑このpRetの返り値が0(エラー)になっていました。

アドバイスいただいたように、プラットホームターゲットをx86にしてみたら
うまくいきました!!
自分のPCが64bitだったので、てっきりx64を指定かAnyCPUだと思ってやってみたのですがうまくいかず、
メッセージを取得しようとしている相手先アプリケーションが32bitの場合は
プラットホームターゲットがx86なのですね。当たり前ですよね・・・

気づかずにお恥ずかしい限りです。

このたびはどうも有難うございました。とても助かりました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板