• ベストアンサー

EnumWindowsのコールバック関数

現在起動している、ウィンドのタイトルを取得したくて1週間前からプログラミングを始めました。 web上のサンプルコードを切った貼ったして、なんとかウィンドタイトルの取得まで漕ぎ着けたのですが、 EnumWindowsのコールバック関数で取得した文字列を呼び出し側で使うにはどうすればですか? ウィンドとか要らないですただ、取得した文字列をメッセージボックス に表示して、クリップボードに貼り付けたいだけです。

質問者が選んだベストアンサー

  • ベストアンサー
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.4

#include <stdio.h> #include <Windows.h> // 定数 #define SW_TITLE (1) // タイトルバーの取得 #define SW_CLASS (2) // クラス名の取得 // 独自の構造体を宣言 typedef struct enum_param_t {  LPTSTR lpBuff;   // 先頭ポインタ位置  LPTSTR lpTail;   // 現在ポインタ位置  LPTSTR lpStop;   // 最終ポインタ位置  UINT swOption;  // 汎用オプション値 } enum_param_t; // ウインドウのふるいにかける処理 BOOL MyIsTopWindow( HWND hWnd, LPTSTR lpTitle, LPTSTR lpClass ) {  if ( IsWindowVisible(hWnd) ){        // 可視状態か   if ( GetWindow(hWnd,GW_OWNER) == NULL ){    // トップレベルウィンドウか    if ( lstrlen(lpTitle) > 0 ){      // キャプションを持っているか     if ( lstrcmp(lpClass,TEXT("Progman")) != 0 ){ // シェルでないか      return TRUE;     }    }   }  }  return FALSE; } // ちょっとだけ書き換えました。 BOOL CALLBACK EnumWndProc( HWND hWnd, LPARAM lParam ) {  enum_param_t *p = (enum_param_t *)lParam;  // ここで構造体を受け取る  TCHAR szWindowName[ 128 ];  TCHAR szClassName[ 128 ];    //ウィンドウテキストの取得  GetWindowText( hWnd, szWindowName, sizeof(szWindowName) );  //ウィンドウクラス名の取得  GetClassName( hWnd, szClassName, sizeof(szClassName) );    // 取得した情報を文字列に取得  if ( MyIsTopWindow(hWnd,szWindowName,szClassName) ){   LPTSTR lpBuff;      // ここで swOption で処理分岐   switch ( p->swOption ){    case SW_TITLE: lpBuff = szWindowName; break; // タイトルバーの取得    case SW_CLASS: lpBuff = szClassName; break; // クラス名の取得    default: return TRUE;   }   // バッファの残り容量をチェック   if ( (p->lpTail + lstrlen(lpBuff) + 1) < p->lpStop ){    p->lpTail += wsprintf( p->lpTail, TEXT("%s\n"), lpBuff );   }  }  return TRUE; } // 文字列をクリップボードにコピー BOOL MyClipboardCopy( HWND hWnd, LPCTSTR lpText ) {  HGLOBAL hMem; // 設定用のメモリ変数  LPTSTR lpBuff; // 複写用のポインタ  DWORD dwSize; // 複写元の長さ    // クリップボードのデータ内容  dwSize = (lstrlen(lpText) + 1); // '\0' 文字分を加算    // データ内容のメモリを確保  if ( (hMem = GlobalAlloc((GHND|GMEM_SHARE),dwSize)) != NULL ){   if ( (lpBuff = (LPTSTR)GlobalLock(hMem)) != NULL ){    // ここでテキストデータを lpBuff にコピー    lstrcpy( lpBuff, lpText );    GlobalUnlock( hMem );        // クリップボードにデータを設定    if ( OpenClipboard(hWnd) ){     EmptyClipboard();     SetClipboardData( CF_TEXT, hMem );     CloseClipboard();     return TRUE;    }   }   GlobalFree( hMem ); // ロックできない時は解放  }  return FALSE; } // メイン関数 int main( void ) {  TCHAR szText[ 32 * 1024 ]; // タイトルバー(32 KB)  enum_param_t prm; // 構造体を宣言    // 構造体の初期化  prm.lpBuff  = szText;  prm.lpTail  = szText; // ここが書き込み位置  prm.lpStop  = szText + sizeof( szText );  prm.swOption = SW_TITLE; // 機能拡張用のオプション(自由に値をセット)    // ウインドウの列挙開始  EnumWindows( EnumWndProc, (LPARAM)&prm );    // 特に必要がないなら削除(printf() でも文字列として表示可能)  MessageBox( NULL, szText, "起動中のWindow", MB_OK );    // クリップボードにコピー  if ( !MyClipboardCopy(NULL,szText) ){   printf( "クリップボードにコピーできませんでした。\n" );  }  return 0; } 以上。

batumaru53
質問者

お礼

すばらしいです。 動作は、希望通りです。 まだ理解するまでに時間が掛かりそうですが、がんばります。 本当にありがとうございました。

すると、全ての回答が全文表示されます。

その他の回答 (3)

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.3

★コールバック関数の lParam を利用すれば良い。 >グローバル変数では無くしたいのですが、コールバック関数で取得した >szTextをどうすれば、持ってこれるのか?持ってこれないのか?  ↑  コールバック関数には第2引数として lParam パラメータを受け取れます。  この lParam に szText のポインタなどを受け取れば良いでしょう。簡単。 >(1)どこの部分でメッセージボックスの表示を行うのか? > main関数の中です。  ↑  了解。 >(2)クリップボードのコピー処理はどこに記述したいのか? > 独立させた関数にしたいです。  ↑  これも了解。 ・今は WinMain() で作っていますが main() で良いんですよね。  つまり、コンソール・アプリケーションが完成品のタイプですよね。  次の回答で main() 関数で使えるように全てを書き換えてみました。 ・特に EnumWindows() 関数の第2引数とコールバック関数の内部での処理を  今後の参考としてみて下さい。 最後に: ・コールバック関数の中で構造体の swOption を参照すれば列挙するウインドウの  タイプをいろいろと呼び出し元で変更できます。上手く利用して下さい。  次の回答では swOption 変数の参照していませんが構造体メンバにはあります。 ・EnumWindows() 関数を実行する前に swOption 変数に何か値をセットしてから  コールバック関数の中で swOption 変数の値により列挙タイプを分ければよい。 ・以上。

すると、全ての回答が全文表示されます。
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.2

★上手くいかなかったのですか? >コールバック関数の中は文字列の取得までとして、 >そのほかは別の関数の中で行いたいのです。  ↑  それならコールバック関数の外でサンプルに載せた処理を行えばよいのでは。 ・ウインドウ・ハンドル hWnd を指定します。  if ( MessageBox(hWnd,lpText,TEXT("確認"),(MB_ICONQUESTION | MB_YESNO)) == IDYES ){   if ( !MyClipboardCopy(hWnd,lpText) ){    MessageBox( hWnd,     TEXT("クリップボードにコピーできなかった。"),     TEXT("エラー"), (MB_ICONERROR | MB_OK) );   }  }  ↑  メッセージボックスを表示したい場所や、クリップボードのコピー処理を行う場所に  上記のサンプルを記述すればよいと思いますけど。 ・一応、ソースを補足に貼り付けて見せて下さい。  それから  (1)どこの部分でメッセージボックスの表示を行うのか?  (2)クリップボードのコピー処理はどこに記述したいのか?  (3)コンソール・アプリケーションか?GUI アプリケーションか?どっち。  上記の3つも補足して下さい。 ・それではまた。

batumaru53
質問者

補足

たびたびの回答ありがとうございます。 恥ずかしくて、お見せできるようなソースではないのですが、恥を忍んでのせてみます。 szTextにタイトルの列挙をまとめてそれを 呼び出し側の関数で使いたいのです。 今はグローバル変数でやっていてそれなりの結果は出ているのですが グローバル変数では無くしたいのですが、コールバック関数で取得した szTextをどうすれば、持ってこれるのか?持ってこれないのか? どういう、処理が良いのかもあまりわかっていないのが現状です。  (1)どこの部分でメッセージボックスの表示を行うのか?   main関数の中です。  (2)クリップボードのコピー処理はどこに記述したいのか?   独立させた関数にしたいです。  (3)コンソール・アプリケーションか?GUI アプリケーションか?どっち。   多分コンソールです、ウィンドは要りません。   最終的にはメッセージボックスも要らないです。 ////////// //ここでグローバル変数?にしてなんとか出来ている感じです。 char szText[1000] ; //MyClipboardCopyはそのままここに書きました。 //この辺はweb上のサンプルをかき集めました。 BOOL CALLBACK EnumWndProc(HWND hWnd, LPARAM lParam) { char szWindowName[128]; char szClassName[128]; //ウィンドウテキスト(キャプション)の取得 GetWindowText( hWnd, szWindowName, sizeof(szWindowName) ); //ウィンドウクラス名の取得 GetClassName( hWnd, szClassName, sizeof(szWindowName) ); //EnumWindows()ではIME等、不可視のウィンドウも全て列挙されるので //ふるいにかける必要がある //この辺を弄ると出力を変えられそう by G //&&はAND ==は同じ //!=は違う 言う演算子 if( ( IsWindowVisible( hWnd ) ) && // 可視状態か ( GetWindow( hWnd, GW_OWNER ) == NULL ) && // トップレベルウィンドウか ( lstrlen( szWindowName ) > 0 ) && // キャプションを持っているか ( lstrcmp( szClassName, "Progman" ) != 0 )) // シェルでないか { //取得した情報を文字列にする //名前だけで良いのでクラス名は要らない(,szClassName) //先頭に改行が入ってしまうのを修正 if ( lstrlen( szText ) == 0){ wsprintf( szText, "%s", szWindowName); } else{ wsprintf( szText, "%s\n%s", szText,szWindowName); } } return TRUE; } int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance , PSTR lpCmdLine , int nCmdShow) { LPTSTR lpText; EnumWindows(EnumWndProc,0); MessageBox(NULL, szText, "起動中のWindow", MB_OK); lpText = szText; MyClipboardCopy(NULL,lpText); return 0; }

すると、全ての回答が全文表示されます。
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.1

★コンソール・アプリケーションですか? ・普通に EnumWindows のコールバック関数内でメッセージボックスの表示や  クリップボードにテキストをコピーすればいいだけです。 ・下にサンプルを載せるので組み合わせて使って下さい。 サンプル: BOOL MyClipboardCopy( HWND hWnd, LPCTSTR lpText ) {  HGLOBAL hMem; // 設定用のメモリ変数  LPTSTR lpBuff; // 複写用のポインタ  DWORD dwSize; // 複写元の長さ    // クリップボードのデータ内容  dwSize = (lstrlen(lpText) + 1); // '\0' 文字分を加算    // データ内容のメモリを確保  if ( (hMem = GlobalAlloc((GHND|GMEM_SHARE),dwSize)) != NULL ){   if ( (lpBuff = (LPTSTR)GlobalLock(hMem)) != NULL ){    // ここでテキストデータを lpBuff にコピー    lstrcpy( lpBuff, lpText );    GlobalUnlock( hMem );        // クリップボードにデータを設定    if ( OpenClipboard(hWnd) ){     EmptyClipboard();     lpBuff = SetClipboardData( CF_TEXT, hMem );     CloseClipboard();    }    else{     lpBuff = NULL; // クリップボードが開けない時は解放指示    }   }   if ( lpBuff == NULL ){    GlobalFree( hMem ); // ロックできない時は解放   }  }  return (lpBuff != NULL); } 使い方: LPTSTR lpText; ←コールバック内で取得したタイトル名などが入っているとする。 if ( MessageBox(NULL,lpText,TEXT("確認"),(MB_ICONQUESTION | MB_YESNO)) == IDYES ){  if ( !MyClipboardCopy(NULL,lpText) ){   MessageBox( NULL,    TEXT("クリップボードにコピーできなかった。"),    TEXT("エラー"), (MB_ICONERROR | MB_OK) );  } } 以上。

batumaru53
質問者

お礼

回答、ありがとうございます。 とりあえず、コールバック関数内で処理してみます。

batumaru53
質問者

補足

早速の、回答ありがとうございます。 なにぶん、始めたばかりで知識が乏しくうまく説明できませんがご容赦ください。 コールバック関数の中は文字列の取得までとして、そのほかは別の関数の中で行いたいのです。 理由はと聞かれると弱いのですが・・ 参考にしたサイトではウィンドにリストボックスを作ってそこに入れていいました。 この所をウィンドを作らずに行いたいのです。 参考にしたURL http://wisdom.sakura.ne.jp/system/winapi/win32/win142.html

すると、全ての回答が全文表示されます。

関連するQ&A