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

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

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

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

Q&A

解決済

2回答

2115閲覧

C#でのウィンドウ名取得について EnumWindows

yuujiMotoki

総合スコア90

C#

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

0グッド

0クリップ

投稿2020/04/29 09:02

編集2020/04/29 10:50

#内容
C#でウィンドウのハンドルを取得する検討しています。

参考ソース
EnumWindows

C#

1using System; 2using System.Runtime.InteropServices; 3 4public delegate bool CallBack(int hwnd, int lParam); 5 6public class EnumReportApp 7{ 8 [DllImport("user32")] 9 public static extern int EnumWindows(CallBack x, int y); 10 11 public static void Main() 12 { 13 CallBack myCallBack = new CallBack(EnumReportApp.Report); 14 EnumWindows(myCallBack, 0); 15 } 16 17 public static bool Report(int hwnd, int lParam) 18 { 19 Console.Write("Window handle is "); 20 Console.WriteLine(hwnd); 21 return true; 22 } 23}

リストを見ると、コールバック関数を使っているのですが、
EnumWindows関数の戻り値は、常にBOOLしか戻ってこない状態で、
取得したいハンドル名を、WINDOWSコンソールに吐き出されています。

#知りたいこと

最終的にはDLLとして、配列変数にして戻したいと思っています。

方法としては

1)コンソールの出力をテキストにして戻す
→ DLLを呼ぶ側に解読するソースをつけないと行けないので、不細工です。

2)メインの外にグローバル配列変数を作る
→ そもそも関数の戻り値として、DLLの呼び出し側に返信できるのか疑問。

C#の使い方としては、もっとスマートな方法は無いものでしょうか?

他の言語では、
サンプル: "列挙(コールバック)時の情報を列挙後へ渡す"
の例がありましたが、C#のソースがあれば紹介いただきたいです。
リンク内容

#現在のコード

もちろん、呼び出しのエントリポイントの外にクラス宣言があり
このまま走らせても、「インデックスが配列の境界外」というエラーになってしまいます。

VBA

1Sub Vba() 2 3Set DLL = New ExcelVbaExt.WindowWhnd 4Dim com As Variant 5Set com = DLL.WindowTitleList 6c = com.Interface 7 8End Sub 9

C#

1using System; 2using System.Runtime.InteropServices; 3using System.Text; 4 5namespace ExcelVbaExt 6{ 7 [ComVisible(true)] 8 [ClassInterface(ClassInterfaceType.AutoDual)] 9 public class InnerClass 10 { 11 public int WHnd; 12 public string APPName; 13 public int Left; 14 public int Top; 15 public int Right; 16 public int Bottom; 17 } 18 19 [ComVisible(true)] 20 [ClassInterface(ClassInterfaceType.AutoDual)] 21 public class ClassApp 22 { 23 public InnerClass[] Interface; 24 } 25 26 [ComVisible(true)] 27 [InterfaceType(ComInterfaceType.InterfaceIsDual)] 28 public interface IWindowWhnd 29 { 30 ClassApp WindowTitleList(); 31 } 32 33 [ClassInterface(ClassInterfaceType.None)] 34 public class WindowWhnd : IWindowWhnd 35 { 36 public static ClassApp _hWndList = new ClassApp(); 37 public static int count; 38 39 [DllImport("user32.dll")] 40 private static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect); 41 42 [StructLayout(LayoutKind.Sequential)] 43 private struct RECT 44 { 45 public int left; 46 public int top; 47 public int right; 48 public int bottom; 49 } 50 51 [DllImport("user32.dll")] 52 [return: MarshalAs(UnmanagedType.Bool)] 53 private extern static bool EnumWindows(EnumWindowsDelegate lpEnumFunc, IntPtr lparam); 54 55 [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 56 private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); 57 58 [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 59 private static extern int GetWindowTextLength(IntPtr hWnd); 60 61 [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 62 private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); 63 64 private delegate bool EnumWindowsDelegate(IntPtr hWnd, IntPtr lparam); 65 66 public ClassApp WindowTitleList() 67 { 68 count = 1; 69 _hWndList = new ClassApp(); 70 _hWndList.Interface = new InnerClass[1]; 71 72 EnumWindows(new EnumWindowsDelegate(EnumWindowCallBack), IntPtr.Zero); 73 74 return _hWndList; 75 } 76 77 private static bool EnumWindowCallBack(IntPtr hWnd, IntPtr lparam) 78 { 79 int textLen = GetWindowTextLength(hWnd); 80 if (0 < textLen) 81 { 82 StringBuilder tsb = new StringBuilder(textLen + 1); 83 GetWindowText(hWnd, tsb, tsb.Capacity); 84 85 RECT rect; 86 bool flag = GetWindowRect(hWnd, out rect); 87 88 count += 1; 89 Array.Resize(ref _hWndList.Interface, count); 90 _hWndList.Interface[count] = new InnerClass(); 91 _hWndList.Interface[count].WHnd = (int)hWnd; 92 _hWndList.Interface[count].APPName = tsb.ToString(); 93 _hWndList.Interface[count].Left = rect.left; 94 _hWndList.Interface[count].Top = rect.top; 95 _hWndList.Interface[count].Right = rect.right; 96 _hWndList.Interface[count].Bottom = rect.bottom; 97 } 98 return true; 99 } 100 } 101}

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

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

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

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

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

Zuishin

2020/04/29 09:05

質問内容はともかく、最近増えてきた WPF アプリや UWP アプリはコントロールにウィンドウを使わないので、ハンドルを取得してどうこうという方法が使えるかどうかの検討からしてください。
Zuishin

2020/04/29 09:05

あ、質問者見てなかった。
guest

回答2

0

そのテのDLLを作る場合は、呼ぶ側でバッファを用意しておいてバッファサイズとアドレスを引数にしてDLLを呼び出し、DLL側ではそのバッファに結果を格納し、実際に消費したサイズとともに返すという形式を取りますね

投稿2020/04/29 10:33

y_waiwai

総合スコア88042

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

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

yuujiMotoki

2020/04/29 10:56

ありがとうございます。 バッファと言う方法、また勉強しなおしたいと思います。
guest

0

自己解決

RESIZEの配列が少なかったのが、エラー原因でした。
(いまの所は、この方法で何とか切り抜けれそうです)

Array.Resize(ref _hWndList.Interface, count +1 );

投稿2020/04/29 10:55

編集2020/04/29 12:32
yuujiMotoki

総合スコア90

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問