Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9304

C#備忘録 - Windowハンドル関連の逆引きリファレンス的なやつ(主にWin32API)

$
0
0

はじめに

Windowsで他アプリと何かしらやりとりしたいときは、大抵ウィンドウハンドルが必要になる。
いちいち調べなおすのは面倒なので、使ったことのあるAPIとかメソッドをまとめてみた。

Windows APIの使用に際して

C# では、ウィンドウハンドルの型はIntPtrとなる。
IntPtrのサイズは32bit/64bit環境に依存する1ので、型をint(32bit)とかと間違えないようにすること。

APIについては、とりあえず[DllImport("user32.dll", CharSet = CharSet.Auto)]つけておけば動くはず。(テキトウ・・)

1. ウィンドウハンドルを取得する

No概要APIまたはメソッド
(Microsoftへリンク)
使用例へリンク
1-1スクリーン座標から取得(API) WindowFromPointhttps://qiita.com/kob58im/items/3587d8e595e655e9391d
1-2全体から検索・列挙(API) FindWindowExhttps://qiita.com/kob58im/items/d5828e6cf5416d776549
1-3親を取得(API) GetAncestorhttps://qiita.com/kob58im/items/3587d8e595e655e9391d
1-4トップレベルウィンドウを列挙しつつ処理する(API) EnumWindowshttps://qiita.com/kob58im/items/3587d8e595e655e9391d
1-5子ウィンドウを列挙しつつ処理する★(API) EnumChildWindowshttps://qiita.com/kob58im/items/3587d8e595e655e9391d
1-Aコントロールから取得Control.Handlehttps://qiita.com/kob58im/items/4bd061df83212a723be7

★・・・ 子のウィンドウハンドルはWin32APIでは取得できないケースがあるようなので注意。

2. ハンドルを使って何かする

No概要APIまたはメソッド
(Microsoftへリンク)
使用例へリンク
2-1クラス名を得る(API) GetClassNamehttps://qiita.com/kob58im/items/3587d8e595e655e9391d
2-2タイトルを得る(API) GetWindowTexthttps://qiita.com/kob58im/items/3587d8e595e655e9391d
2-3プロセスIDを得る(API) GetWindowThreadProcessIdhttps://qiita.com/kob58im/items/d5828e6cf5416d776549
2-4座標やサイズなどの情報を得る(API) GetWindowInfohttps://qiita.com/kob58im/items/3587d8e595e655e9391d
2-5メッセージを送る(API) SendMessagehttps://qiita.com/kob58im/items/4bd061df83212a723be7
2-AUI Automationを使うAutomationElement.FromHandlehttps://qiita.com/kob58im/items/3587d8e595e655e9391d

抜粋

※抜粋しているので、そのままでは動きません。使用例の記事を参照ください。
※この記事でのDllImportの属性指定や、メソッド宣言のパラメータ指定は、あくまで例であり、これを推奨するものではありません。

1-1. WindowFromPoint

// 定義部staticclassNativeMethods{[StructLayout(LayoutKind.Sequential)]publicstructPOINT{publicintx;publicinty;}[DllImport("user32.dll",SetLastError=true)]publicstaticexternIntPtrWindowFromPoint(POINTpoint);}// 使用部voidhoge(){varp=newPOINT();NativeMethods.GetCursorPos(outp);IntPtrhWnd=NativeMethods.WindowFromPoint(p);}

1-2. FindWindowEx

// 定義部staticclassNativeMethods{[DllImport("user32.dll",SetLastError=true,CharSet=CharSet.Auto)]publicstaticexternIntPtrFindWindowEx(IntPtrparentWnd,IntPtrpreviousWnd,stringclassName,stringwindowText);}// 使用部voidhoge(){IntPtrhWnd=IntPtr.Zero;while(IntPtr.Zero!=(hWnd=NativeMethods.FindWindowEx(IntPtr.Zero,hWnd,クラス名文字列,ウィンドウ名文字列))){// クラス名・ウィンドウ名に一致したウィンドウに対する処理をここに書く}}

1-3. GetAncestor

// 定義部staticclassNativeMethods{[DllImport("user32.dll",SetLastError=true)]publicstaticexternIntPtrGetAncestor(IntPtrhWnd,uintgaFlags);publicconstuintGA_PARENT=1;publicconstuintGA_ROOT=2;publicconstuintGA_ROOTOWNER=3;}// 使用部voidhoge(IntPtrhWnd){IntPtrhWndRoot=IntPtr.Zero;hWndRoot=NativeMethods.GetAncestor(hWnd,NativeMethods.GA_ROOT);}

1-4. EnumWindows

// 定義部staticclassNativeMethods{publicdelegateboolEnumWindowsDelegate(IntPtrhWnd,IntPtrlparam);[DllImport("user32.dll")][return:MarshalAs(UnmanagedType.Bool)]publicexternstaticboolEnumWindows(EnumWindowsDelegatelpEnumFunc,IntPtrlparam);}// 使用部boolEnumWindowCallBack(IntPtrhWnd,IntPtrlparam){// hWndを使った処理をここに書く// trueを返すことで、すべてのウィンドウを列挙するreturntrue;}voidhoge(){NativeMethods.EnumWindows(EnumWindowCallBack,IntPtr.Zero);}

FindWindowExのほうが使いやすいかも

1-5. EnumChildWindows

// 定義部staticclassNativeMethods{publicdelegateboolEnumWindowsDelegate(IntPtrhWnd,IntPtrlparam);[DllImport("user32.dll")][return:MarshalAs(UnmanagedType.Bool)]publicstaticexternboolEnumChildWindows(IntPtrhandle,EnumWindowsDelegateenumProc,IntPtrlParam);}// 使用部boolEnumChildWindowCallBack(IntPtrhWnd,IntPtrlparam){// 処理...// hWndの子ウィンドウを探すNativeMethods.EnumChildWindows(hWnd,EnumChildWindowCallBack,IntPtr.Zero);returntrue;// すべての兄弟ウィンドウを列挙する}voidhoge(){NativeMethods.EnumChildWindows(ルートとなるウィンドウのハンドル,EnumChildWindowCallBack,IntPtr.Zero);}

FindWindowExのほうが使いやすいかも

★子のウィンドウハンドルはWin32APIでは取得できないケースがあるようなので注意。

2-1. GetClassName

// 定義部staticclassNativeMethods{[DllImport("user32.dll",CharSet=CharSet.Auto,SetLastError=true)]publicstaticexternintGetClassName(IntPtrhWnd,StringBuilderlpClassName,intnMaxCount);}// 使用部publicstaticstringMyGetClassName(IntPtrhWnd,outintretCode){StringBuildercsb=newStringBuilder(MaxTextLength);retCode=NativeMethods.GetClassName(hWnd,csb,csb.Capacity);if(retCode>0){returncsb.ToString();}else{returnstring.Empty;}}

2-2. GetWindowText

// 定義部staticclassNativeMethods{[DllImport("user32.dll",CharSet=CharSet.Auto,SetLastError=true)]publicstaticexternintGetWindowTextLength(IntPtrhWnd);[DllImport("user32.dll",CharSet=CharSet.Auto,SetLastError=true)]publicstaticexternintGetWindowText(IntPtrhWnd,StringBuilderlpString,intnMaxCount);}// 使用部publicstaticstringMyGetWindowText(IntPtrhWnd,outintretCode){//ウィンドウのタイトルを取得するStringBuildertsb=newStringBuilder(MaxTextLength);retCode=NativeMethods.GetWindowText(hWnd,tsb,tsb.Capacity);if(retCode>0){// 成功すると長さが返るreturntsb.ToString();}else{// 0の場合はエラーの可能性があるreturnstring.Empty;}}

2-3. GetWindowThreadProcessId

// 定義部staticclassNativeMethods{[DllImport("user32.dll",SetLastError=true)]publicstaticexternintGetWindowThreadProcessId(IntPtrhWnd,outintlpdwProcessId);}// 使用部voidhoge(){intpid;NativeMethods.GetWindowThreadProcessId(hWnd,outpid);Processp=Process.GetProcessById(pid);}

2-4. GetWindowInfo

// 定義部staticclassNativeMethods{[StructLayout(LayoutKind.Sequential)]publicstructWINDOWINFO{publicintcbSize;publicRECTrcWindow;publicRECTrcClient;publicintdwStyle;publicintdwExStyle;publicintdwWindowStatus;publicuintcxWindowBorders;publicuintcyWindowBorders;publicshortatomWindowType;publicshortwCreatorVersion;}[StructLayout(LayoutKind.Sequential)]publicstructRECT{publicintleft;publicinttop;publicintright;publicintbottom;}[DllImport("user32.dll",SetLastError=true)]publicstaticexternintGetWindowInfo(IntPtrhwnd,refWINDOWINFOpwi);}// 使用部publicstaticWINDOWINFOMyGetWindowInfo(IntPtrhWnd,outintretCode){varwi=newWINDOWINFO();wi.cbSize=Marshal.SizeOf(wi);retCode=NativeMethods.GetWindowInfo(hWnd,refwi);returnwi;}

2-5. SendMessage

本質と関係ないとこで解放処理が漏れてます。そのうち見直します。(というか例を変えたい・・)

// 定義部staticclassNativeMethods{[DllImport("user32")]publicexternstaticIntPtrSendMessage(IntPtrhWnd,intMsg,IntPtrwParam,IntPtrlParam);}// 使用部staticIntPtrSetTabStop(TextBoxBaset,inttabSize){int[]tabarray=newint[]{tabSize*4};intwparam=tabarray.Length;IntPtrparray=Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(int))*tabarray.Length);Marshal.Copy(tabarray,0,parray,tabarray.Length);IntPtrret=SendMessage(t.Handle,EM_SETTABSTOPS,newIntPtr(wparam),parray);// 解放処理が漏れている。 Marshal.FreeCoTaskMem とかで解放してください。returnret;}

脱線編 - WinAPIまわりのメモリ確保と解放について

メモリの解放は完璧にしようとすると奥が深そう(参考サイト参照)であるが、趣味の範疇ならMarshal.AllocCoTaskMem, Marshal.FreeCoTaskMem確保;try{処理;}finally{解放;}で十分かと。

参考サイト


  1. 正確にはコンパイル時のオプション指定による。 


Viewing all articles
Browse latest Browse all 9304

Trending Articles