SAK 図書館
VS.NET C 言語編3 - win32 アプリケーション、DialogBox、CreateThread
■VC.NET で win32 アプリケーション作成
・真面目にメインウィンドウを作成する場合は、WinMain で、
RegisterClass
CreateWindow
LoadAccelerators
ShowWindow
GetMessage
TranslateAccelerator
TranslateMessage
DispatchMessage
して、
WndProc
で処理する必要があるのだが、メインウィンドウでタブストップ等の
コントロール制御を行うのは実に面倒である。
昔は、根気があったよなあ〜と我ながら感心する。(^^;
・ちょっとしたツールプログラムのインタフェースウィンドウなら、
ダイアログクラスを使用するのが簡単で良い。
ダイアログは標準でタブストップ等の制御を行ってくれる。
つまりは、VB のフォームに非常に近い。
・以下、win32 アプリケーションではあるが、メインウィンドウは作成せず、
ダイアログをメインウィンドウとして使用するプログラムのサンプルである。
テストではあるが、一応、
初期化ファイル(.ini) の読み書き
フォルダ選択コモンモジュールの使用
マルチスレッドでの処理制御
を行っている。
■win32 アプリケーションテスト
・VC.NET で、C++ ではなく、C をコンパイルする場合、プリコンパイルヘッダ
を使用しないようにしないと、コンパイラが正しく動作しない。
・リソースソースについては、
『VS.NET C 言語編4 - win32 アプリケーション、リソースソース、DIALOGEX』
を参照して下さい。
/*
========================================================================
win32 アプリケーションテスト
========================================================================
*/
// インクルードヘッダ
#include <windows.h>
#include <shlobj.h>
#include "resource.h"
// 定数宣言
#define MAX_STR 1025 // 文字列最大数
#define WM_USER_THREADEND WM_USER + 1 // スレッド終了メッセージ
// 関数プロトタイプ
LRESULT CALLBACK TestProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
DWORD WINAPI ThreadProc(LPVOID lpvoid);
VOID GetIniData(HWND hWnd);
VOID WriteIniData(HWND hWnd);
int SchStrPrior(LPCTSTR str, TCHAR chr);
LPTSTR LeftStr(LPTSTR ret, LPCTSTR str, int len);
LPTSTR StrLong(LPTSTR ret, long num, int l);
BOOL SelFolder(HWND hWnd, LPSTR dir);
LRESULT CALLBACK SelFolderProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
VOID DisabledDlg(HWND hWnd);
VOID EnabledDlg(HWND hWnd);
BOOL CheckInputData(HWND hWnd);
// グローバル変数
HINSTANCE hInst; // インスタンスハンドル
HWND hOwn; // オーナウィンドウハンドル
TCHAR PgmTitle[MAX_STR]; // プログラムタイトル
TCHAR PgmIni[MAX_STR]; // プログラム初期化ファイル
TCHAR CurDir[MAX_STR]; // カレントフォルダ
HANDLE hThread; // スレッドハンドル
DWORD ThreadId; // スレッドID
/*
========================================================================
メイン
========================================================================
*/
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
// インスタンスハンドル保管
hInst = hInstance;
// ストリングテーブル取得
LoadString(hInstance, IDS_APP_TITLE, PgmTitle, MAX_STR);
// win32 アプリケーションテストダイアログ表示
DialogBox(hInstance, (LPCTSTR)IDD_TEST, NULL, (DLGPROC)TestProc);
// 終了
return 0;
}
/*
========================================================================
win32 アプリケーションテストダイアログプロシジャ
========================================================================
*/
LRESULT CALLBACK TestProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
TCHAR str[MAX_STR];
switch (message) {
case WM_INITDIALOG:
hOwn = hDlg;
GetIniData(hDlg);
return TRUE;
case WM_USER_THREADEND:
if (wParam == 101) CloseHandle(hThread);
SetWindowText(GetDlgItem(hDlg, IDC_MSG), "処理終了しました。");
EnabledDlg(hDlg);
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDC_INBUTTON:
if (SelFolder(hDlg, str)) {
SetWindowText(GetDlgItem(hDlg, IDC_INPUTPATH), str);
}
return TRUE;
case IDOK:
if (!CheckInputData(hDlg)) {
MessageBeep(MB_ICONEXCLAMATION);
break;
}
DisabledDlg(hDlg);
WriteIniData(hDlg);
SetWindowText(GetDlgItem(hDlg, IDC_MSG), "処理中...");
hThread = CreateThread(NULL, 0, ThreadProc, (LPVOID)101, 0, &ThreadId);
return TRUE;
case IDCANCEL:
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
}
return FALSE;
}
/*
========================================================================
スレッドプロシジャ
========================================================================
*/
DWORD WINAPI ThreadProc(LPVOID lpvoid)
{
// スレッド処理
MessageBox(hOwn, "実行!!", PgmTitle, MB_OK | MB_ICONINFORMATION);
// スレッド終了
PostMessage(hOwn, WM_USER_THREADEND, (WPARAM)lpvoid, 0);
ExitThread(0);
return 0;
}
/*
========================================================================
初期化ファイル参照
========================================================================
*/
VOID GetIniData(HWND hWnd)
{
TCHAR str[MAX_STR];
TCHAR str2[MAX_STR];
// 初期化ファイルパス名取得
if (GetModuleFileName(hInst, str, sizeof(str)) == 0) {
MessageBox(hWnd, "プログラム名取得に失敗しました。", PgmTitle, MB_OK | MB_ICONSTOP);
exit(0);
}
lstrcpy(PgmIni, LeftStr(str2, str, SchStrPrior(str, '.')));
lstrcat(PgmIni, ".ini");
// カレントフォルダ取得
lstrcpy(CurDir, LeftStr(str2, str, SchStrPrior(str, '\\')));
// 初期化ファイル参照
GetPrivateProfileString("file", "number", "", str, sizeof(str), PgmIni);
SetWindowText(GetDlgItem(hWnd, IDC_NUMBER), str);
GetPrivateProfileString("file", "inputpath", "", str, sizeof(str), PgmIni);
SetWindowText(GetDlgItem(hWnd, IDC_INPUTPATH), str);
return;
}
/*
========================================================================
初期化ファイル保存
========================================================================
*/
VOID WriteIniData(HWND hWnd)
{
TCHAR str[MAX_STR];
// 初期化ファイル保存
GetWindowText(GetDlgItem(hWnd, IDC_NUMBER), str, sizeof(str));
WritePrivateProfileString("file", "number", str, PgmIni);
GetWindowText(GetDlgItem(hWnd, IDC_INPUTPATH), str, sizeof(str));
WritePrivateProfileString("file", "inputpath", str, PgmIni);
return;
}
/*
========================================================================
文字位置検索(prior)
========================================================================
*/
int SchStrPrior(LPCTSTR str, TCHAR chr)
{
LPCTSTR si;
if ((si = str + lstrlen(str) - 1) < str) return -1;
do {
if (*si == chr) return(si - str);
si = AnsiPrev(str, si);
} while (si > str);
if (*si == chr) return(si - str);
return -1;
}
/*
========================================================================
左文字列切出
========================================================================
*/
LPTSTR LeftStr(LPTSTR ret, LPCTSTR str, int len)
{
if (len < 1) return(lstrcpy(ret, ""));
lstrcpy(ret, str);
if (len < lstrlen(str)) *(ret + len) = '\0';
return ret;
}
/*
========================================================================
数値 → 文字列変換(long)
========================================================================
*/
LPTSTR StrLong(LPTSTR ret, long num, int l)
{
int i;
TCHAR str[MAX_STR];
if (lstrlen(ltoa(num, ret, 10)) > l) return ret;
for (i = 1, *str = '\0'; i <= l; i++) lstrcat(str, " ");
lstrcat(str, ret);
if (l < lstrlen(str)) {
lstrcpy(ret, str + lstrlen(str) - l);
}
else {
lstrcpy(ret, str);
}
return ret;
}
/*
========================================================================
フォルダ選択
========================================================================
*/
BOOL SelFolder(HWND hWnd, LPSTR dir)
{
BOOL rcd = FALSE;
BROWSEINFO bi;
LPITEMIDLIST il;
bi.hwndOwner = hWnd;
bi.pidlRoot = 0;
bi.pszDisplayName = 0;
bi.lpszTitle = PgmTitle;
bi.ulFlags = BIF_RETURNONLYFSDIRS;
bi.lpfn = (BFFCALLBACK)SelFolderProc;
il = SHBrowseForFolder(&bi);
if (il) {
if (SHGetPathFromIDList(il, dir)) {
rcd = TRUE;
}
}
return rcd;
}
/*
========================================================================
フォルダ選択プロシジャ
========================================================================
*/
LRESULT CALLBACK SelFolderProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
TCHAR str[MAX_STR];
switch (message)
{
case BFFM_INITIALIZED:
GetWindowText(GetDlgItem(hOwn, IDC_INPUTPATH), str, sizeof(str));
if (lstrcmpi(str, "") == 0) {
lstrcpy(str, CurDir);
}
SendMessage(hWnd, BFFM_SETSELECTION, TRUE, (LPARAM)str);
}
return 0;
}
/*
========================================================================
ダイアログ無効化
========================================================================
*/
VOID DisabledDlg(HWND hWnd)
{
EnableMenuItem(GetSystemMenu(hWnd, FALSE), SC_CLOSE, MF_DISABLED | MF_GRAYED);
EnableWindow(GetDlgItem(hWnd, IDC_NUMBER), FALSE);
EnableWindow(GetDlgItem(hWnd, IDC_INPUTPATH), FALSE);
EnableWindow(GetDlgItem(hWnd, IDC_INBUTTON), FALSE);
EnableWindow(GetDlgItem(hWnd, IDOK), FALSE);
EnableWindow(GetDlgItem(hWnd, IDCANCEL), FALSE);
return;
}
/*
========================================================================
ダイアログ有効化
========================================================================
*/
VOID EnabledDlg(HWND hWnd)
{
EnableMenuItem(GetSystemMenu(hWnd, FALSE), SC_CLOSE, MF_ENABLED);
EnableWindow(GetDlgItem(hWnd, IDC_NUMBER), TRUE);
EnableWindow(GetDlgItem(hWnd, IDC_INPUTPATH), TRUE);
EnableWindow(GetDlgItem(hWnd, IDC_INBUTTON), TRUE);
EnableWindow(GetDlgItem(hWnd, IDOK), TRUE);
EnableWindow(GetDlgItem(hWnd, IDCANCEL), TRUE);
return;
}
/*
========================================================================
入力データチェック
========================================================================
*/
BOOL CheckInputData(HWND hWnd)
{
TCHAR str[MAX_STR];
// データチェック
GetWindowText(GetDlgItem(hWnd, IDC_NUMBER), str, sizeof(str));
if (FALSE) {
SetWindowText(GetDlgItem(hWnd, IDC_MSG), "データの指定が間違っています。");
return FALSE;
}
return TRUE;
}
■コンパイルすると、次のワーニングが出る。
SchStrPrior を Windows95 時代のソースから移植したのが原因と思う。
う〜ん、とりあえず動作に支障はないようなので、よしとしよう。(^^;
詳しい方、お教えいただけたらうれしいです。
g:\Tmp\vsp\test\test.c(171) : warning C4244: 'return' : '__w64 int' から 'int' に変換しました。データが失われているかもしれません。
g:\Tmp\vsp\test\test.c(174) : warning C4244: 'return' : '__w64 int' から 'int' に変換しました。データが失われているかもしれません。
・【追加情報】 SchStrPrior の戻り値型を INT_PTR 型にすると良いらしい。
int は win64 でも 32ビットのままだが、INT_PTR は win64 だと 64ビット
になるのでこの警告が出ないはずとのこと。
(情報下さった方、ありがとうございます。)
■パソコン基礎知識 C 言語編資料
■プログラミング言語資料
■パソコン基礎知識 ハード編資料
■パソコン基礎知識 画像編資料
■パソコン基礎知識 Windows 編資料
■コンピュータシステム導入編資料