二重起動防止は、CreateMutex 関数か FindWindow 関数を使用すると可能です。
ファイルをアイコンにドロップして起動したときのファイル名はコマンドライン引数で取得できますが、GetCommandLine関数か __argv、__argc 変数を使用できます。 ただし、GetCommandLine 関数を使用する場合は、ファイル名分離関数を自作する必要があるでしょう。GetCommandLineW 関数を使用する場合は、CommandLineToArgvW 関数を使える。 二重起動防止とコマンドライン引数の両方の機能を追加したいときは、コマンドライン引数を別のプロセス(この場合は、既に起動中のプログラム)に引き渡します。 |
LRESULT CALLBACK ProcWnd(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_COPYDATA: COPYDATASTRUCT *pcds; pcds = (COPYDATASTRUCT*) lParam; if(pcds->cbData > 0){ Parse_CmdLine((char*)pcds->lpData); } break; case WM_CLOSE: DestroyWindow(hWnd); PostQuitMessage(0); break; default: return DefWindowProc(hWnd, uMsg, wParam, lParam); } return 0; } int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, LPSTR lpCmdLine, int nCmdShow) { // 二重起動防止&コマンドライン引数引き渡し HWND hWnd = FindWindow(MYWNDCLASS, MYWNDTITLE); if(hWnd){ COPYDATASTRUCT cds; ZeroMemory(&cds, sizeof(cds)); cds.cbData = strlen(lpCmdLine)+1; cds.lpData = lpCmdLine; SendMessage(hWnd, WM_COPYDATA, NULL, (LPARAM)&cds); return 0; } // ウィンドウクラスの登録 WNDCLASSEX wc; ... RegisterClassEx(&wc); // ウィンドウの作成 hWnd = CreateWindowEx(...); // メッセージ ループ MSG msg; while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } |
IE をATL関数を使用してウィンドウに貼り付けるサンプル。
AtlAxWinInit() と CreateWindowEx() が無くても表示はできるが、動作不良(COPY&PASTE ができない)が発生する。 atl.lib のリンク設定が必要。 |
#include <windows.h> #include <atlbase.h> #include <exdisp.h> LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static IWebBrowser2 *pWB = NULL; static HWND hWB = NULL; switch(uMsg) { case WM_CREATE: { CHAR strURL[MAX_PATH] = "http://w5.abcoroti.com/~pgm/"; WCHAR wstrURL[MAX_PATH]; VARIANT vURL = {0}, vDummy = {0}; LPUNKNOWN pUk = NULL; LPOLESTR pProgID = NULL; CHAR strPrgID[256]; HINSTANCE hInst = ((LPCREATESTRUCT)lParam)->hInstance; CoInitialize(NULL); AtlAxWinInit(); ProgIDFromCLSID(CLSID_WebBrowser, &pProgID); WideCharToMultiByte(CP_ACP, 0, pProgID, -1, strPrgID, sizeof(strPrgID), NULL, NULL); CoTaskMemFree(pProgID); hWB = CreateWindowEx(0, "AtlAxWin", strPrgID, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hWnd, NULL, hInst, NULL); AtlAxGetControl(hWB, &pUk); if(pUk){ pUk->QueryInterface(IID_IWebBrowser2, (LPVOID *) &pWB); pUk->Release(); pUk = NULL; } vURL.vt = VT_BSTR; MultiByteToWideChar(CP_ACP, 0, strURL, -1, wstrURL, sizeof(wstrURL)); vURL.bstrVal = SysAllocString(wstrURL); if(pWB) pWB->Navigate2(&vURL, &vDummy, &vDummy, &vDummy, &vDummy); SysFreeString(vURL.bstrVal); VariantClear(&vURL); SendMessage(hWnd, WM_SETTEXT, 0, (LPARAM) strURL); } return 0; case WM_SIZE: MoveWindow(hWB, 0, 0, LOWORD(lParam), HIWORD(lParam), FALSE); return 0; case WM_CLOSE: if(pWB){ pWB->Stop(); pWB->Release(); pWB = NULL; } DestroyWindow(hWnd); CoUninitialize(); // 本来は、メインウィンドウを閉じてメッセージループを抜けた後に記述する PostQuitMessage(0); return 0; default: break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } |
Macromedia Flash をATL関数を使用してウィンドウに貼り付けるサンプル。
Flash9d.ocx のCLSIDや名前空間名、メンバ、メソッド等は、ATL関数を記述しないでコンパイルすると生成される Flash9d.tlh というヘッダファイルに記述されている。 atl.lib のリンク設定が必要。 Flash9d.ocx はソースファイルと同じフォルダにコピーしておく。 |
#include <windows.h> #include <atlbase.h> #import ".\\Flash9d.ocx" using namespace ShockwaveFlashObjects; LRESULT CALLBACK WindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) { static IShockwaveFlash *pFlash = NULL; static HWND hFlash = NULL; switch(uMsg) { case WM_CREATE: { LPUNKNOWN pUk = NULL; LPOLESTR pProgID = NULL; CHAR strPrgID[256]; HINSTANCE hInst = ((LPCREATESTRUCT)lParam)->hInstance; CoInitialize(NULL); AtlAxWinInit(); ProgIDFromCLSID(__uuidof(ShockwaveFlash), &pProgID); WideCharToMultiByte(CP_ACP, 0, pProgID, -1, strPrgID, sizeof(strPrgID), NULL, NULL); CoTaskMemFree(pProgID); hFlash = CreateWindowEx(0, "AtlAxWin", strPrgID, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hWnd, NULL, hInst, NULL); AtlAxGetControl(hFlash, &pUk); if(pUk){ pUk->QueryInterface(__uuidof(IShockwaveFlash), (LPVOID *) &pFlash); pUk->Release(); } if(pFlash){ pFlash->put_Movie(L"c:\\sample.swf"); pFlash->Play(); } } return 0; case WM_SIZE: MoveWindow(hFlash, 0, 0, LOWORD(lParam), HIWORD(lParam), FALSE); return 0; case WM_CLOSE: if(pFlash){ pFlash->Stop(); pFlash->Release(); pFlash = NULL; } DestroyWindow(hWnd); CoUninitialize(); // 本来は、メインウィンドウを閉じてメッセージループを抜けた後に記述する PostQuitMessage(0); return 0; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } |
リモートホストのテキストファイルの内容を読み込んで表示する。
wininet.lib のリンク設定が必要。 |
#include <windows.h> #include <wininet.h> void Read_Html(HWND hWnd) { HINTERNET hSession,hFile; DWORD dwRead; char szTemp[1024]; char strURL[] = "http://w5.abcoroti.com/~pgm/"; HDC hDC; int ct = 0; hSession = InternetOpen("WinInet Sample", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); hFile = InternetOpenUrl(hSession, (LPCTSTR)strURL, NULL, 0, INTERNET_FLAG_DONT_CACHE, 0); hDC = GetDC(hWnd); while (InternetReadFile(hFile, (LPVOID)szTemp, 1024, &dwRead)) { if (!dwRead) break; TextOut(hDC,0,ct,szTemp,strlen(szTemp)); ct += 20; } InternetCloseHandle(hSession); InternetCloseHandle(hFile); ReleaseDC(hWnd,hDC); } |
ダイアログに、MSFlexGrid Control を表示するサンプル
atl.lib のリンク設定が必要。 リソースエディタで、作成したダイアログを右クリック→[ActiveX コントロールの挿入]→[Microsoft FlexGrid Control] を選択。 |
#include <windows.h> #include <atlbase.h> #include "resource.h" #import <MSFLXGRD.OCX> exclude("OLEDropEffectConstants") using namespace MSFlexGridLib; int CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { static IMSFlexGrid *pFG = NULL; switch (uMsg) { case WM_INITDIALOG: { LPUNKNOWN pUk = NULL; AtlAxGetControl(GetDlgItem(hDlg, IDC_MSFLEXGRID1), &pUk); if(pUk){ pUk->QueryInterface(__uuidof(IMSFlexGrid), (LPVOID*) &pFG); pUk->Release(); } if(!pFG) break; pFG->put_Cols(4); pFG->put_Rows(3); _bstr_t bstr("ooooo"); pFG->put_TextArray(0, bstr); pFG->put_TextArray(1, _bstr_t("abcdefg")); pFG->put_TextMatrix(1, 1, _bstr_t("あいうえお")); } break; case WM_COMMAND: switch(wParam) { case IDOK: SendMessage(hDlg,WM_CLOSE,0,0); break; case IDCANCEL: SendMessage(hDlg,WM_CLOSE,0,0); break; default: return FALSE; } break; case WM_CLOSE: if(pFG){ pFG->Release(); pFG = NULL; } DestroyWindow(hDlg); PostQuitMessage(0); break; default: return FALSE; } return TRUE; } int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, LPSTR lpCmdLine, int nCmdShow) { MSG msg; HWND hDlg; CoInitialize(NULL); hDlg = AtlAxCreateDialog(hInst, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc, NULL); ShowWindow(hDlg, nCmdShow); while(GetMessage(&msg, NULL, 0, 0)) { if (IsDialogMessage(hDlg, &msg)) continue; TranslateMessage(&msg); DispatchMessage(&msg); } CoUninitialize(); return msg.wParam; } |
MSDNサンプルのguidgenをビルドして実行すると、
作成されたCLSIDがクリップボードにコピーされる。 おそらく、作成したCLSIDは、ActiveXコントロールを自作するときに使用する。 MSDEV→[ツール]→[コントロールの登録]を実行するか Regsvr32.exe を実行して、そのCLSIDを記述した ライブラリをレジストリに登録して使用する。 uuidgen.exe は、DirectShow のフィルターを作成するときに使う。 |
//{6F0D123B-BAD2-4167-A0D0-80224F25FABB} は下のguidの別の表記方法である GUID guid = {0x6F0D123B, 0xBAD2, 0x4167, {0xA0, 0xD0, 0x80, 0x22, 0x4F, 0x25, 0xFA, 0xBB}}; char strGuid[64]; sprintf(strGuid,"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",guid.Data1,guid.Data2,guid.Data3, guid.Data4[0],guid.Data4[1],guid.Data4[2],guid.Data4[3],guid.Data4[4], guid.Data4[5],guid.Data4[6],guid.Data4[7]); // 専用関数で変換する場合 LPOLESTR wstrGuid; StringFromCLSID(*guid, &wstrGuid); WideCharToMultiByte(CP_ACP, 0, wstrGuid, -1, strGuid, sizeof(strGuid), NULL, NULL); CoTaskMemFree(wstrGuid); // 逆変換 GUID guid; CLSIDFromString(OLESTR("{6F0D123B-BAD2-4167-A0D0-80224F25FABB}"), &guid); // CLSIDが同じか調べる BOOL bEqual = IsEqualCLSID(clsid1, clsid2); // CLSIDを関数の引数にするときは、CLSIDよりはREFCLSIDを使う。 // GUIDやIIDもREFGUIDやREFIIDを使う。 // WTYPES.HでREFCLSIDは、const CLSID &と定義される。 void func(REFCLSID clsid) { } main() { CLSID clsid; func(clsid); } |
// 元のサイズに戻す if(IsIconic(hWnd) || IsZoomed(hWnd)){ ShowWindow(hWnd, SW_RESTORE); } // 最小化から元のサイズに戻す if(IsIconic(hWnd)){ OpenIcon(hWnd); } // 最小化 ShowWindow(hWnd, SW_MINIMIZE); // または、CloseWindow(hWnd); // 最大化 ShowWindow(hWnd, SW_MAXIMIZE); // 表示 ShowWindow(hWnd, SW_SHOW); // 非表示 ShowWindow(hWnd, SW_HIDE); // 有効化 EnableWindow(hWnd, TRUE); // 無効化 EnableWindow(hWnd, FALSE); // 表示されているか if(IsWindowVisible(hWnd)){ } // 状態の取得 WINDOWPLACEMENT wndpl; ZeroMemory(&wndpl, sizeof(wndpl)); wndpl.length = sizeof(WINDOWPLACEMENT); GetWindowPlacement(hWnd, &wndpl); |
他の関数内のwhile()ループを終了させたい時やプログレス バーにファイル読み込みの進行状況を表示したい時は、マルチスレッドを使えば良い。
マルチスレッドとは、複数のスレッドを使用したプログラム手法の事である。 スレッドを使用すると、処理が速くなるというメリットもある。 ただし、呼び出し元のスレッドは、呼び出したスレッドが終了する前に残りを処理してしまうため、スレッドがいつ終わったのか調べる必要がある場合もある。 作成されたスレッドの関数が、再帰構造のときは、再帰の深度をカウントすると終了時が分かる。 マルチスレッドは、MSDEV の設定後、process.h をインクルードし、_beginthread() でスレッドの作成、_endthread() で破棄を行う。スレッドは関数が終わると _endthread() が呼び出されるようになっているため、_endthread() は、途中終了したい場合にだけ使えば良い。 _beginthread() は、関数の引数を1つしか渡せないが、構造体のポインタを引数にすると複数の値を渡す事が出来る。 《MSDEV の設定》 [プロジェクト] メニューの [設定] をクリックします。[プロジェクトの設定] ダイアログ ボックスで、[C/C++] タブをクリックします。[カテゴリ] ボックスの [コード生成] をクリックします。[使用するランタイム ライブラリ] ボックスの [マルチスレッド] をクリックします。[OK] をクリックします。 |
#include <windows.h> #include <process.h> struct LOOP { int ct; // 現在のループ回数 int ct_max; // ループの上限値 }; HWND g_hWnd = NULL; bool g_bEnd = true; // スレッドが終了したら true void Count(void *pv) { g_bEnd = false; LOOP *lp = (LOOP *)pv; lp->ct = 0; while(lp->ct < lp->ct_max && !g_bEnd){ Sleep(10); (lp->ct) ++; InvalidateRect(g_hWnd, NULL, FALSE); } g_bEnd = true; InvalidateRect(g_hWnd, NULL, TRUE); } LRESULT CALLBACK ProcWnd(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static LOOP lp = {0,0}; switch (uMsg) { case WM_CREATE: g_hWnd = hWnd; return 0; case WM_KEYUP: switch (wParam) { case 'S': if(g_bEnd){ lp.ct = 0; lp.ct_max = 1000; InvalidateRect(g_hWnd, NULL, TRUE); _beginthread(Count, 0, (void*)&lp); } break; case 'E': g_bEnd = true; break; } return 0; case WM_PAINT: { PAINTSTRUCT ps; HDC hDC = BeginPaint(hWnd,&ps); char str1[256] = "[S]キーで開始、[E]キーで終了します"; char str2[256] = "終了!"; char str3[256] = ""; TextOut(hDC, 0, 0, str1, strlen(str1)); _itoa(lp.ct, str3, 10); TextOut(hDC, 0, 30, str3, strlen(str3)); if(lp.ct > 0 && g_bEnd){ TextOut(hDC, 0, 60, str2, strlen(str2)); } EndPaint(hWnd,&ps); } return 0; case WM_CLOSE: DestroyWindow(hWnd); PostQuitMessage(0); return 0; default: break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } |
|
自作ヘッダファイルが多い場合などに使用する
|
・未定義の場合にのみ定義したい場合。 ----- ヘッダファイルなどで --------------- #ifndef RED #define RED 0xFF0000 #endif ------------------------------------------- ・ヘッダファイルの再読を防止したい場合。 (定義済みであれば内容が処理されないことを利用する。 |
char result[256]; long r = (long) FindExecutable(sample.exe, "C:\\program1\\", result); 戻り値 32 以上 成功 0 メモリ不足 31 ファイルタイプが違う ERROR_FILE_NOT_FOUND 指定されたファイル名がない ERROR_PATH_NOT_FOUND 指定されたパスがない ERROR_BAD_FORMAT Win32アプリでないか、アイコンである または、 BOOL GetBinaryType ( LPCTSTR lpApplicationName,// ファイル名へのポインタ LPDWORD lpBinaryType// ファイルの種類を格納する変数へのポインタ ); |
ShellAbout(hWnd, "タイトル", "著作権情報", LoadIcon(hInst,MAKEINTRESOURCE(IDI_ICON1))); |
// 保存 #include <stdio.h> FILE *file; int n = 12345; if((file=fopen("sample.txt","w"))==NULL){ return 0; } fprintf(file,"%d\n",n); fputs("ABCDEFG",file); fclose(file); // 読み込み ---------- 最大 256バイトで、1行ずつ読み込む場合 ---------- #include <stdio.h> FILE *file; char s[256]; if((file=fopen("sample.txt","r"))==NULL){ return 0; } // while(!feof(file)) 内で、rewind、fsetpos、fseek、clearerr // は使用しない while(!feof(file)){ fgets(s,256,file); if(ss[strlen(ss)-1] == '\n'){ ss[strlen(ss)-1] = '\0'; } } fclose(file); ----- 全て一度に読み込む場合(\r\nは、\nに変換される) ----- #include <io.h> #include <fcntl.h> int file; if((file=_open("sample.txt",_O_TEXT))==-1){ return 0; } long size1 = _filelength(file); char *buf = new char [size1]; int size2 = _read(file,buf,size1); buf[size2] = '\0'; delete[] buf; _close(file); |
// 読み書きに使うデータ typedef struct{ int num; char str[64]; }DATA; DATA dt[16]; int ct = 5; for(int i=0;i<ct;i++){ dt[i].num = i; strcpy(dt[i].str, "abc"); } ------------------------------------ fopen関数を使う場合 -------------------------------- #include <stdio.h> // 保存 FILE *file; if((file=fopen("sample.dat","wb"))==NULL){ return 0; } // バイナリの書き込みにfprintf(),fputs() は使わない fwrite(&ct,sizeof(int),1,file); // 数値ctを保存 fwrite(&dt,sizeof(DATA),ct,file); // 配列dtを保存 fclose(file); // 読み込み FILE *file; if((file=fopen("sample.dat","rb"))==NULL){ return 0; } // バイナリの読み込みにfscanf(),fgets() は使わない fread(&ct,sizeof(int),1,file); // 数値ctの読み込み fread(&dt,sizeof(DATA),ct,file); // 配列dtの読み込み fclose(file); --------------------------------- CreateFile関数を使う場合 ------------------------------ // 保存 HANDLE hFile; DWORD dwWrite; hFile = CreateFile("sample.dat",GENERIC_WRITE,FILE_SHARE_WRITE, NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); if(hFile == INVALID_HANDLE_VALUE){ return 0; } WriteFile(hFile,&ct,sizeof(int),&dwWrite,NULL); WriteFile(hFile,dt,sizeof(DATA)*ct,&dwWrite,NULL); CloseHandle(hFile); // 読み込み HANDLE hFile; DWORD dwRead; hFile = CreateFile("sample.dat",GENERIC_READ,FILE_SHARE_READ, NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); if(hFile == INVALID_HANDLE_VALUE){ return 0; } ReadFile(hFile,&ct,sizeof(int),&dwRead,NULL); ReadFile(hFile,dt,sizeof(DATA)*ct,&dwRead,NULL); CloseHandle(hFile); |
----- 全て一度に読み込む場合 ----- HANDLE hFile; DWORD dwRead; hFile = CreateFile("sample.dat",GENERIC_READ,FILE_SHARE_READ, NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); if(hFile == INVALID_HANDLE_VALUE){ return 0; } DWORD size = GetFileSize(hFile, NULL); if(size > 0 && size != 0xFFFFFFFF){ char *buf = new char [size]; ReadFile(hFile,buf,size,&dwRead,NULL); delete[] buf; } CloseHandle(hFile); |
クラス内で使用すると解放時にメモリリークになるから注意。
put_value() が2つあるのは、オーバーロードというプログラミング技法である。
オーバーライドではない。
この項目のサンプル コードは、CPPファイルでコンソール アプリとして作成する
#include <stdio.h>
#include <malloc.h>
#include <memory.h>
void put_value(int **ppn)
{
int n[4][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
int x,y;
for(y=0;y<4;y++){
for(x=0;x<4;x++){
ppn[y][x] = n[y][x];
printf(" %2d", ppn[y][x]);
}
putchar('\n');
}
}
void put_value(int (*pn)[4])
{
int n[4][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
int x,y;
for(y=0;y<4;y++){
for(x=0;x<4;x++){
pn[y][x] = n[y][x];
printf(" %2d", pn[y][x]);
}
putchar('\n');
}
}
// 2つ目が固定の場合(malloc)
void two_dimensional_arrays1()
{
int (*pn)[4];
pn = (int(*)[4]) malloc(sizeof(int)*4*4);
put_value(pn);
free(pn);
}
// 2つ目が固定の場合(new 演算子)
void two_dimensional_arrays2()
{
int (*pn)[4];
pn = new int [4][4];
put_value(pn);
delete[] pn;
}
// 両方とも可変の場合(malloc)
void two_dimensional_arrays3()
{
int i;
int **ppn;
ppn = (int**) malloc(sizeof(int*)*4); // ←訂正(2012/1/6)
for(i=0;i<4;i++){
ppn[i] = (int*) malloc(sizeof(int)*4);
}
put_value(ppn);
for(i=0;i<4;i++){
free(ppn[i]);
}
free(ppn);
}
// 両方とも可変の場合(new 演算子)
void two_dimensional_arrays4()
{
int i;
int **ppn;
ppn = new int* [4];
for(i=0;i<4;i++){
ppn[i] = new int [4];
}
put_value(ppn);
for(i=0;i<4;i++){
delete[] ppn[i];
}
delete[] ppn;
}
void main()
{
// 2つ目が固定の場合(malloc)
two_dimensional_arrays1();
// 2つ目が固定の場合(new 演算子)
two_dimensional_arrays2();
// 両方とも可変の場合(malloc)
two_dimensional_arrays3();
// 両方とも可変の場合(new 演算子)
two_dimensional_arrays4();
printf("\nHit any key");
getchar();
}
|