第4章 Cygwin におけるプログラミング

Cygwin を使うことで、Microsoft 又は off-the-shelf の出版物において定義されている GUI 関数を含む、標準的な Windows の 32 ビット API をフルに使用したプログラムを作成することが出来ます。 しかしながら、Microsoft のツールの代わりに GNU ツールを使用する場合、 それらのアプリケーションを作成するプロセスは少々異なったものとなります。

ほとんどの部分については、ソースコードに変更を加える必要はありません。 しかし、関数から全ての __export 属性を除去し、 以下に示すような形に置き換えなければなりません。

int foo (int) __attribute__ ((__dllexport__));

int
foo (int i)

Makefile は他の UNIX 風の Makefile に、そして他の Cygwin での Makefile に似ています。唯一の違いは、プログラムをコマンドラインアプリケーションではなく GUI アプリケーションとしてリンクするために gcc -mwindows を使用するという点だけです。 例を示します。

myapp.exe : myapp.o myapp.res
	gcc -mwindows myapp.o myapp.res -o $@

myapp.res : myapp.rc resource.h
	windres $< -O coff -o $@

windres を使えば、 Windows リソースを COFF フォーマットの .res ファイルにコンパイル出来ることを覚えておいて下さい。 これによって全てのビットマップ、アイコン、そして必要となる他のリソースが、 一つの扱いやすいオブジェクトファイルに格納されます。 通常、「-O coff」を省略した場合は Windows .res フォーマットのファイルが作成されます。 しかし我々にとってリンクが可能なのは COFF オブジェクトだけです。 そこで windres が COFF オブジェクトを作成するように指示しますが、 「リンカは Windows リソースファイルを直接扱うことが可能である」 と仮定する多くの事例に合わせるべく、 .res というファイル名の命名規則は残してあります。 windres に関する更なる情報については、 binutils のマニュアルを参照して下さい。

始めるに当たって参考となるよう、GUI モードの「Hello, World!」プログラムのサンプルを以下に示しておきます。

/*-------------------------------------------------*/
/* hellogui.c - gui hello world                    */
/* build: gcc -mwindows hellogui.c -o hellogui.exe */
/*-------------------------------------------------*/
#include <windows.h>

char glpszText[1024];

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int APIENTRY WinMain(HINSTANCE hInstance, 
		HINSTANCE hPrevInstance,
		LPSTR lpCmdLine,
		int nCmdShow)
{
	sprintf(glpszText, 
		"Hello World\nGetCommandLine(): [%s]\n"
		"WinMain lpCmdLine: [%s]\n",
		lpCmdLine, GetCommandLine() );

	WNDCLASSEX wcex; 
 
	wcex.cbSize = sizeof(wcex);
	wcex.style = CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc = WndProc;
	wcex.cbClsExtra = 0;
	wcex.cbWndExtra = 0;
	wcex.hInstance = hInstance;
	wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName = NULL;
	wcex.lpszClassName = "HELLO";
	wcex.hIconSm = NULL;

	if (!RegisterClassEx(&wcex))
		return FALSE; 

	HWND hWnd;
	hWnd = CreateWindow("HELLO", "Hello", WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);

	if (!hWnd)
		return FALSE;

	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);

	MSG msg;
	while (GetMessage(&msg, NULL, 0, 0)) 
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT ps;
	HDC hdc;
	
	switch (message) 
	{
		case WM_PAINT:
			hdc = BeginPaint(hWnd, &ps);
			RECT rt;
			GetClientRect(hWnd, &rt);
			DrawText(hdc, glpszText, strlen(glpszText), &rt, DT_TOP | DT_LEFT);
			EndPaint(hWnd, &ps);
			break;
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}