C プログラミングの小技
C言語による WIN32API 利用 (Drag & Drop) (2010/04/08)
はじめに
GUI環境では、CUIベースのコマンドを使用する場合は、%SystemRoot%\system32\cmd.exe 等を起動し、コマンドを
実行させる必要が生じます。
必要な機能をGUIプログラムとして作成し、処理対象のファイル名を Drag&Drop で渡せると便利な場合も多いので、
簡単なGUIプログラムの雛形を用意します。
また、fprintf で情報を出力できると便利なケースも多いので、cmd.exe 以外の explorer.exe 等から起動された場合
には、コンソールウインドウも同時に生成する事にします。
雛形プログラムに関して
このプログラムは、プログラムを作成する時のスタートとなる最低限度の実装です。そのため、このプログラムが
出来る事は、ウインドウの生成、ドラッグアンドドロップの有効化、ドラックアンドドラックで受け取ったファイル名の
表示(コンソールに表示)のみです。
cmd.exe からプログラムが起動された時は起動した cmd.exe の画面に表示されます。
explorer.exe からダブルクリックでコマンドが起動された時は、コンソールウインドウを同時に生成し、ドラックアンド
ドロップで送られてきたファイル名は、生成したコンソール画面に表示します。
C言語で記述された100行程度のプログラムで、WIN32APIのみ利用しているので容易に理解できると思います。
ソフトの使用に関して
windows に cygwin
が導入された環境で、 gcc (3.xx) でコンパイルされることを想定しています。
実行時には、cygwin を必要としないように -mno-cygwin オプションを付けてコンパイルしています。
cygwin のインストールに関しては、
http://www.cygwin.com/setup.exe
の setup.exe をダウンロードします。
実際のインストール方法は、多くのサイトで公開していますのでそちらを参照下さい。
現行の cygwin のバージョンは 1.7.x で、ディフォルトの gcc 4.x は -mno-cygwin
オプションが利用できない
(将来的にはサポートされると思われます)ため、gcc 3.x. をインストールする事をお勧めします。
ソフトのコンパイルと実行
以下の作業は、
"コマンド プロンプト" を起動して実行します。
ダウンロードしたファイルは、C:\DragAndDrop に保存されていると仮定しています。
C:\> cd C:\DragAndDrop>
C:\DragAndDrop>
C:\DragAndDrop>cat DragAndDrop.c
#include <stdio.h>
#include <windows.h>
/* Drag & Drop でファイル名を受け取るプログラムの雛形
gcc -O4 -Wall -mno-cygwin -mwindows -o DragAndDrop DragAndDrop.c
gcc -O4 -Wall -mno-cygwin -mwindows -mconsole -o DragAndDrop
DragAndDrop.c
*/
TCHAR fnameWithPath[MAX_PATH] ;
void processing( char *fileNameWithPath )
{// fprintf の使用には、gcc のコンパイルオプションに -mconsole を指定することが必須
fprintf( stdout, "D&D:%s\n", fileNameWithPath ) ;
}
////////////////////////////////////////////////////////////////////////////////
// ウィンドウプログラム部 // HWND
は、対象ウィンドウを特定するハンドル (Window ID)
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT message, WPARAM
wParam, LPARAM lParam)
{
switch( message ) {
case WM_CREATE:
DragAcceptFiles(hWnd, TRUE); // Drag & Drop操作を有効 (enable
WM_DROPFILES)
break;
case WM_DROPFILES:
SetForegroundWindow(hWnd); // 他のスレッドよりも若干高い優先順位を割り当て
{register int i, max;
for( i=0, max=DragQueryFile( (HDROP)wParam, -1, NULL, 0 );
i<max;
i++ ) {
DragQueryFile( (HDROP)wParam, i, fnameWithPath, sizeof(fnameWithPath) )
;
processing( fnameWithPath ) ;
}
}
DragFinish((HDROP)wParam);
break;
/* major events
case WM_LBUTTONDOWN:
break;
case WM_RBUTTONDOWN:
break;
case WM_MOUSEMOVE:
break;
case WM_KEYDOWN: // MessageBox(hWnd, "WM_KEYDOWN",
"キーイベントの発生", MB_OK);
break;
case WM_SIZE: // ウィンドウサイズ調整
break;
// Send(If it's
necessary) PostMessage(hWnd,WM_PAINT,0,0) or No break;
case WM_PAINT: // (再)描画処理
{PAINTSTRUCT ps ;
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
}
break;
*/
case WM_CLOSE: //
必要な確認処理後、DestroyWindow関数を呼び出す
DestroyWindow( hWnd ) ;
break;
case WM_DESTROY: // ウィンドウを破棄した後に送られるメッセージ
PostQuitMessage( 0 ) ;
break;
default:
return DefWindowProc( hWnd, message, wParam, lParam ) ;
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR
lpCmdLine, int nCmdShow)
{
HWND
hWnd ;
WNDCLASSEX wc ;
MSG
message ;
int
returnedValue
;
// BOOL が本来の正しい型
const char *ClassName = "Canvas",
*title = "drag and drop" ;
// ウィンドウクラスの情報を設定
wc.cbSize
=
sizeof(WNDCLASSEX)
;
// 構造体のサイズ
wc.style
= CS_HREDRAW |
CS_VREDRAW | CS_DBLCLKS; // スタイルの設定
wc.lpfnWndProc =
WindowProcedure;
// ウィンドウプロシージャ
wc.cbClsExtra =
0;
// 構造体が使用する extra メモリサイズ
wc.cbWndExtra =
0;
// ウィンドウが使用する extra メモリサイズ
wc.hInstance =
hInstance;
// インスタンスハンドル
wc.hIcon
=
LoadIcon(hInstance, "PRGICON")
; //
アイコン
wc.hCursor
= LoadCursor(NULL,
IDC_ARROW)
;
//
マウスカーソル
wc.hbrBackground =
(HBRUSH)GetStockObject(WHITE_BRUSH) ; // ウィンドウ背景
wc.lpszMenuName =
NULL,
// メニュー名
wc.lpszClassName = TEXT(ClassName)
;
// ウィンドウクラス名
wc.hIconSm
= LoadIcon(hInstance,
"PRGICON")
; // 子アイコン
if( RegisterClassEx( &wc ) == 0 ) return
1;
// ウィンドウクラスの登録
if( (hWnd =
CreateWindow(
// ウィンドウの生成
wc.lpszClassName,
// ウィンドウクラス名
TEXT(title),
// タイトルバーに表示する文字列
WS_OVERLAPPED | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU,
// ウィンドウの種類 WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
//
ウィンドウを表示する位置(X座標) CW_USEDEFAULT,
CW_USEDEFAULT,
//
ウィンドウを表示する位置(Y座標) CW_USEDEFAULT,
256,
// ウィンドウの幅 DEFAULT ⇒
MAIN_LX_SIZE,
128,
// ウィンドウの高さ DEFAULT ⇒ MAIN_LY_SIZE,
NULL,
// 親ウィンドウのウィンドウハンドル
NULL,
// メニューハンドル
hInstance,
// インスタンスハンドル
NULL
// その他の作成データ
) ) == NULL ) return 1;
ShowWindow( hWnd, SW_SHOW )
; // ウィンドウを表示
UpdateWindow( hWnd )
;
// ウィンドウの更新
//
メニューの有効無効設定は、WindowProcedure の WM_CREATE で行うので、
// 現時点において、hWnd でのアクセスは失敗する。
while( (returnedValue =
GetMessage(&message, NULL, 0, 0)) != 0 ) { // メインループ
if( returnedValue == -1 ) return -1; // GetMessage() が失敗(-1)なら終了する
TranslateMessage( &message ) ;
DispatchMessage( &message ) ;
}
return 0;
}
C:\DragAndDrop>gcc -O4 -Wall -mno-cygwin -mwindows
-mconsole -o DragAndDrop DragAndDrop.c
C:\DragAndDrop>cygcheck DragAndDrop.exe
Found: DragAndDrop.exe
DragAndDrop.exe
C:\WINDOWS\system32\msvcrt.dll
C:\WINDOWS\system32\KERNEL32.dll
C:\WINDOWS\system32\ntdll.dll
C:\WINDOWS\system32\GDI32.dll
C:\WINDOWS\system32\USER32.dll
C:\WINDOWS\system32\SHELL32.DLL
C:\WINDOWS\system32\ADVAPI32.dll
C:\WINDOWS\system32\RPCRT4.dll
C:\WINDOWS\system32\Secur32.dll
C:\WINDOWS\system32\SHLWAPI.dll
C:\DragAndDrop>
C:\DragAndDrop>DragAndDrop.exe
終わりに
void processing( char
*fnameWithPath )
{//
fprintf の使用には、gcc のコンパイルオプションに -mconsole を指定することが必須
fprintf( stdout, "D&D:%s\n",
fnameWithPath ) ;
}
に利用者の必要な処理を定義すれば直ぐに利用できると思います。
簡単なサンプルですが、参考になれば幸いです。