早速プログラムを見てみましょう。
普通のメニューと、ダイアログボックスのリソース・スクリプトです。// process03x.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "終了(&X)...", IDM_END END POPUP "パイプ(&P)" BEGIN MENUITEM "パイプに書き込み(&W)", IDM_WRITE END END ///////////////////////////////////////////////////////////////////////////// // // Dialog // MYDLG DIALOG DISCARDABLE 0, 0, 137, 67 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "パイプに書き込む" FONT 9, "MS Pゴシック" BEGIN EDITTEXT IDC_EDIT1,7,7,123,36,ES_MULTILINE | ES_AUTOHSCROLL | ES_WANTRETURN DEFPUSHBUTTON "OK",IDOK,7,46,50,14 PUSHBUTTON "キャンセル",IDCANCEL,80,46,50,14 END
継承されるハンドルをグローバル変数(hWrite)にしています。// process03x.cpp #ifndef STRICT #define STRICT #endif #include <windows.h> #include <windowsx.h> #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyDlgProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE);LRESULT CALLBACK MyDlgProc(HWND, UINT, WPARAM, LPARAM); BOOL InitInstance(HINSTANCE, int); char szClassName[] = "process03x"; //ウィンドウクラス HANDLE hWrite; char szBuf[256]; HINSTANCE hInst;
このへんはいつもと同じです。int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; hInst = hCurInst; if (!InitApp(hCurInst)) return FALSE; if (!InitInstance(hCurInst, nCmdShow)) return FALSE; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } //ウィンドウ・クラスの登録 ATOM InitApp(HINSTANCE hInst) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; //プロシージャ名 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst;//インスタンス wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = "MYMENU"; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); return (RegisterClassEx(&wc)); } //ウィンドウの生成 BOOL InitInstance(HINSTANCE hInst, int nCmdShow) { HWND hWnd; hWnd = CreateWindow(szClassName, "子プロセス", //タイトルバーにこの名前が表示されます WS_OVERLAPPEDWINDOW, //ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 210, //幅 120, //高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInst, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; }
メニューからIDM_WRITEが選択されたらダイアログボックスを出します。//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; switch (msg) { case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_WRITE: DialogBox(hInst, "MYDLG", hWnd, (DLGPROC)MyDlgProc); break; } break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { if (hWrite) if (CloseHandle(hWrite)) MessageBox(hWnd, "hWriteをクローズしました", "OK", MB_OK); DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }
終了時にhWriteがNULLでない場合はCloseHandleで閉じます。
ダイアログボックスのプロシージャです。LRESULT CALLBACK MyDlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { DWORD dwWrite; char szStr[256]; switch (msg) { case WM_INITDIALOG: hWrite = GetStdHandle(STD_OUTPUT_HANDLE); if (hWrite == INVALID_HANDLE_VALUE) { MessageBox(hDlg, "hWriteが無効です", "OK", MB_OK); CloseHandle(hWrite); hWrite = NULL; } SetFocus(GetDlgItem(hDlg, IDC_EDIT1)); strcpy(szBuf, ""); return TRUE; case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: memset(szStr, ' ', sizeof(szStr)); szStr[255] = '\0'; WriteFile(hWrite, szStr, strlen(szStr), &dwWrite, NULL); Edit_GetText(GetDlgItem(hDlg, IDC_EDIT1), szBuf, sizeof(szBuf)); if (!WriteFile(hWrite, szBuf, strlen(szBuf), &dwWrite, NULL)) { MessageBox(hDlg, "書き込みエラーです", "Error", MB_OK); } CloseHandle(hWrite); hWrite = NULL; EndDialog(hDlg, IDOK); return TRUE; case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE; } return FALSE; } return FALSE; }
たったこれだけです。使い方は前章で作ったプログラムから このプログラムを起動します。そして、このプログラムのダイアログボックスに、 書き込みたい内容を記入します。すると、親プロセスのエディットコントロールに 内容が表示されます。
WM_INITメッセージが来たら、GetStdHandleで書き込みハンドルを取得します。 書き込みハンドルが有効でないときはCloseHandleで閉じてhWriteをNULLにしておきます。
エディットコントロールに文字列を書き込んで、OKボタンを押すと WriteFile関数でパイプにこの文字列を書き込みます。この関数が失敗したときは その旨メッセージボックスで知らせます。 成功しても失敗してもhWriteを閉じて、NULLにしておきます。 ダイアログボックスを開くたびにhWriteを取得するので閉じるときにはhWriteも閉じておきます。
もしメインウィンドウのプロシージャでhWriteを取得すると、次のような困った問題が起きます。
呼び出し側プログラムから、このプログラムが呼ばれたあとで親プログラムが終了してしまった
場合WriteFile関数が失敗しません。子プロセス側では、呼び出し元がいなくなったことに
気が付かない、ということが起こります。
このプログラムを単独で起動した場合、当然書き込みは失敗します。
いろいろな場合を想定して実験してみてください。簡単なプログラムですが結構奥が深いです。 また、匿名パイプを2本装備すると呼び出し側と子供側で双方向の通信ができるのでしょうか。 (親プロセスで書き込んだものを、子プロセスで表示、子プロセスで書き込んだものを親プロセスで 表示する)
これも実験してみてください。
Update 13/Dec/1999 By Y.Kumei