質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.45%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

7054閲覧

C#よりDLL(C++)を使用し、グローバルフック をおこないたい

trons

総合スコア20

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

2クリップ

投稿2018/08/20 05:12

編集2018/08/20 05:41

前提・実現したいこと

C#よりDLL(C++)を使用し、グローバルフック (HCBT_XXXX&WM_XXXX)をおこないたい

ここに質問の内容を詳しく書いてください。
C#より32Bitで作成されたDLL(C++)を呼び出す処理を作成し32Bit上では動作しますが、
64Bit上で正常に動作しません。

OS    呼出EXE  呼出先EXE DLL
32BitOS 32BitEXE  32BitEXE  32BitDLL OK
64BitOS 32BitEXE  32BitEXE  32BitDLL OK
64BitOS 64BitEXE  64BitEXE  64BitDLL NG

グローバルフックの機能としては、フック対象のEXEの移動および終了を禁止します。

フックのメッセージをSPY++でメッセージを確認したところ、
メッセージ自体は相手のプロセスが受信し、SetWindowsHookExの結果を返却後、
相手側プロセスが落ちてしまいます。

32Bit上では動作しているので、なんらかの個所が正しく64Bit化できていないのだと
思いますがわかりません。
よろしくお願いします。

### 該当のソースコード

◆◆◆DLL側(C++)1個目◆◆
(HCBTフック)

#define STRICT #include <windows.h> #define DllExport __declspec( dllexport ) void __stdcall MB(LPCTSTR str); DllExport bool CALLBACK CloseHook64(HWND); DllExport bool CALLBACK UnCloseHook64(void); #pragma data_seg("share") HHOOK hHookWnd = NULL; HINSTANCE hdll = NULL; HWND hTarget = NULL; #pragma data_seg() LRESULT CALLBACK CallWndProc(int nCode,WPARAM wParam,LPARAM lParam) { if (nCode >= 0) { switch (nCode) { case HCBT_MINMAX: case HCBT_MOVESIZE: case HCBT_DESTROYWND://ウインドウの閉じるを禁止 { if((HWND)wParam==hTarget) { return 1; break; } } } } return CallNextHookEx(hHookWnd, nCode, wParam, lParam); //次のフックを呼ぶ } // フックを組み込む bool CALLBACK CloseHook64(HWND HandleofTarget) { if(hdll == NULL) return false; hTarget = HandleofTarget; hHookWnd = SetWindowsHookEx(WH_CBT,(HOOKPROC)CallWndProc, hdll, 0); if(hHookWnd == NULL) { return false; } else { return true; } } // フックを解除する bool CALLBACK UnCloseHook64(void) { int ans = UnhookWindowsHookEx(hHookWnd); hHookWnd = NULL; if(ans == 0) { return false; } else { return true; } }

◆◆◆DLL側(C++)2個目◆◆
(WM系フック)

#define STRICT #include <windows.h> #define DllExport __declspec( dllexport ) void __stdcall MB(LPCTSTR str); #define pCW ((CWPSTRUCT*)lParam) DllExport bool CALLBACK MoveHook64(HWND); DllExport bool CALLBACK UnMoveHook64(void); LRESULT CALLBACK NewProc( HWND,UINT,WPARAM,LPARAM ); #pragma data_seg("share") HHOOK hHookWnd = NULL; HINSTANCE hdll = NULL; HWND hTarget = NULL; int g_bSubclassed = 0; UINT WM_HOOKEX = 0; WNDPROC OldProc = NULL; #pragma data_seg() LRESULT CALLBACK NewProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_CLOSE: // ウインドウあるいはアプリケーションをクローズされた case WM_DESTROY: // ウインドウが破棄された case WM_SIZE: // ウインドウのサイズが変更(マウス操作) case WM_MOVE: // ウインドウが移動した { return 1; break; } case WM_MOVING: // リサイズ中にウィンドウに送られる(マウス操作) case WM_ENTERSIZEMOVE: // ウィンドウが移動・サイズ変更した(マウス操作) case WM_EXITSIZEMOVE: // ウィンドウの移動・サイズ変更の処理が終了したとき(マウス操作) { return 1; break; } case WM_SYSCOMMAND: { //右上のボタン系 switch (wParam & 0xFFF0) { case SC_CLOSE: { return 1; break; } case SC_MOVE: { return 1; break; } case SC_MAXIMIZE: { return 1; break; } case SC_MINIMIZE: { return 1; break; } case SC_RESTORE: { return 1; break; } case SC_SIZE: { return 1; break; } } } } return CallWindowProc(OldProc, hwnd, message, wParam, lParam); } LRESULT CALLBACK HookProc(int code, WPARAM wParam, LPARAM lParam) { if( (pCW->message == WM_HOOKEX) && pCW->lParam ) { ::UnhookWindowsHookEx( hHookWnd ); if( g_bSubclassed ) goto END; TCHAR lib_name[MAX_PATH]; ::GetModuleFileName( hdll, lib_name, MAX_PATH ); if( !::LoadLibrary( lib_name ) ) goto END; //32Bit //OldProc = (WNDPROC)(LONG_PTR)::SetWindowLongPtr( hTarget, GWL_WNDPROC, (__int3264)(LONG_PTR)NewProc ); //64Bit OldProc = (WNDPROC)::SetWindowLongPtr(hTarget, GWLP_WNDPROC, (LONG)NewProc); if( OldProc==NULL )::FreeLibrary( hdll ); else { ::MessageBeep(MB_OK); g_bSubclassed = true; } } else if( pCW->message == WM_HOOKEX ) { ::UnhookWindowsHookEx( hHookWnd ); //32 //if( !SetWindowLongPtr( hTarget, GWL_WNDPROC, (__int3264)(LONG_PTR)OldProc ) ) //64Bit if( !SetWindowLongPtr( hTarget, GWLP_WNDPROC, (LONG)OldProc ) ) goto END; ::FreeLibrary( hdll ); ::MessageBeep(MB_OK); g_bSubclassed = false; } END: return ::CallNextHookEx(hHookWnd, code, wParam, lParam); } // フックを組み込む bool CALLBACK MoveHook64(HWND HandleofTarget) { if(hdll == NULL) return false; hTarget = HandleofTarget; hHookWnd = SetWindowsHookEx( WH_CALLWNDPROC,(HOOKPROC)HookProc, hdll, GetWindowThreadProcessId(HandleofTarget,NULL) ); if( hHookWnd==NULL ) { return false; } else { SendMessage( HandleofTarget,WM_HOOKEX,0,1 ); return true; } } // フックを解除する bool CALLBACK UnMoveHook64(void) { hHookWnd = SetWindowsHookEx( WH_CALLWNDPROC,(HOOKPROC)HookProc, hdll, GetWindowThreadProcessId(hTarget,NULL) ); if( hHookWnd == NULL ) { return false; } else { hHookWnd = NULL; SendMessage( hTarget,WM_HOOKEX,0,0 ); return (g_bSubclassed == NULL); } }

◆◆◆EXE側(C#)◆◆

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; using System.Windows.Forms; namespace Hook64 { class Program { [DllImport("CloseHook64.dll")] private extern static bool CloseHook64(IntPtr hWnd); [DllImport("MoveHook64.dll")] private extern static bool MoveHook64(IntPtr hWnd); static void Main(string[] args) { if (args.Length == 0) { Environment.ExitCode = 100; return; } else if (args.Length == 1) { try { //32 //IntPtr handle = (IntPtr)Convert.ToInt32(args[0]); //64 Int64 val = 0; if (Int64.TryParse(args[0], out val)) { IntPtr handle = (IntPtr)val; if (!CloseHook64(handle)) { Environment.ExitCode = 101; return; } if (!MoveHook64(handle)) { Environment.ExitCode = 102; return; } } } catch (Exception Ex) { Environment.ExitCode = 255; MessageBox.Show(Ex.Message); return; } } else if (args.Length > 1) { Environment.ExitCode = 104; return; } //処理成功 Environment.ExitCode = 0; } } }

補足情報(FW/ツールのバージョンなど)

Microsoft Visual C# 2010 01018-532-2002102-70943 .NET3.5
Microsoft Visual C++ 2010 01018-532-2002102-70943

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

試してませんが

C++

1 //64Bit 2 OldProc = (WNDPROC)::SetWindowLongPtr(hTarget, GWLP_WNDPROC, (LONG)NewProc);

C++

1 //64Bit 2 if( !SetWindowLongPtr( hTarget, GWLP_WNDPROC, (LONG)OldProc ) ) 3 goto END;

で、32ビット(LONG)にキャストしているのが原因と思います。キャストが不要なようにサブクラス化は新しい API を使用するのをお勧めします。
http://eternalwindows.jp/control/controlbase/controlbase06.html

潜在的な問題として以下のグローバル変数は.sharedセクションに入れるべきではありません。

C++

1int g_bSubclassed = 0; 2WNDPROC OldProc = NULL;

これらはプロセス内でローカルになるべき変数で、プロセス間で共有する必要はありません。現状では1プロセスしかフック対象としていないので、問題になることはないと思います。

また、提示されているコードでは WM_HOOKEX が初期化されていないように見えます。実際のコードでは RegisterWindowMessage 等で初期化されているのだとは思います。今の値は WM_NULL と同じですので、これもあまり問題になることはないと思います。

投稿2018/08/20 11:21

atata0319

総合スコア881

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

trons

2018/08/21 01:11

ご指摘いただいた個所を修正したところ、正常に64Bit環境でも動作しました。 ありがとうございました。
guest

0

質問へのコメントで書いたように、NG なのは以下だと理解して。

64BitOS 64BitEXE  64BitEXE  32BitDLL

以下の記事の Step 9 の下の方の図の「例 3.」と同様になっているのではないですか?

Part 2. .NET Framework 2.0 アプリケーションの 64 ビット対応
https://blogs.msdn.microsoft.com/nakama/2008/11/05/part-2-net-framework-2-0-64/

であれば、「例 4.」にあるようにする、即ち質問者さんが書いた、

32BitOS 32BitEXE  32BitEXE  32BitDLL OK
64BitOS 32BitEXE  32BitEXE  32BitDLL OK

のようにする、即ち x86 で EXE をコンパイルするということになると思うのですが。

投稿2018/08/20 06:28

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

32bitのdllは64bitで動作しません。

投稿2018/08/20 05:32

tekka

総合スコア514

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

trons

2018/08/20 05:42 編集

回答ありがとうございます。 本文をミスしていました。 (本文を修正させていただきました。) 誤 64BitOS 64BitEXE  64BitEXE  64BitDLL OK 正 64BitOS 64BitEXE  64BitEXE  64BitDLL NG 記入ミスをした、部分の64Bitでの動作が正常に動かず困っております。 基本的には32BitDLL呼び出し部分等の型を64Bit化すればよいと考えているのですが、うまく動作しません。 よろしくお願いします。
退会済みユーザー

退会済みユーザー

2018/08/20 06:15

> 誤 64BitOS 64BitEXE  64BitEXE  64BitDLL OK > 正 64BitOS 64BitEXE  64BitEXE  64BitDLL NG また間違っているのでは? 以下では? 誤 64BitOS 64BitEXE  64BitEXE  64BitDLL OK 正 64BitOS 64BitEXE  64BitEXE  32BitDLL NG
trons

2018/08/20 06:47 編集

OS    呼出EXE  呼出先EXE DLL 「64BitOS 64BitEXE  64BitEXE  32BitDLL NG」 呼び出しEXEとDLLのコンパイルビットが不一致を起こしているためNGになると思います。 動作しないのは、64BitOS上で64BitEXEから64BitDLLを使用し、64BitのEXEにHookした場合です。 32BitOnlyの場合とWoWを使用した場合の64BitOS上での32BitEXEへのHookは動作しています。 よろしくお願いします。
退会済みユーザー

退会済みユーザー

2018/08/20 09:12 編集

私の回答と、回答に貼ったリンク先の記事を読んでいただいているでしょうか? Hook とは何を言っているか理解できていませんが、Step 9 の下の方の図の「例 3.」と同様になっているとすると、動かないのは間違いないですけど。
tekka

2018/08/20 15:27

ちょっと再現取るために環境整えたいと思います。先に解決されたらすいません。
tekka

2018/08/20 15:31 編集

削除
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.45%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問