「私はド素人、内容には全く自身を持てません」状態からヨチヨチ歩き程度に上達できたと思う今日この頃なので、一旦内容を整理した。

VC++ ver.6 を使用中。

Win32API *

いわゆるSDKプログラミング。これを知らねばはじまらない

link *

メモ *

クリップボード *

DoEvents *

VB6でいうところのDoEventsは以下(なのだそうだ。出典は失念)

MSG msg;
if(::PeekMessage(&msg,NULL,0,0,PM_REMOVE)){
    ::TranslateMessage(&msg);
    ::DispatchMessage(&msg);
}

DLLを使う *

インポートライブラリを使ってビルド時に関数を参照する方法と、実行中に動的に関数を参照する方法とがある。

以前A社の計測装置を購入した際、USBによる操作用にDLLが添付されてきたことがあった(実はそれがお目当て)。しかし、言語のサポートとしてはVisual Basic用の標準モジュールのみで、インポートライブラリはもちろんCのヘッダもなかった。その時標準モジュールを参考にヘッダを書き、何とか動的呼び出しにまでこじつけたのが勉強したきっかけ。

お目当ての関数ポインタには、ちゃんと自ら型(引数、戻り値)を指定してやる。

DLLと .def ファイルがあればインポートライブラリが作れるみたいだ!? 中身は全く理解していないが

lib /def:my_def_file.def

とすれば .libができるみたい。実際にできた。The Code Project - CppSQLite - C++ Wrapper for SQLite - Databaseを参考にした。

IDEの操作 *

ジワジワと操作を覚え、ジワジワと便利になってゆくもの

メモ *

ライブラリ *

ある関数に必要なヘッダとライブラリはヘルプに記載されている。ヘッダは include すれば良い。ライブラリは

のいずれかで追加する(両者はどう違うのだ?)

デバッグ *

ステップオーバー
main routineのみのtrace。そこでcallされた関数内部に行かない
ステップイン
main routineでcallされた関数内部に行く。外部ライブラリのコードの海に突き進むことも。
ステップアウト
現在のroutineを抜けて呼出し元に戻る

全般的なこと *

link *

メモ *

同種のコントロールたちを、例えばVBのコントロール配列の様にして一括して処理したい *

以下VC++超初心者のホームページから。

自分で適当に配列を作って、コントロールIDを格納するのが(実装と理解の観点で)一番お手軽

グラフ *

SDKに限った話ではないが、VCでグラフを実現するのはそう簡単なことではなさそうだ。自分で描画することはできるが面倒くさいのでパス。そこで既存のものを使いたくなるわけだが、標準でついてくるのはMSChartくらい。VBから使うのは簡単だが、VCから使うにはかなりのクセモノである上に文書も少ない。定番がどれなのかもよくわからない。CodeGuruでも乱立してるみたいだ。

インストーラ *

National InstrumentsMeasurement Studioを使って、計測制御用のプログラムが使い慣れた言語でラクラク書けてとても幸せだが、成果物の配布にあたっては「インストーラを作りなさい」とのことであった。そういえばインストーラについては全く知らなかったのでWeb上の文書をひととおり調べた結果が以下。

WTL *

非常に大雑把にいうと「手動MFC亜種」。実行ファイルが軽いという利点がある。MFC、ClassWizardの動作を見つめなおすきっかけにもなる。

link *

メモ *

COM *

高度なテクノロジ。本腰入れて勉強しないと理解に至れない。

link *

メモ *

VARIANT、COleVariant、SAFEARRAY、COleSafeArray... *

便利なんだか不便なんだかよくわからないのでムカついていた時に参考にしたのが以下。

MFC *

業界標準のフレームワークだが、全くのWindowsプログラミング初学者が手を染めるべきではないと思う。(とりあえずは動作しても、何が何だかわからない状態になると思われる)

link *

メモ *

SDIウィンドウの作成 *

最初にAppWizardさんが作ってくれるが、後から自分で作りたい場合はどうすればよいか?

に記述が見つかった。指定するリソースIDのメニューを前もって作っておかねばうまくいかなかった。

CEditView *

CHtmlView *

COM絡み *

フォント *

フォントまわりは奥が深い。CreateFontの引数には泣きそうになる。よって、とりあえず動いたやつをメモとして貼る。CFontのメンバ関数とグローバルなAPIが同名だが、引数は同じっぽい。

CreateFont(20, 0, 0, 0, FW_NORMAL, FALSE, FALSE, 0, SHIFTJIS_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, _T("MS ゴシック"));

CFontなら以下のようなお手軽設定も可能。

hFont.CreatePointFont(15*10, _T("MS ゴシック"));

設定させるにはWM_SETFONTのwParamにHFONTをのせてやってメッセージを送る

HFONT hFont;
...
::SendMessage(hWnd, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE,0));

か、CWndのSetFontメンバを使って

SetFont(&hFont,TRUE); // CFont hFont;

とする。しかしCFontオブジェクトがローカル変数だとこれは失敗するので、CWndのメンバにしておくとよし。(ナレッジウェア Tips3 - SetFont)

リストビュー *

使用する際には、stdafx.hに Afxcview.h をインクルードしておくこと。リストビュー(CListView)は正体がリストコントロール(CListCtrl)なビュークラスだそうだ。ダイアログ等にリストコントロールを直接貼り付ける時と違い、スタイルはリソースから指定できない。「レポート」にするにはPreCreateWindow内で

cs.style &= ~LVS_TYPEMASK;
cs.style |= LVS_REPORT;

とする。その他SetExtendedStyleまわりはOnInitialUpdateに記述するとよし。(以上はClistViewの表示がうまくいかない・・・。における記述を引用)

ダイアログベースでEnter *

「MFCでEnterキーが反応してしまう」のやりとりを参考にしました。

ダイアログのデフォルト動作では、Enterによって終了してしまう。これを変えるには例えば以下のようにする。

BOOL CxxxDlg::PreTranslateMessage(MSG* pMsg)
{
    if(pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN)
        return TRUE;
    return CDialog::PreTranslateMessage(pMsg);
}

ユーザー定義メッセージ *

MFCではメッセージマップをClassWizardで楽々記述できるのが大変らくちんなのだが、ユーザー定義メッセージを扱う際には手動でなくてはいけない。

エディットボックスの表示更新のタイミングについて *

調べようと思ってとりあえず以下の文書を見つけたが、詳しい検証はしていない。

ワーカスレッドとUpdateData *

's'の初期化が'default'ラベルによって行われませんでした *

switch文を使っていたら上記のようなエラー(C2361)に遭遇した。あるcaseのみで使う変数をそこで宣言した場合に、残りのcaseでもスコープが残っているけどいいのか、というニュアンスなのだそうだ。こんな時は変数を宣言・使用している箇所をブロックの中に閉じ込めてしまえばよい。

・・・という内容を http://frog.raindrop.jp/knowledge/archives/000223.html にて学びました。

右クリックメニュー *

右クリックでポップアップメニューを出す方法を見て学んだ。このページに記述されていることではあるが、念のためこちらにも書く。何か処理をする(ハンドラを書く)ためにはメニューIDとハンドラとの対応をとってやらないといけない。このあたりはClassWizardにやらせるとラクだが、メニューIDを直接ソースに書くとClassWizardはそれに気づいてくれない。そこで、(実際にはどこにも使われないけど)メニューリソースをひとつ用意し、そこで適当な メニューIDを登録しておけばよい。するとClassWizardはそれを認識してくれるので、同じメニューIDを用いれば右クリックメニューのハンドラが楽に実装できる。

SDK雛型 *

シングルウィンドウ *

#include<windows.h>
const char lpClassName[]="SDKTemplate";    // window class

LRESULT CALLBACK WndProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp) {
    switch (msg) {
        case WM_COMMAND:
        switch(LOWORD(wp)) {
            //case BUTTON:
            //break;
            }
        break;
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        }
        return DefWindowProc(hwnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInst , HINSTANCE hPrevInstance , PSTR lpCmdLine , int nCmdShow ) {
    HWND hwnd;
    MSG msg;
    WNDCLASS winc;

    winc.style	= CS_HREDRAW | CS_VREDRAW;
    winc.lpfnWndProc = WndProc;
    winc.cbClsExtra = 0;
    winc.cbWndExtra = 0;
    winc.hInstance = hInst;
    winc.hIcon	= LoadIcon(NULL , IDI_APPLICATION);
    winc.hCursor = LoadCursor(NULL , IDC_ARROW);
    winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    winc.lpszMenuName = NULL;
    winc.lpszClassName = lpClassName;

    if (!RegisterClass(&winc)) return 0;

    hwnd = CreateWindow(
        lpClassName ,    // class name
        TEXT("My SDK") , // window name
        WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
        100 , 100 , // horizontal, vertical position
        200 , 200 , // width and height
        NULL ,	// parent window
        NULL ,	// menu
        hInst , // application instance
        NULL // window-creation data
    );

    if (hwnd == NULL) return 0;

    while (GetMessage(&msg , NULL , 0 , 0)) DispatchMessage(&msg);
    return msg.wParam;
}

ダイアログベース *

以上を参考に作成しましたが、理解不足に基づくミスを私が犯してる可能性は大いにあります。

#include<windows.h>
#include"resource.h"

BOOL CALLBACK DialogProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
{
  switch(msg){
  case WM_INITDIALOG:
    // initialize
    return TRUE;
  case WM_COMMAND:
    switch(LOWORD(wp)){
    case IDOK:
      EndDialog(hDlg,LOWORD(wp));
      return TRUE;
    case IDCANCEL:
      EndDialog(hDlg,LOWORD(wp));
      return TRUE;
    }
    break;
  case WM_CLOSE:
    PostQuitMessage(0);
    break;
  }
  return FALSE;
}


int WINAPI WinMain(HINSTANCE hinst,HINSTANCE hPreInst, LPSTR pCmdLine,int nCmdShow)
{
  DialogBox(hinst,MAKEINTRESOURCE(IDD_DIALOG1),NULL,DialogProc);
  return FALSE;
}