TOP

VC++ まめ知識】

VC++に関するメモを気づいた時点で随時メモしておく私的なものです。

(以下は.NET+MFCアプリケーションが前提です。SDKな人には参考にはならないでしょう。)



◇ダウンロード

  [ツール類] デバッグ用のランタイムは再配布不可だそうなので
                 リリースコンパイルしてあります。
                 ※動かない時のおまじない

   ・最終更新   IP通信テスター(TCPIPサーバ、クライアント、UDPが可)
   ・最終更新   X25プロトコルテスター
   ・最終更新   インターフェース社製PCI4101ボード通信テスター
   ・最終更新   インターフェース社製PCI4161ボード通信テスター(COMポート通信テスターとしても動きます)
   ・最終更新   WAVファイル連結ツール



部品のダウンロードはこちら

◇TIPS
■VisualStudioのプロジェクト内にあるsuoファイルがDOS窓から見えない、消せない suoファイルは隠しファイルみたいです。 見る → dir /A:H 消す → del /A:H *.suo ■
静的リンク方法 ■iniファイルの利用 char buf[256]; GetPrivateProfileString("preference", "interval", "", buf, sizeof(buf), "./PandoraGoAhead.ini" ); ■画面の位置とサイズを変更する。 void CGyaoCalmDlg::PositionMe(int l,int t,int w,int h) { WINDOWPLACEMENT placement; this->GetWindowPlacement(&placement); placement.rcNormalPosition.left = l; placement.rcNormalPosition.right = placement.rcNormalPosition.left + w; placement.rcNormalPosition.top = t; placement.rcNormalPosition.bottom = placement.rcNormalPosition.top + h; this->SetWindowPlacement(&placement); } ■カレントディレクトリにある全ファイルを参照する WIN32_FIND_DATA wD; HANDLE wH = FindFirstFile(".\\mail_*.txt",&wD); if(wH != INVALID_HANDLE_VALUE) { if((strcmp(wD.cFileName,".") != 0)&&(strcmp(wD.cFileName,"..") != 0)) { AfxMessageBox(wD.cFileName); } while(1) { if(FindNextFile(wH,&wD) == 0) break; if(strcmp(wD.cFileName,".") == 0) continue; if(strcmp(wD.cFileName,"..") == 0) continue; AfxMessageBox(wD.cFileName); } FindClose(wH); } ■HTTP受信 int/*0:正常 -1:異常*/ CFortuneFinderDlg::GetPage(CString url,CString fname,CString key) { result.Format("INFO : No error"); CFile fp; unsigned char buf[2048]; int ret = -1; INTERNET_PORT port = 0; //ポート番号 DWORD stype = 0; //サービスタイプ DWORD atype = PRE_CONFIG_INTERNET_ACCESS; //アクセスタイプ CString obj = ""; CString server = ""; //--------- //接続 //--------- AfxParseURL(url, stype, server, obj, port); //URLの解析 CInternetSession session("Test Agent Ver0.01",atype); //セッションの生成 CHttpConnection* conn = session.GetHttpConnection(server,port); //コネクションの確率 int nverb = CHttpConnection::HTTP_VERB_GET; //リクエストの送信 DWORD dwInetFlags = INTERNET_FLAG_EXISTING_CONNECT; CHttpFile* pf = conn->OpenRequest(nverb, obj, NULL, 1, NULL, NULL, dwInetFlags); CString strHeaders =_T("Content-Type: application/x-www-form-urlencoded"); pf->AddRequestHeaders(strHeaders); pf->SendRequest(); DWORD dwRet; pf->QueryInfoStatusCode(dwRet); if(dwRet >= HTTP_STATUS_BAD_REQUEST) { result.Format("ERROR : Illegal HTTP status %d",dwRet); goto RETURN; } //--------- //ファイルへ保存 //--------- if(fp.Open(fname,CFile::modeCreate|CFile::modeWrite) == NULL) { result.Format("ERROR : Could not create file [%s]",fname); goto RETURN; } memset(buf,NULL,sizeof(buf)); while(long len = pf->Read(buf,2048)) { if(strstr((char*)buf,key) != NULL) ret = 0; fp.Write(buf,len); memset(buf,NULL,sizeof(buf)); } fp.Close(); RETURN: //--------- //後始末 //--------- pf->Close(); conn->Close(); session.Close(); delete pf; delete conn; return ret; } ■メモリリーク調査 _CrtSetBreakAlloc(デバッガでプログラム終了時に表示されるリークメモリアドレス); ■ブラウザを起動する char wbuf[512]; CString browser; GetCurrentDirectory(sizeof(wbuf),wbuf); CString URL; URL.Format("%s\\help\\index.html",wbuf); CWnd* pwnd = GetActiveWindow(); HINSTANCE RetVal = FindExecutable(URL, NULL, wbuf); browser = (CString) wbuf; browser.TrimLeft(); //両端のスペースを削除 browser.TrimRight(); long ret = (long)RetVal; if ((ret <= 32) || (browser.IsEmpty())) { AfxMessageBox("ブラウザが見つかりません",MB_ICONEXCLAMATION); } else { //ShellExecuteでブラウザを起動する strcpy(wbuf,browser.GetBuffer(browser.GetLength())); browser.ReleaseBuffer(); ShellExecute(HWND(pwnd), "open", wbuf,URL, NULL,SW_SHOWNORMAL); } ■タスクトレイにアイコンを表示させる #define WM_TRYCLK WM_APP + 3 //タスクトレイ化 NOTIFYICONDATA m_nIcon; //タスクトレイ化 afx_msg LRESULT CMaruankiDlg::OnTrayClk(WPARAM wParam, LPARAM lParam); //タスクトレイ化 BEGIN_MESSAGE_MAP(CMaruankiDlg, CDialog) ON_MESSAGE( WM_TRYCLK, OnTrayClk) //タスクトレイ化 : END_MESSAGE_MAP() BOOL CMaruankiDlg::OnInitDialog() { : //-------------- //タスクトレイ化 //-------------- m_nIcon.cbSize = sizeof(NOTIFYICONDATA); m_nIcon.uID = 1; m_nIcon.hWnd = m_hWnd; m_nIcon.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP; m_nIcon.hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); m_nIcon.uCallbackMessage = WM_TRYCLK; lstrcpy(m_nIcon.szTip,AfxGetAppName()); ::Shell_NotifyIcon(NIM_ADD,&m_nIcon); return TRUE; // フォーカスをコントロールに設定した場合を除き、TRUE を返します。 } //-------------------------- //タスクトレイ化 アイコンがクリックされた場合の処理 //-------------------------- LRESULT CMaruankiDlg::OnTrayClk(WPARAM wParam, LPARAM lParam) { CString strwork; switch(lParam) { case WM_LBUTTONUP: this->ShowWindow(SW_SHOW); break; } return 0L; } void CMaruankiDlg::OnClose() { ::Shell_NotifyIcon(NIM_DELETE,&m_nIcon); //タスクトレイ化 CDialog::OnClose(); } ■ウィンドウメッセージが届いているかを明示的にチェックして処理をさせる MSG message; while(1) { if(::PeekMessage(&message,NULL,0,0,PM_REMOVE)==0) break; ::TranslateMessage(&message); ::DispatchMessage(&message); } ■ダミーのウィンドウを作成してウィンドウメッセージを扱える様にする Create(NULL,NULL,WS_OVERLAPPEDWINDOW,CRect(0,0,0,0),GetDesktopWindow(),0); ■子ダイアログをnewする ~ヘッダにて~ CDialog* p_MaskL; ~ソースにて~ ・作る時  p_MaskL = new CDialog;  p_MaskL->Create(IDD_MASK, this);  p_MaskL->ShowWindow(SW_SHOW); ・消す時  delete p_Mask; 子画面側では以下をやっておく↓ ■newで作成した画面の資源開放を親ではなく子が自分でやる方法 void CADSchstat::OnCancel() { DestroyWindow(); } void CADSchstat::PostNcDestroy() { CDialog::PostNcDestroy(); delete this; } ■ファイル操作 一行づつ読む CString wstr; CStdioFile f_CMU(".\\CMU.txt",CFile::modeRead); while(f_CMU.ReadString(wstr) != NULL) { //処理 } f_CMU.Close(); ■STLのdequeで中間の要素をeraseする方法(イテレータを使う) #include std::deque queue; queue.clear(); queue.push_back(1); queue.push_back(2); queue.push_back(3); queue.push_back(4); queue.push_back(5); queue.push_back(6); queue.push_back(7); queue.push_back(8); queue.push_back(9); queue.push_back(10); std::deque<long>::size_type i; std::deque<long>::iterator iter; for(i=0,iter=queue.begin();i<queue.size();i++,iter++) { if(queue[i] == 5) { queue.erase(iter); break; } } CString wstr; CString msg=""; for(i=0;i<queue.size();i++) { wstr.Format("%d ",queue[i]); msg+=wstr; } AfxMessageBox(msg); ■ちょっとVCと関係ないけどDOSプロンプト(DOS窓)でバッチファイルを使って一定周期ごとにファイルを延々とftp転送する方法 --------ftp_auto_upload.bat----------- :START echo open 10.0.2.5>ftp_auto_upload.cat echo ftpuser>>ftp_auto_upload.cat echo ftpuser>>ftp_auto_upload.cat echo cd LCN1>>ftp_auto_upload.cat echo bin>>ftp_auto_upload.cat echo mput *.bin>>ftp_auto_upload.cat echo bye>>ftp_auto_upload.cat ftp -i -s:ftp_auto_upload.cat call sleep 60 GOTO START :END -------------------------------------- --------sleep.bat--------------------- @echo off REM Sleep.bat [秒数] set /a wtime=(%1+0)*1000 echo WScript.Sleep %wtime% > sleep_tmp.vbs cscript //NoLogo sleep_tmp.vbs del sleep_tmp.vbs set wtime= -------------------------------------- ■特殊キーが押されている場合の処理 if((::GetKeyState(VK_CONTROL) < 0 )&&(::GetKeyState(VK_SHIFT) < 0 )&&(::GetKeyState(VK_MENU) < 0 )) { //CTL+SHIFT+ALTが押されている場合 ■チェックボックスの状態を検査する CButon* wp; wp = (CButton*)GetDlgItem(IDC_CHECK1); if(wp->GetCheck()) { //チェックされていた場合 : ■モーダルダイアログボックスを作る モーダルな(他の画面をブロックする)子ダイアログボックスを作るには以下 CDialog* wp; wp = new CDialog(IDD_DLG_NOTE,this); wp->DoModal(); delete wp; ■「コピー中です」のダイアログを出しつつフォルダごとコピーする (SHFileOperationを使うが、非常に癖が強い。他の良い方法はないか?) 呼び出し側 strcpy(copyfrom,"..\\..\\log"); strcpy(copyto,"..\..\log_200501072125"); フォルダごとコピーする処理 char wdir[128]; memset(wbuf,NULL,sizeof(wbuf)); //(初期化を必ずしないとエラーとなる) if(copyfrom[1] != ':') { GetCurrentDirectory(sizeof(wdir),wdir); sprintf(wbuf,"%s\\",wdir); } strcat(wbuf,copyfrom); //(擬似絶対パス(先頭にドライブレターが必要。途中に相対パスが混入してもOK)でないとエラーとなる) strcat(wbuf,"\\*.*\0"); //「ドライブ名:\\~\\コピー元フォルダ\\*.*」を char wbuf2[256]; memset(wbuf2,NULL,sizeof(wbuf2)); //(初期化を必ずしないとエラーとなる) if(copyto[1] != ':') { char wdir[128]; GetCurrentDirectory(sizeof(wdir),wdir); sprintf(wbuf2,"%s\\",wdir); } strcat(wbuf2,copyto); //(擬似絶対パス(先頭にドライブレターが必要。途中に相対パスが混入してもOK)でないとエラーとなる) strcat(wbuf2,"\\\0"); //「ドライブ名:\\~\\コピー先フォルダ\\」へ SHFILEOPSTRUCT FileOp; ZeroMemory( &FileOp, sizeof(SHFILEOPSTRUCT) ); FileOp.wFunc = FO_COPY; //「コピー」、 FileOp.pFrom = wbuf; FileOp.pTo = wbuf2; FileOp.fFlags = FOF_NOCONFIRMATION|FOF_NOCONFIRMMKDIR; int ret = SHFileOperation( &FileOp ); //する if(ret == 0) { sprintf(wbuf,"%s にログを退避しました%d",wParent->copyto,ret); MessageBox(NULL, wbuf, "mainDisp", MB_ICONEXCLAMATION|MB_APPLMODAL|MB_OK|MB_SETFOREGROUND); } else { //キャンセルされた場合途中までコピーされてしまっているので削除する char wbuf3[256]; strcpy(wbuf3,wbuf2); ZeroMemory( &FileOp, sizeof(SHFILEOPSTRUCT) ); strcat(wbuf2,"*.*\0"); FileOp.pFrom = wbuf2; //「ドライブ名:\\~\\コピー先フォルダ\\*.*」を FileOp.pTo = wbuf2; FileOp.wFunc = FO_DELETE; //「削除」、 FileOp.fFlags = FOF_NOCONFIRMATION|FOF_NOCONFIRMMKDIR; SHFileOperation( &FileOp ); //して、 RemoveDirectory(wbuf3); //「ドライブ名:\\~\\コピー先フォルダ」も消す } ■部品を非活性(ボタンなら押せなく)/活性にする GetDlgItem(IDC_STATIC_LCN8/*部品ID*/)->EnableWindow(FALSE/*TRUEなら活性*/); ■パスを分解する char wdrive[16]; char wdir[128]; char wfname[128]; char wext[16]; _splitpath(wAttach,wdrive,wdir,wfname,wext); //フルパスを分解して、 strcat(wfname,wext); //ファイル名を得る ■ウィンドウメッセージを投げて処理を起動する #define WM_OPEN_MAP (WM_USER + 227) ON_MESSAGE(WM_OPEN_MAP, OpenMAP) LRESULT CDypMainFrame::OpenMAP(WPARAM wParam, LPARAM lParam) { : return (LRESULT)0; } 以上を用意しておいて、以下を実行するとOpenMAP関数が呼び出される PostMessage(WM_OPEN_MAP); ■メインフレームの「閉じる」ボタンおよびシステムメニューの削除 CMenu* pSysMenu = GetSystemMenu(FALSE); if(pSysMenu != NULL) { pSysMenu->DeleteMenu(SC_CLOSE,MF_BYCOMMAND); } ■ダイアログバーの作成 class CMyDialogBar : public CDialogBar { : } CMyDialogBar m_1STBAR; m_1STBAR.Create(this, IDD_1STBAR, WS_CHILD|WS_VISIBLE|CBRS_TOP, IDD_1STBAR); ■ボタンの表示位置を変更 WINDOWPLACEMENT placement; m_2NDBAR.GetDlgItem(IDC_BTN_SETTING )->GetWindowPlacement(&placement); placement.rcNormalPosition.left = startX; placement.rcNormalPosition.right = startX + wW; m_2NDBAR.GetDlgItem(IDC_BTN_SETTING )->SetWindowPlacement(&placement); ■ボタンにビットマップを貼り付ける CBitmapButton m_bb_UDR; m_bb_UDR.SubclassDlgItem(IDC_BTN_UDR,&m_2NDBAR); m_bb_UDR.SetButtonStyle(BS_PUSHBUTTON|BS_OWNERDRAW); m_bb_UDR.LoadBitmaps(IDB_UDR_UP,IDB_UDR_DOWN); m_bb_UDR.SizeToContent(); m_bb_UDR.Invalidate(); ■ダイアログバー上のコンボボックスに行を挿入 CComboBox m_combo_wopen; m_combo_wopen.SubclassDlgItem(IDC_CMB_WOPEN,(CWnd*)&m_2NDBAR); m_combo_wopen.InsertString(-1,"--Window selection--"); m_combo_wopen.InsertString(-1,"TRAFFIC DISPLAY"); ただし、最初は何度やってもうまくいかなかったのに、コンボボックスを一度削除 して作り直したらすんなり動いた。別のコツがあるような気もする。 それから、.NETのリソース画面上でコンボボックスをシングルクリックすると大き さを変更できるモードになるので、そこであらかじめのおおきさを広げておく必要 もあるみたい。これをやらないと行を挿入しても表示されなかったりもした。 ■子ダイアログ画面を作成する 初期化処理で以下 u_pCDlg_VHist = new CDypDlg_VHist; u_pCDlg_VHist->Create(IDD_VHIST, this); 終了処理で以下 if(u_pCDlg_VHist != NULL) { if(u_pCDlg_VHist->GetSafeHwnd() != NULL) { delete u_pCDlg_VHist; u_pCDlg_VHist = NULL; } } 子ダイアログ画面はなるたけstaticで作らず上記のようにnewして最後にdeleteする ように作った方がバグが出なくて安全。 ■タイマーの利用 適当にタイマーIDを定義する #define TI_LAMP 100 .NETのプロパティ画面「メッセージ」からWM_TIMERにハンドラOnTimerを追加する。 SetTimer(TI_LAMP, 500/*ミリ秒*/, NULL); void CDypMainFrame::OnTimer(UINT nIDEvent) { switch(nIDEvent) { case TI_LAMP: //ここにタイマー満了時の処理を書く : break; } } タイマーは一度セットするとKillTimer関数でキャンセル しない限り延々と呼び出される。OnTimer関数は手でコー ディングせず ■2重起動(多重起動)の防止 if (::FindWindow(NULL,"VDL3-TERM") != NULL) //タイトル名で同一画面が起動しているかを探す { return FALSE; } ■画面を探して殺す(終了メッセージを送る)場合↓ CWnd* hwnd; hwnd = FindWindow(NULL,"VDL3-SCENA"); if(hwnd != NULL) { hwnd->PostMessage(WM_CLOSE,NULL,NULL); } ■メニューバーの削除、ウィンドウスタイルの細かな設定、全画面表示、タイトルバーキャプションの設定 BOOL CDypMainFrame::PreCreateWindow(CREATESTRUCT& cs) { //メニューバーの削除 if(cs.hMenu != NULL) { ::DestroyMenu(cs.hMenu); cs.hMenu = NULL; } //ウィンドウスタイルの細かな設定 cs.style = WS_POPUP | //ポップアップスタイル WS_CAPTION | //タイトルバーあり WS_SYSMENU | //タイトルバー左端にアイコンあり WS_MAXIMIZEBOX | //最大化ボタンあり WS_MINIMIZEBOX | //最小化ボタンあり WS_THICKFRAME | //サイズ変更可 WS_VISIBLE; //初期状態で可視 //全画面表示 cs.x = 0; cs.y = 0; cs.cx = GetSystemMetrics(SM_CXSCREEN) -1; cs.cy = GetSystemMetrics(SM_CYSCREEN) -1; AfxGetApp()->m_nCmdShow = SW_MAXIMIZE; //タイトルバーキャプションの設定 cs.lpszName = "VDL3-TERM"; : return CMDIFrameWnd::PreCreateWindow(cs); } ■メッセージボックスの表示 if(IDOK == MessageBox("SURE TO EXIT?", "VDL3 COMMAND", MB_ICONEXCLAMATION/*ビックリマーク*/|MB_APPLMODAL/*ボタンが押されるまで待つ*/|MB_OKCANCEL/*OKボタンとCANCELボタン*/|MB_SETFOREGROUND/*最前面表示*/)) { //承諾 : } ■ソケット送信 send(Tcp_client.m_sock, (char*)&wOUT, sizeof(wOUT),0); ■スタティックテキストの表示文字変更 m_1STBAR.GetDlgItem(IDC_LBL_FREQD)->SetWindowText("OKOK"); ■WAVファイルの再生 sndPlaySound("..\\VDL\\sound\\pinpon.wav",SND_ASYNC/*バックグラウンドで鳴らす*/); ■システム時刻(JST)を獲得 SYSTEMTIME st; GetLocalTime(&st); //現在時刻を獲得し、 sprintf(wbuf,"%02d%02d%02d%02d", //HHMMSSmmに編集 st.wHour,st.wMinute,st.wSecond,st.wMilliseconds/10); UTCを獲得対場合はGetSystemTimeを使う。 ■前回起動時の子画面表示位置を再現する 子画面に対して.NETのプロパティ画面「メッセージ」からWM_MOVEにOnMove関数を 追加し、画面表示位置をファイルへ随時記録する処理を作る。 void CDypDlg_VHist::OnMove(int x, int y) { CDialog::OnMove(x, y); if(first_move == 1) { //画面生成初回にx=0,y=0のデフォルト位置でOnMoveが呼ばれることへの措置 first_move = 0; } else { WINDOWPLACEMENT placement; placement.length = sizeof(placement); GetWindowPlacement(&placement); //最小化になぜか対応がうまくできないので無効化する措置(最小化以前の位置が有効になります) if(placement.showCmd == SW_MINIMIZE || placement.showCmd == SW_SHOWMINIMIZED){ if(placement.flags == WPF_RESTORETOMAXIMIZED){ placement.showCmd = SW_SHOWMAXIMIZED; }else{ placement.showCmd = SW_RESTORE; } } if( (placement.rcNormalPosition.top > 0) && //妥当な位置情報でなくOnMoveが呼ばれる場合があることへの措置 (placement.rcNormalPosition.top < placement.rcNormalPosition.bottom) && (placement.rcNormalPosition.left < placement.rcNormalPosition.right) ) { FILE* fp = fopen("..\\VDL\\VHist_pos.txt","w"); if( fp != NULL ) { //位置保存ファイルへ記録する fwrite(&placement, sizeof(placement), 1, fp); fclose(fp); } } } } 親画面がこの子画面を表示する処理に以下を追加する。 WINDOWPLACEMENT placement; placement.length = sizeof(placement); FILE* fp = fopen("..\\VDL\\VHist_pos.txt","r"); if( fp != NULL ) { //位置保存ファイルがあったら読み出して反映する fread(&placement, sizeof(placement), 1, fp); if( (placement.rcNormalPosition.left == placement.rcNormalPosition.right) || (placement.rcNormalPosition.top == placement.rcNormalPosition.bottom) ) { //不正な幅値の場合は読み込まない } else { u_pCDlg_VHist->SetWindowPlacement(&placement); } fclose(fp); } ■外部アプリケーションや外部コマンドの実行 ①やり方1(非同期に動いてくれる) ShellExecute(NULL,NULL,"SCENA.exe",NULL,".\\",SW_SHOWNORMAL); ②やり方2(非同期に動いてくれる。CloseHandleしなくてもリークしない。なんでかわからないが。) char ntpserverpath[256]; STARTUPINFO SInfo; PROCESS_INFORMATION PInfo; GetStartupInfo(&SInfo); sprintf(ntpserverpath,"..\\..\\Freeware\\NTP\\client\\winsntpc.exe %s -ntp -timeout=3 -quiet",envsg.Getc("VDL_SERV_IP")); CreateProcess(0, ntpserverpath, 0, 0, FALSE, DETACHED_PROCESS, 0, 0, &SInfo, &PInfo); ③やり方3(同期して動いてくれる 結果は見ない) char wCommand[512]; BOOL bSuccess; STARTUPINFO si; PROCESS_INFORMATION pi; sprintf(wCommand,"xcopy.exe /I %s %s",copyfrom,copyto); memset(&si, NULL, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; bSuccess = CreateProcess (NULL,wCommand,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi); if (bSuccess != TRUE) return NULL; WaitForSingleObject(pi.hProcess, INFINITE); // 終了まで待つ CloseHandle(pi.hThread); CloseHandle(pi.hProcess); ④やり方4(同期して動いてくれる 結果メッセージをパイプを使って読み込む) HANDLE hPipe[2]; //実行する外部コマンドの出力を読み込むためのパイプ SECURITY_ATTRIBUTES secAtt; //セキュリティ情報(パイプの作成に必要) STARTUPINFO si; //起動条件 PROCESS_INFORMATION pi; //プロセス情報 char buf[256]; DWORD readLen; BOOL bChk; //--------------- //パイプの作成 //--------------- secAtt.nLength = sizeof(SECURITY_ATTRIBUTES); secAtt.lpSecurityDescriptor = NULL; secAtt.bInheritHandle = TRUE; CreatePipe(&hPipe[0],&hPipe[1],&secAtt,0); //--------------- //起動条件の設定 //--------------- memset(&si,NULL,sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USEFILLATTRIBUTE|STARTF_USECOUNTCHARS|STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; si.hStdOutput = hPipe[1]; //--------------- //外部コマンドの実行 //--------------- bChk = CreateProcess(NULL,"Iisreset /STOP",NULL,NULL,TRUE,0,NULL,NULL,&si,&pi); if(bChk != TRUE) { AfxMessageBox("外部コマンド起動失敗"); return; } WaitForSingleObject(pi.hProcess,INFINITE); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); //--------------- //外部コマンドから返された結果メッセージ(文章)を読み込む //--------------- bChk = ReadFile(hPipe[0],buf,sizeof(buf),&readLen,NULL); if(bChk != TRUE) { AfxMessageBox("結果読み込み失敗"); } else { buf[readLen] = '\0'; AfxMessageBox(buf); } //--------------- //パイプの破棄 //--------------- CloseHandle(hPipe[0]); CloseHandle(hPipe[1]); ■ファイル選択ダイアログを開いて選択されたファイルをメモ帳で開く //CFileDialog* fdlg= new CFileDialog(TRUE, NULL, NULL, OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR, // "システムログファイル(*.txt)|*.txt|すべてのファイル(*.*)|*.*||", this); //fdlg->GetOFN().lpstrInitialDir = "..\\VDL\\Log"; //デフォルトのパスを指定 //if(fdlg->DoModal() == IDOK) //{ // ShellExecute(NULL,NULL,"Notepad.exe",fdlg.GetPathName(),"..\\VDL\\Log",SW_SHOWNORMAL); //} //delete fdlg; // //注:この方法はNGでした。CFileDialogはたとえOFN_NOCHANGEDIRフラグをセットして起動してもファイルの選択中はカレントディレクトリが動いてしまう仕様のようです。 //  (ダイアログを閉じる時に戻しているだけみたいです。)なにかと危険なので↓のフォルダ選択ダイアログを使う方法をにしましょう。 int f_get; BROWSEINFO bInfo; LPITEMIDLIST pIDList; TCHAR path[512]; //フォルダ選択ダイアログ 準備 bInfo.hwndOwner = AfxGetMainWnd()->m_hWnd; //親ウインドウのハンドル bInfo.pidlRoot = NULL; //デフォルトパス(NULL:デスクトップ) bInfo.pszDisplayName = path; //選択されたパス受け取り用バッファ bInfo.lpszTitle = _T("保存先フォルダの選択"); //ダイアログに表示するタイトル bInfo.ulFlags = BIF_RETURNONLYFSDIRS | BIF_BROWSEINCLUDEFILES; bInfo.lpfn = NULL; bInfo.lParam = (LPARAM)0; RETRY: f_get=0; //フォルダ選択ダイアログ 表示 pIDList = ::SHBrowseForFolder(&bInfo); if(pIDList == NULL) { //キャンセル時 f_get=1; } else { //選択時 if(!::SHGetPathFromIDList(pIDList, path)) { //エラー時 } else { //パス正常時 if ((GetFileAttributes(path) & FILE_ATTRIBUTE_DIRECTORY) == 0) f_get=1; //選ばれたのはファイルなのか?フォルダなのか? } // pIDListのポイントしているメモリを開放する ::CoTaskMemFree( pIDList ); } if(f_get == 0) { AfxMessageBox("ファイルを選択して下さい"); goto RETRY; } GetDlgItem(IDC_EDIT_PATH)->SetWindowText(path); ■フォルダ選択ダイアログを開いて選択されたパスを表示する BROWSEINFO bInfo; LPITEMIDLIST pIDList; TCHAR path[512]; //フォルダ選択ダイアログ 準備 bInfo.hwndOwner = AfxGetMainWnd()->m_hWnd; //親ウインドウのハンドル bInfo.pidlRoot = NULL; //デフォルトパス(NULL:デスクトップ) bInfo.pszDisplayName = path; //選択されたパス受け取り用バッファ bInfo.lpszTitle = _T("フォルダの選択"); //ダイアログに表示するタイトル bInfo.ulFlags = BIF_RETURNONLYFSDIRS; bInfo.lpfn = NULL; bInfo.lParam = (LPARAM)0; //フォルダ選択ダイアログ 表示 pIDList = ::SHBrowseForFolder(&bInfo); if(pIDList == NULL) { //キャンセル時 } else { //選択時 if(!::SHGetPathFromIDList(pIDList, path)) { //エラー時 } else { //パス正常時 GetDlgItem(IDC_EDIT_PATH)->SetWindowText(path); } // 最後にpIDListのポイントしているメモリを開放します ::CoTaskMemFree( pIDList ); } ■プルダウンメニューの作成 ソースの頭にあるハンドラ定義に以下を追加 BEGIN_MESSAGE_MAP(CDypMainFrame, CMDIFrameWnd) : ON_BN_CLICKED(5401,OnClickENVINI) : END_MESSAGE_MAP() メニューを表示したい箇所に以下を記述 CMenu menu; menu.CreatePopupMenu(); menu.AppendMenu(MF_STRING|MF_ENABLED,5401,"BASIC ENVIRONMENT SETTING FILE"); CPoint point; GetCursorPos(&point); menu.TrackPopupMenu( TPM_LEFTALIGN | //クリック時のX座標をメニューの左辺にする TPM_RIGHTBUTTON, //→クリックでメニュー選択可能とする point.x,point.y, //メニューの表示位置 this //このメニューを所有するウィンドウ ); menu.DestroyMenu(); メニューが選択された時の処理として以下を追加 void CDypMainFrame::OnClickENVINI() { : } ■部品の色を個別に設定する 初期化処理ですきな色のブラシを(クラスメンバとして)作っておく m_Brush_Black.CreateSolidBrush(RGB(0,0,0)); //黒色のブラシを作成 .NETのプロパティウィンドウの「メッセージ」画面からWM_CTLCOLOR メッセージのハンドラOnCtlColorを追加する HBRUSH CDypMainFrame::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { HBRUSH hbr = CMDIFrameWnd::OnCtlColor(pDC, pWnd, nCtlColor); if(*pWnd == *GetDlgItem(IDC_LBL_NAME)) //この部品の場合だけ { pDC->SetBkColor(RGB(0,0,0)); //背景を黒に pDC->SetTextColor(RGB(255,255,255)); //文字を白に return (HBRUSH)m_Brush_Black; //塗るよ } return hbr; //それ以外は規定の色で } ■ビットマップを表示する 【ダイアログベースの場合】 クラスメンバとして以下を追加し、 CBitmap bmp_gray; プログラムから以下を呼ぶ 初期化処理にて bmp_gray.LoadBitmap(IDB_BMP_GRAY/*ビットマップリソースのID*/); 更新処理にて CStatic* wp = (CStatic*)GetDlgItem(IDC_PICT1/*ピクチャーコントロールのID*/); wp->SetBitmap(bmp_gray); 【MDI,SDIの場合】 以下の関数を追加する //---------------------------------------------------------- //ビットマップ表示用関数 //---------------------------------------------------------- int CDypMainFrame::BitDisp(CWnd* pItem, int bmp) { RECT wRect; int x,y,w,h; //描画領域の座標を獲得 pItem->GetClientRect(&wRect); x=wRect.left; y=wRect.top; w=wRect.right-wRect.left; h=wRect.bottom-wRect.top; CDC pM; CBitmap pB; CDC* pDC=pItem->GetDC(); pB.LoadBitmap(bmp); pM.CreateCompatibleDC(pDC); CBitmap* pOld = pM.SelectObject(&pB); BOOL ret = pDC->BitBlt(x,y,w,h,&pM,0,0,SRCCOPY); pM.SelectObject(pOld); pM.DeleteDC(); pB.DeleteObject(); pItem->ReleaseDC(pDC); pItem->Invalidate(); return 0; } .NETのリソースビュー画面からBitMapリソースを追加する 仮にIDC_BMP_GREENとして作ったとする。 画面にPictureControlの部品を配置する 仮にIDC_BMP_LSTA1として作ったとする。 BitDisp(IDC_BMP_LSTA1,IDB_BMP_GREEN); と呼び出すとIDC_BMP_LSTA1という部品上にIDC_BMP_GREENというビットマップ が貼り付けられる。



◇ リストボックス(CListBox)の項目(行)毎に色を変更する

オーナードローとかオーナー描画とか言われるやり方だそうです。

1.リストボックスのリソースで「Owner Draw=固定」に設定する。
2.MeasureItemメソッドとDrawItemメソッドをオーバライドするため
  ヘッダファイルに以下を追加する。
	virtual void		DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
	virtual void		MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
  (ウィンドウメッセージWM_DRAWITEMとWM_MEASUREITEMにハンドラ
  を追加するとOnMeasureItemとOnDrawItemというメソッドが出来る
  がそれをいじってもダメ)。
3.以下の様にハンドラを記述する。
void CADSOwnerDrawListBox4CHIST::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
  {
	// TODO : ここにメッセージ ハンドラ コードを追加するか、既定の処理を呼び出します。
	lpMeasureItemStruct->itemHeight = 10/*1行の高さを設定*/;
  }
  void CADSOwnerDrawListBox4CHIST::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
  {    // この関数はリストボックスに行を追加したり削除したりした際に行数の数だけ繰り返し呼び出される。
         if(lpDrawItemStruct.itemData == -1 || lpDrawItemStruct.itemData == NULL) return;
	CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
	pDC->FillSolidRect(&lpDrawItemStruct->rcItem, RGB(0,0,0)/*背景の色*/);
	pDC->SetBkColor(RGB(0,0,0)/*文字の後ろの色(背景と一緒にしとくべき)*/);
	pDC->SetTextColor(RGB(255,255,255)/*文字の色*/);
	pDC->DrawText(table[i].Msg/*lpDrawItemStruct->itemData*/,&lpDrawItemStruct->rcItem,DT_LEFT | DT_VCENTER | DT_SINGLELINE);
  }
4.あとは普通に行の追加とかすれば、この例の場合背景=黒、文字=白で表示される。
	wp->InsertString(-1,"ADDED");

ただしこれはあくまで例で、4の文字列"ADDED"の様にその場限りのデータでは実際は①で参照した時に消えてしまっているので、
必ずクラスメンバとしてバッファを取り、そのアドレスをInsertString等に渡してあげないとダメ。




◇ 画面表示更新をドドドっとやる時は

やり方1
SetRedraw(FALSE);
・・・CComboBoxへAddStringの嵐とか
SetRedraw(TRUE);
Invalidate();

やり方2
LockWindowUpdate
・・・CComboBoxへAddStringの嵐とか
UnlockWindowUpdate




◇ 右クリックメニュー(プルダウンメニュー)を作る

afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
BEGIN_MESSAGE_MAP(CpullDlg, CDialog)
	ON_WM_RBUTTONDOWN()
END_MESSAGE_MAP()
void CpullDlg::OnRButtonDown(UINT nFlags, CPoint point)
{
	CMenu menu;
	CMenu menuchild;
	menu.CreatePopupMenu();
	menuchild.CreatePopupMenu();
	menuchild.AppendMenu(MF_STRING, 100, "レベル2-1");
	menuchild.AppendMenu(MF_STRING, 101, "レベル2-2");
	menu.AppendMenu(MF_STRING|MF_ENABLED|MF_POPUP,
               (unsigned int)menuchild.m_hMenu,"レベル1");
	ClientToScreen(&point);
	menu.TrackPopupMenu(
		TPM_LEFTALIGN  |		//クリック時のX座標をメニューの左辺にする
			 TPM_RIGHTBUTTON,	//右クリックでメニュー選択可能とする
			point.x,point.y,	//メニューの表示位置
			this				//このメニューを所有するウィンドウ
			);
	menu.DestroyMenu();

	CDialog::OnRButtonDown(nFlags, point);
}



◇ メインフレームのハンドルを獲得する

メインフレームが自分から見て親なのか祖母なのかも
わからない場合は以下の方法で。
CWnd* pMainWnd = AfxGetApp()->m_pMainWnd;
CMainFrame* pMainFrame = (CMainFrame*)pMainWnd;



◇ タイトルバーのアイコンを消す

デフォルトで用意されるアイコンを後でいくら消しゴムで消しても変化なしです。
その場合は消しゴムで消したアイコンを別名でコピーして、
あとはその既存のアイコンのIDを呼んでいるところを全検索し、名前を書き換えれば
反映されます。バグ?



◇ コントロールのフォントを変更する

画面上の文字全部のフォントを一括で変更するなら
ダイアログのプロパティでフォントを設定する。
そうでないなら以下。

	CWnd *cwn;
	static CFont pFont;

	pFont.CreateFont(24, 12, 0, 0, FW_HEAVY, FALSE, FALSE,
						FALSE, ANSI_CHARSET/*SHIFTJIS_CHARSET*/, OUT_CHARACTER_PRECIS,
							CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY,
								FIXED_PITCH | FF_MODERN,
									"Hanzel Extended bold" );

	cwn=(CWnd *)GetDlgItem(IDC_STATIC1);
	cwn->SetFont(&pFont, TRUE);

もしくはもっと簡単に
	pFont.CreatePointFont(9*10, _T("MS ゴシック"));
	cwn->SetFont(&pFont,TRUE);



◇ 自分のウィンドウハンドルを取得するには?

MFC では、ウィンドウハンドルはほとんど意識せずに利用できますが、
API を直接呼び出す必要がある場合、ウィンドウハンドルが必要にな
るときがあります。
MFC で自分のウィンドウハンドルを取得するには CWnd クラスのメンバ
変数 m_hWnd や、メンバ関数の GetSafeHwnd() などが使えます。



◇ ボタンにビットマップを貼り付ける。


	CBitmapButton m_BmpBtn;

	m_BmpBtn.SubclassDlgItem(IDOK, this);
	m_BmpBtn.SetButtonStyle(BS_PUSHBUTTON|BS_OWNERDRAW);
	m_BmpBtn.LoadBitmaps(IDB_BITMAP1,IDB_BITMAP2);
	m_BmpBtn.SizeToContent();





◇ ラジオボックスを制御するには?



4つのラジオボタンが

○ ○
○ ○

と並んで、左上=A、右上=B、左下=C、右下=Dの場合、

【プロパティの設定】

    A:				B:
    ・Group: True			・Group: False
    ・ID   : IDC_RAIDO_A		・ID   : IDC_RAIDO_B

    C:				D:
    ・Group: True			・Group: False
    ・ID   : IDC_RAIDO_C		・ID   : IDC_RAIDO_D

    左をTrueに設定すると左右がグループ化される。これで自動排他制御される。

以下はボタンの状態を直接チェックするやり方
	初期化は以下
		CButton* wpb = (CButton*)GetDlgItem(regtbl[i].chkboxid);
		wpb->SetWindowText("");
		wpb->SetCheck(FALSE);
	チェックは以下
		CButton* wpb = (CButton*)GetDlgItem(regtbl[i].chkboxid);
		if(wpb->GetCheck() == TRUE)
		{		//チェックされている場合
			:
		}

以下はラジオボタンに変数を割り当てるやりかた
(*あとでソースが追いづらくなるのでやめたほうが良い。面倒でも「直接チェックするやりかた」にすべき)

【ヘッダファイルの設定】
    class CSCRTEST : public CDialog
    {
        protected:
            virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV サポート
        public :
            int m_iradio_a; ←A
            int m_iradio_c; ←C
    }

【ソースファイルの設定】

    IMPLEMENT_DYNAMIC(CSCRCntPara, CDialog)
        : CDialog(CSCRCntPara::IDD, pParent)
        , m_iradio_a(FALSE) ←A	
        , m_iradio_c(FALSE) ←C
    {
    }
    void CSCRCntPara::DoDataExchange(CDataExchange* pDX)
    {
        CDialog::DoDataExchange(pDX);
        DDX_Radio(pDX, IDC_RAIDO_A,   m_iradio_a); ←A	
        DDX_Radio(pDX, IDC_RAIDO_C,   m_iradio_c); ←C	
        /* ラジオボックスIDのリンク? */
    }
    グループ化したので片方のボタンだけ登録する。

【ラジオボックスの操作】

    m_iradio_a = 0;
    m_iradio_c = 0;
    UpdateData(FALSE);		/* 保存や終了する時は固定させるためにTRUEにする。*/
    ● ○
  ● ○

    m_iradio_a = 1;
    m_iradio_c = 1;
    UpdateData(FALSE);
    ○ ●
  ○ ●

  要は0が設定されたら自分にチェックが付き、1が設定されたらグループ化した相手にチェックが付く。





◇ ダイアログバーを作るには


  MDI画面にドキュメントを開く以外にダイアログバーを表示させておきたい様な場合は
  以下の様にします。

  ①.NETのメニュー「リソースの追加」→「ダイアログ」でダイアログバーに用いるテンプ
   レート図案を作ります。
   スタイル=子 境界線=なし ID=IDD_DIALOGBAR1(例)
  ②~MainFrm.hに CDialogbar m_dialogbar1; を追加。
  ③~MainFrm.cppの OnCreateの中で
   m_dialogbar1.Create(this,IDD_DIALOGBAR1,WS_VISIBLE|CBRS_TOP,AFX_IDW_TOOLBAR);

      //ドッキングバーにしたい場合は以下も。
   m_dialogbar1.SetBarStyle(m_dialogbar1.GetBarStyle()|CBRS_SIZE_DYNAMIC);
      m_dialogbar1.EnableDocking(CBRS_ALIGN_ANY);
      EnableDocking(CBRS_ALIGN_ANY);
      DockControlBar(&m_dialogbar1);

    これで自由にレイアウト変更ができるドッキンバー形式のメニューなんかが作れます。





				
TOP inserted by FC2 system