「オブジェクト指向の倒し方、知らないでしょ? オレはもう知ってますよ」

「オブジェクト指向の倒し方、知らないでしょ? オレはもう知ってますよ」

オブジェクト指向と公的教義の倒し方を知っているブログ
荀子を知っているブログ 織田信長を知っているブログ

近世日本の身分制社会 は 2025/09/29 168 で終了。

誤認の修正以外は現段階ではしない前提。後で一斉に全体を見直し、分量を集約したいが未定。

2025/11/24 から次議題 Windows プログラム C/C++ ( オブジェクト指向の規律絶対主義への否定 )開始。

01章 2025/11/24 : 02章 2025/11/27 : 03章 2025/12/04
04章 01/03 2025/12/13
04章 02/03 2025/12/30
04章 03/03 2026/01/12

Windows  C/C++ 検証報告プロジェクト:画面構成 WindowBuild 2025/01/12

 

- C視点および Window 標準 API 視点 -

 

※ ここでは、オブジェクト指向の規律および、マイクロソフト独自仕様が濃すぎてもはやC/C++ではないリソース/マクロはできるだけ除外しながら動作確認、正しいかどうかの前段階としての Windows プログラムを介しての Microsoft の内部的な仕組みの理解のための検証報告が、ここでの主目的となる。その初期準備の経緯は03章で説明している。

 

※ ここでは Windows 10/11 のPCが対象であることと、02章で紹介している Microsoft Visual Stutio Community 2026( 無料版 Visual C/C++ 開発環境 ) のインストール環境を前提に、話を進めている。


※ 当ブログでは 統合前時代 という言葉をよく使うため先に説明しておくと、これは Windows が 95 / 98 系と NT 4.0 / 2000 系が統合されることになった Windows XP よりも前のそれらの時代のことを指す。当ブログ筆者は NT 4.0 / 2000 の方での関わりが強かったことで 統合前 32 Bit 時代 といういい方をしている場合は、32 Bit 化本格発足となった NT4.0 以来の Windows API( 32 Bit 本格化当時の Windows 標準内部仕様 )の意味が強い。

 

Windows C/C++04章 WnidowBuild 02/03 の続きとし、Visual Studio Community 2026 がインストール済みで、前回案内の WindowBuild_2Progect.zip を表示・実行できること、Microsoft Spy++ の用法もざっと確認している前提で、記述していく。

 

当ブログでは、各当事者・各所それぞれで常に取り組まなければならないはずの次の段階に向けた軽重管理・概念整備( まずは上同士の上方修正の手本の作り合いによる、その上方修正を原本・元手とした年期計画的なきざみ下方修正 = 上同士視点の手本の作り合い )といえる敷居交流を前提としている。

 

当ブログの、なぜそうした方が良いといえるのかの解釈・意図の構築の仕方は、それは当ブログ筆者がたまたま統合前 32 Bit 時代から見渡してきた Microsoft の Windows 標準 API 史的、CRT 史的、UNICODE 対応史的な、ここ30年のOS内部仕様をざっと見渡しての、顕著だった統合期 Windows XP 以後の 64 Bit 化以降も進められてきた Microsoft のC原点回帰的な概念整理を検証報告的な参考とした上だということを、どういうことなのかをISO9000系善用重視の見渡し方で 01/03 と 02/03 の方でその経緯や前提を説明している。

 

本題に入り、wWinMain からの説明を始めるにあたり、前回は Windows C/C++ で気を付けなければならない Microsoft の多くの事情から伝えなければならなかったことで前回はそちら中心となったが、いったん要約しておくと

 

① Microsoft が各仕様ごとに用意しているそれぞれの専用変数型にいったん沿っておく前提の、変数型計画を推奨

 

② Windows C/C++ においての文字列処理は、MS-DOS 時代以来の旧 ANSI SHIFT-JIS マルチバイトについては外部ファイル等でに対応したい理由の個所は char 型による文字列処理をしても良いが、基本は WCHAR 型( TCHAR、wchar_t、LPWSTR )の方での Windows 推奨 UNICODE-16LE での設計を推奨

 

③ 実現できた前回設計に改善余地がいくらでもあることに気づいていながら、次の設計でそこを改良していく取り組みにおいて、実現最優先でそこへの時間と労力を惜しんでばかりいては一向に上達していかない。前回のままやよその実例任せの流用ばかりしているといつまでも上達しない、前回までの整理整頓の片付け( 概念整理 )ができていない分だけ、次の実現目標の設計規模がほんの少し高くなっただけで即、自分たちでどうしていいのか解らず壁にぶち当たるばかりの典型に陥る

 

※ Cステート内( if や for や while 等 )や手続き( 関数・プロシージャ )呼び出し内での、手続き呼び出しおよびキャスト( 変数型互換の見なし参照 )の複雑な多重化は、変数型計画、引き数・戻り値計画を概念整備し直す必要のある箇所の見落としの原因

 

④ 前回説明した Microsoft のC原点回帰的な Windows 標準 API 側の概念整理史 ① ② の経緯は ③ と関係して参考になるため、旧認識でも通るからと互換任せに軽視し続けるのではなく、Microsoft の変更に気づき次第いったん合わせておき、オーバーライドよりもラッパー概念優先の Microsoft の経緯にしてもなぜそうした方がいいのかを自身でも概念整理し、自身で理由を明確化していく

 

といった当ブログとしての概要・意図はざっと伝わっている前提で、プロジェクト WindowBuild の wWinMain の説明の続きに入る。

 

 

 

 

4. WindowBuild 手続き( 関数・プロシージャ )呼び出し

 

 各手続きや各構造体が、Windows C/C++ に慣れていないとそのプロジェクト内で定義されたものなのか、それとも API 側や CRT 側のものなのか判別しにくいからこそ、手続き名や変数名や定義名の工夫も大事になってくる。

 

 WindowBuild はプロジェクト内定義として、メインソース.cpp 上部の前方宣言群の方で

 

 

 

 

プロジェクト内手続きの定義をしている。

 

WindowBuild 手続きの引き数に const( 参照のみ指定。変数内容の変更を禁止する指定 ) を使っているが、これは API の CreateWindow の引き数に充てる際の、特に引き数に充てる変数の型違い厳格化が年々強まっているコンパイルでの警告に対応するためのキャストを減らすために変数型を合わせることが目的で、そうした理由がない場合は当ブログでは積極に const を使うことはしないことにしている。

 

しかし今見ると、ここでは3個目の const WCHAR *( 引き数としては5個目。最後の引き数 )は const にする必要が無かったのをすっかり直し忘れてしまっているが、そうする必要がなかったのにそうしている箇所はその時は些細でも、こうしたひとつひとつを軽視の見落としの姿勢が変数型計画の弊害、再細分化・再集約化の不備、意義の乏しい残骸の体積が弊害化を生みやすくなるため、前回の設計では直さなくてもそういう所に気づき次第に次の設計では、積極的に改善していく前提を常にもっておくことが上達差になる。

 

2の赤枠の FilesCSV 群手続きは、WindowsBuild 手続きによって画面構成処理が行われる際に、CSV 式のテキストファイルを参照するための各処理になる。

 

FileCSVOpen 手続きはテキストファイルの参照準備だが、そのフォーマットが 旧 ANSI SHIFT-JIS 型( MS-DOS 時代以来の半角1バイト全角2バイトの旧マルチバイト式 )か、現推奨の国際 UNICODE 式( 全2バイト )かの初動の判別処理もしている。

 

FilesCSVRecode 手続きは参照テキストファイルの件数( レコード数 )を確認するための処理、FileCSVRead は参照テキストファイルから1項目情報( コード )ずつ順番に取得する処理、の、それぞれの手続き前方宣言になる。

 

 

 

 

※ 当 WindowBuild プロジェクトでは、F1 ~ F3 キーによって、画面構成の情報テキストファイル WindowBuild01.txt ~ 03.txt を参照する動作になっているが、1レコードあたり( 1件あたり )計7コード( 7項目 )というデータ構造 その情報群では1件あたりのその単位構造としての設計。テーブル配列的な単位概念 )となる。こちらの WindowBuild03.txt の場合では、レコード総数は全部で24件になる。

 

※ プログラム設計の上達のコツとして、多くの場合は

 

 ① まずは目的企画を、データ設計( および変数名・変数型計画 )優先で全体を仕様想定していく

 ② 情報群側( データ想定計画 )を何度も見直しながら、情報群の都合優先でプログラム側がそれに対応していく

 

という基本的な順番が重要。いったん組み立ててみた時に大変だと感じて息切れを起こしている時点で今回分でのその基本手順による改善余地がいくらでもあることを意味しているいくらでも改善余地のあるはずの今回分は次回に向けて、できそうなところから見直して段階的に改善点を反映していくことも怠ってはならない。所詮は実現できた止まりの前回分までの正しさを理由に、前回分を次にそのままたらい回し続けるのみではいつまでも上達せず、次の目標規模がほんの少し上がっただけで毎度の息切れとつまづき体質を繰り返す典型になる。当初の情報項目の想定設計から、概念名称および意味合いの改良がほんの少し加えられるだけでも関連を大幅に直さなければならなくなるのも常、ざっと作ってみるからこそ次の段階の改善余地があちこち見えるようになる。次に向けてのその積極的な見直しによる再細分化と再集約化を面倒がっているようではいつまでも上達しない

 

 どうしていいのか解らず錯乱気味につまづいている場合というのは、データ側の見直しをせずにプログラム側を直したくないという不都合優先をデータ側に合わせさせようとしている、つまり本来の順番を力関係任せにねじ曲げる偽善解釈 低次元序列権威体質 )が改められていない典型をまず疑った方がよい。データ構造側はいわば議題的な材料性質、プログラム構造側はいわばその解釈対応体質だからこそ、扱う題材対象の改良や拡張( のための再細分化・再集約化 )をしようとすると、必然的にそれを解釈対応するために、旧受態( プログラム側の旧設計観 )から、次の段階の互換/非互換( 旧廃策 = 浪費権威の残骸が弊害化し続ける旧態時代の正しさの集約消滅 )の概念整理・配置転換もその分だけ進めなければならない。そこを以前通りのケンカ腰のねじ伏せ合いにいつまでも固執し続ける旧態偽善解釈体質をモタモタ続けようとするから、ちょっとした次世代認識が迫られるたびにいとも簡単に精神的支柱を崩壊させ合いつまづく有様、年期計画的な準備要領以前のまずその認識ができるようになるまでに5年も10年かかる手のかかる有様の、まさに教育機関のただのいいなりおよびオブジェクト指向の規律のただのいいなりの気の小さい知能障害の集まりどもの姿そのものの典型に陥るのである。

 

今回の改善余地はどこまでを今回で対応するのか、どこからを次回以降で対応していくかの折り合い( 今後のバージョンアップ想定といえる Ver 1.0 から 2.0 へ向かう過程の自分たちの 1.1 単位 1.01 単位の境界管理・領域敷居管理 )を付けながら進めなければならないのが常、そこへの選任評議敷居( ISO9000系善用 )の地道な向き合いこそが結局は、次第に設計全体の質の向上のコツを、余裕をもって見渡していけるようになる次の段階への上達の近道になる。

 

3の赤枠の定数群は、画面に設置される文字/数字入力項目やボタンなどそれぞれの、役割ごとの処理分けの番号設計になる。

 

#define( デファイン ) はあくまで記述上の代替マクロで、こうした慣例的な定数代替の使い方の他にも、例えば HDC hDC = CreateCompatibuleDC( hWnd ); という API 手続き名の記述が長いからと、手続き名の部分を API_CDC( hWnd ); といった代替記述化という使い方や、if 等のCステートの書式自体の代替的な使い方もできるが、目先の記述をただ楽にすること自体が重要なのではない、そこを 錯覚 してはならないことに要注意。

 

どの機能の使い方でも同じことがいえるが、プログラム設計としての概念整理に何ら結び付かない安易な使い方は、設計理念としての階層工程の再細分化・再集約化になっていないにも拘わらず施行した気・使いこなしている気に 誤認・錯覚 し始める原因、Microsoft の概念整理の参考でもない、むしろ概念名設計による強調付けに反する使い方にしかなっていない #defile の代替乱用は、プログラム設計における概念整理から乖離化させる原因となる。

 

#define は、当例のように慣例的によく使われてきた定数の使い方なら想定の概念整理として有用だが、その他の #define の使い方は当ブログでは推奨しない。

 

※ Windows 標準 API の手続き名をただ短くしたいだけだったり、記述を短くするだけのCステート内や手続き呼び出し引き数内での手続き呼び出しの多重化など、安易な理由ではなく概念名による軽重管理の想定設計も大事だということを忘れてはならない。つまり Windows の仕様に介入的な狙いの概念名の場合は、例えば複数の Windows 標準 API を掛け合わせたちょっとした小フレームワーク試行( 形態構成 )としてのち dll 化も視野の、概念名統制の小言語設計の視野くらい考慮してみなければならない。

 

 

wWinMain の4の赤枠の、WindowBuild 手続き呼び出しの方に話を進めるが

 

 

 

 

まずA赤枠の API の CreateWindowW は、メインウインドウ作成だが、当ブログ筆者の場合、手続き呼び出しの際は、その手続き名およびその引き数がいくら横に長くなったとしても、横1行で書き切る場合が多い。

 

しかし例えば、

 

HWND hWnd = CreateWindowW

(

    chNameEntry,                               // コメント01

    chNameWindow,                         // コメント02

     WS_OVERLAPPEDWINDOW,  //  コメント03

     CW_USEDEFAULT,                      // コメント04

     0,                                                      // コメント05

     CW_USEDEFAULT, 0,                // コメント06

     nullptr,                                          // コメント07

     nullptr,                                          // コメント08

     hIns,                                              // コメント09

     nullptr                                          // コメント10

 );

 

という Microsoft Learn での案内に似た記述の仕方も可能で、API や CRT に慣れない内の概念整理のひとつの手になる。

 

※ API = Windows の各機能に働きかけるための手続き群。Windows.h 等

※ CRT = Cの定番処理の手助け・補佐のための手続き群。stdio.h 等

 

CreateWindowW が正常に作動したかどうかを、次の if で判定している所は、見本ではここが if( !hWnd  ) という方式にしているが、C/C++の旧慣例からも変数に ! のみの if の使い方がやけに見られるが、当ブログ筆者は原則それは用いないようにしている。

 

変数に ! をつけただけの if( ! 変数 ) は if( 変数 ==  0 ) または if( 変数 == false ) の機械語 jze ゼロイコールジャンプを意味するが、このC旧慣習は当ブログ筆者は意義・象形( 概念整理 の軽視と見なし、その場合は if( 変数 == 0 ) なのか if( 変数 != 0 ) なのか、また if( 変数 == true )なのか if( 変数 == false ) なのか、当ブログでは概念整理の一環としてそこを面倒がらず明記していくことを前提としている。

 

意義・象形重視だとここは if( hWnd == nullprt ) と記述したい所だったが、nullptr も0も同じことではあるが、デスクトップアプリケーションの見本の方を意識しながらそれを伝えようと、ここでは0で記述することにした。

 

Bの赤枠 は、テキストファイルからの読み込みで画面構成をしていくための設定値群および判定値群で、この WindowBuild 手続き( 関数・プロシージャ )内での完結でよかったため、ここで小仕様文書的な記述もしておいた。

 

ここでの設定値群/判定値群のための各変数は、const は使っていないもののそれがついている前提の、const を使うかどうかはともかくの const を使わなくてもそれが参照用変数かどうかの、用途・意図の一貫性や強調性からの概念整理の整然性をもたせていく、なぜそうしているのかを伝えやすくする姿勢が、上達の近道になる。

 

まず、手続き 内 においての変数の設置の仕方は、使い回せることを理由に変数の設置を控えるようなことはしない方がよい、逆に、ほんの少しのためだけであっても概念別ごと・各処理箇所ごとにその処理専用ごとに変数を積極的に設置していくようにした方が、概念整理に結びつく場合が多い。

 

API 手続きにしても CRT 手続きにしてもプロジェクト内手続きにしても、戻り値を受け取るための変数型が同じだからと、戻り値を受け取るためのその手続き内での変数をひとつ用意してそれを使い回すという共用の仕方は、受け取る関連性が強ければ共用してもいいが、同じ戻り値の変数型で一時的なものだから、という理由で使い回すのではなく、関連別観がある場合は面倒がらずにその仕様別ごとに変数を設置した方が概念整理に結び付きやすい。

 

その方針でその手続き内の変数が増えていくといっても、仮に50個100個と変数を設置することになろうが、合計で1000バイト分2000バイト程度の変数の設置ごときで Windows 側のメモリ量の圧迫や処理速度の重荷になることなどは、統合前 32 Bit 時代当時のPCでも皆無、別章で紹介予定の DIB 設計時での一部例外は除いて、大抵の場合は、手続き内変数の場合は増やす分には負荷的な支障になることはほとんどない、共用変数( どの手続きからも参照できるグローバル変数 )の概念整理の場合( 順述 )と違って、手続き内での変数の設置は、その変数が手続き外に直接影響を与え合うことの無いその中での完結の変数だからこそ、その手続き内においての概念整理を優先に遠慮せずに、いくらでも変数を設置してしまってよい。

 

※ 手続き内での変数設置は、関連別性次第に、面倒がらずに各処理専用の変数を積極的に設置していく作りにしておくと、各処理単位の再細分化・再集約化どころを見つけやすくするきっかけにできる。概念ごとに面倒がらずに積極的にその処理用の変数をそれぞれ設置しておくことで、その部分を丸ごと移動させやすい形が自然に作られ、処理の順番の入れ替えをしやすくさせたり間に拡張処理を入れやすくする整然さが出てきて、どの部分をどう改良すればいいのかも見つけやすくなる。

 

※ 手続き内に設置されていく変数( データ計画側 )はいわば、用途別の配線や通用路などの概念整備( 再細分化・再集約化 )のためのものでもある。その概念別単位の役目・配置転換による解釈対応側( プログラム計画側 )の見直しが手間だからと、変数( 小情報群設計 )および変数型計画の都合優先でプログラム側を直さなければならない( 本来はそうしなければならない )のを面倒がり、そこを疎かにごっちゃにいい所取りに兼用できている気に、直さなくてよいことにする偽善曲解任せ・力関係任せ体質にし続けてしまっている箇所は概念整理不足・想定不足の欠陥患部になりやすい。所詮は目先の利害体質の欠陥患部だからこそその時にその患部しか見ようとしなくなることが原因の、関連全体の見直しなど皆無ないわゆるスパゲッティコード症状の典型を引き起こし、次の段階への壁にぶち当たってばかりの、要するに原因の矛先をはき違えてばかりの常に息切れとつまづき体質から抜けられない典型になる。Microsoft としてもC原点回帰視点では、誤認の弊害化をさせやすくしてしまうその難しさ厄介さがよく解っているからこそ、だから大元の各根底仕様ごとの専用変数型や手続き名のあり方などの概念整備を進めてきたのである。ここは何にでもいえる目的構築性・組織構想性の上同士視点のまさに問われどころだからこそ、教育機関およびオブジェクト指向の規律のただのいいなりどものような、目先の利害次第に何もかもをスパゲッティコード症状の悪化に向かわせ合うことしか能がない、自分たちのその愚かさだらしなさも自分たちで改善( まずは上同士の上方修正を元手とする年期計画的なきざみ下方修正の次世代選任評議序列敷居化 できたことがないその上同士失格の怠慢の顔色を、だから当ブログでは上から順番に厳しさを上乗せのその踏みにじりを前提としているのである。

 

※ 一方で共用変数と共用手続きの設置の想定計画の方は、手続き内完結の変数とは性質が真逆、概念整理不足分の不都合の悪影響を共用手続き間で与え合いがちになる。概念名称計画や引き数/変数型計画が曖昧になり始めた改善余地のある共用変数や共用手続きの、その概念整理不足の残骸を解消するのに手間取ったり後回しにし続ける分だけ環境改善や上達の遅れになるからこそ、今回分の改善余地に気づき次第に、次回に向けてできる所からの再細分化・再集約化を怠ってはならない。実際やってみるとよく解ると思うがまず手続き 内 の場合は、逆にどれだけ変数の設置を増やすことができるのかくらいの意気込みでやってみると、変数を増設する意味が実際にどの程度あるのか、また思っていたほど増えなかったことが積極的に確認されていくことで、箇所ごとの軽重・概念区別を見渡しやすくする形が自然に作られるようになる。次第にどの場合にどのような変数の設置の仕方をすればいいのかのコツが身についていき、結果的に共用変数の設置、プロジェクト内共用手続きの設置の方の概念整理にも結びつくため推奨。

 

プログラム説明を進め、WindowBuild 手続き内の画面構成用の変数情報群の設置の、そのすぐ次の外部テキストファイルによる画面構成の様子について、ざっと説明していく。

 

 

 

 

画面構成のためのテキストファイル読み込み処理として、プロジェクト内手続き( 関数・プロシージャ )として FileCSVRecode、FileCSVOpen、FileCSVRead の3手続きを用意、メインソース上部に前方宣言をしている。

 

 

 

この3手続きの内部の説明は省略し、

 

 ・FileCSVRecode  テキストファイルの画面部品の設置件数( レコード合計数 )を取得

 ・FileCSVOpen   テキストファイルの項目( コード )取得の開始準備および、そのテキストファイルが UNICODE-16LE( Windows 推奨 全2バイト国際コードテキスト ) か 旧 ANSI SHIFT-JIS( MS-DOS 時代以来の半角1バイト全角2バイト旧テキスト )を判別

 ・FileCSVRead  FileCSVOpen で指定したテキストファイルから、この処理が行われるごとに次の1項目分を取得

 

していく処理となる。

 

Cの1赤枠でまず設置する部品の件数を取得。

 

Cの2の1赤枠で部品件数分のウインドウハンドルおよび役割番号の保管数を確保。

 

Cの3の1赤枠は画面の大きさを測定的に管理する用の変数で、3の2赤枠の方で、最も右下に向かった部品のその大きさを足した値を最大値( Left と Top の位置が最も深い部品の、その Width と Height を足した値 )と見立て、この値を元手に最終的な画面の大きさに見なす作りにしてある。

 

Cの4赤枠が1項目ごとの情報読み込み開始、Cの5赤枠は、1赤枠で事前に取得しておいた件数分で、部品情報の読み込みおよび設置の繰り返し。

 

Cの6赤枠でまずは1項目の取得で、ここは作りが少しややこしいが、情報群設計として1項目は SL、BL、BU といったその部品が入力項目なのか等の種別を取得し、その判別および参照用パラメーター式の判定的な振り分け処理をしているだけだが、C/C++に不慣れな場合はBの赤枠の情報群を意識しながら、Cの5赤枠の for の行数表記左枠の所にブレークポイントを設置し、F5 キーデバッグモードでここから F10 キーを押しながら変数の中がどうなっているのかをひと通り見てみると、何が起きているのか解りやすい。

 

Cの7赤枠 と Cの2の2赤枠は単純で、1件あたり合計7項目の内の残り6項目の読み込み、ここで API  WindowCreateEx に必要な情報が整うことより、API で部品設置を行うと共に、ウインドウハンドルとその役目番号の管理変数に保管。

 

※ Cの7赤枠 の所での概念整備として、ここは Left Top Width Height と単純だからと

 

int iPos[ 4 ];

for( int iCnt = 0; iCnt < 4; iCnt = iCnt + 1 )

{

    iPos[ iCnt ] =  FileCSVRead( &fCSV, chRead, iReadWorkSize, bUnicode, true, true );

 }

 

のようにすればいいと思いがちだが、少し例外的な DIB 設計の事情の負荷対策のためにやむなくその部分だけは処理速度優先の最適化をしなければならない、という理由がない普段は、処理ごと用の変数および変数名重視の作りにしておいた方が概念整理に結び付きやすい。実際、ここの画面構成の処理自体は Windows 95 / Windows NT 4.0 浸透期の Pentium 100 Mhz ~ PentiumⅡ 200 Mhz CPU 時代でも大した負荷もなく完了できるような軽さで、1件あたりの情報項目数がだいぶ多くなるといった理由がなければ短縮化に熱心になる必要はない。例えば何らの拡張理由で Left Top Width Height を1件あたり3セット分の情報項目が続くという仕様になった場合は、

 

int iLeft[ 3 ]; int iTop[ 3 ]; int iWidth[ 3 ]; int iHeight[ 3 ];

for( int iCnt = 0; iCnt < 3; iCnt = iCnt + 1 )

{

     iLeft[ iCnt ] =  FileCSVRead( &fCSV, chRead, iReadWorkSize, bUnicode, true, true );

     iTop[ iCnt ] =  FileCSVRead( &fCSV, chRead, iReadWorkSize, bUnicode, true, true );

     iWidth[ iCnt ] =  FileCSVRead( &fCSV, chRead, iReadWorkSize, bUnicode, true, true );

     iHeight[ iCnt ] =  FileCSVRead( &fCSV, chRead, iReadWorkSize, bUnicode, true, true );

 }

 

のような作りにしておいた方が概念整理がしやすくなる。前者のやり方で4の部分を12にすればよいという場合、その仕様に向き合っている近日は細部仕様を把握していられるが、1年も2年も経って再利用しようとその部分を見直した時、前者の作りよりも後者の変数名重視の作りにしてあった方がそこで何が行われているのかを思い出しやすくなり、第三者への伝えやすさにもそのまま直結する。第三者に見せるかどうかはともかくの、その伝えやすさに優れた作りができているほど、参考にし合える概念整理になっていたり、全体の改善余地を見つけやすい作りに向かわせていることを意味する。

 

もし前者のような作りからの3セット分拡張対応なら、方式としては少し強引かも知れないが例えば

 

struct RectPos
{
    int iLeft;
    int iTop;
    int iWidth;
    int iHeight;
};
 
RectPos stPosition[ 3 ];

  ・

  ・

  ・

int *pSet = ( int * )stPosition;
 

for( int iCnt = 0; iCnt < 12; iCnt = iCnt + 1 )

{

    pSet[ iCnt ] =  FileCSVRead( &fCSV, chRead, iReadWorkSize, bUnicode, true, true );

}

 

のような作りにしておくのも手になる。

 

int 型の変数4個の構造体の、その3配列分の定義は int 型変数が合計12個並んだデータ構造という見なし方で、この場合だと pSet[ 0 ] が stPosition[ 0 ].iLeft に、pSet[ 4 ] が stPosition[ 1 ].iLeft に、 pSet[ 8 ] が stPosition[ 2 ].iLeft に相当する。扱う項目数が多くて大変な場合、少し機械語的な変数型・バイト数計画になってしまうがこうした方法も手になる。

 

当プログラムでは、動作中に F1 ~ F3 キーが押されると、各対象のテキストファイルが読み込まれて画面が再構成される作りにしてあるが、その際にはCの2の1、Cの2の2でのウインドウハンドルと役割番号の g_ の保管変数これらは、その初期化がプロジェクト内手続きの CloseWindowAndAlloc 手続きの方で先に行われてから、この手続き処理が今一度行われ、画面が再構成がされるという手順になっている。

 

テキストファイルによる画面構成部分の、次の続きに進むが

 

 

 

 

C8赤枠は、画面構成時に適した画面の大きさを計るための手続き内変数 iWindowMaxWidth、iWindowMaxHeight を元手に、画面表示位置を中央に表示させるための演算的な処理だが、Windows C/C++ に慣れていないとそれが API 手続き呼び出しなのか CRT 手続き呼び出しなのかプロジェクト内手続き呼び出しなのかの判別がしにくくてややこしいが、ここで呼び出される CreateCompatibleDC、GetDeviceCaps、DeleteDC、SetWindowPos いずれも Windows 標準 API の手続きになる。

 

C9赤枠は、部品設置として発行されたウインドウハンドルを介して、全て画面に表示させる処理で、ここの ShoWindow、UpdateWindow 手続きも Windows 標準 API になる。

 

C9赤枠までが画面構成に関する処理、C10赤枠は画面構成後の初期設定的な処理群で、SetFocus が Windows 標準 API、WndCategorySearch と WndProc はプロジェクト内手続きになる。

 

C10赤枠は、MFCだとMicrosoft の内部リソースマクロ側で大抵は自動的に処理してくれる部分だが、当ブログのように非MFC前提だと手動で処理しなければならない部分で、妥当な方法なのか解らないがこういう作りにしてある。

 

※ Windows 標準 API はどういった場合に使う手続きがどう用意されているのか、Microsoft はMFCの足並みに揃えさせることに頼ってばかりでそこをろくに説明してこなかったことで非MFC側は今もなお把握しにくく、その分だけ難易度の高さになっている。だからこそ当ブログではその検証報告を動機としている。

 

WindowBuild 手続きの画面構成処理の説明をここで終え、手続き呼び出し元の wWinMain に視点を戻す。

 

 

 

 

wWinMain の4赤枠の WindowBuild 手続きの呼び出し内まで説明したため、wWinMain 最後の5赤枠部分の説明をする。

 

5赤枠部分は、デスクトップアプリケーションの見本の方では元々は

 

 

 

 

このようになっていて、一見は Microsoft の見本の方が整っているように見えるが、当ブログの方ではまず本来の意味合い重視の書式に直している。

 

繰り返し処理としてよく使われる while や for 、また if の条件内 {  } が始まる場所は、{  } 先の処理が大きめになりそうな場合は、その先での使用予定の変数や戻り値判定のための変数などを、あえてその手前に宣言する書式にしておいた方が、概念整理に結び付きやすい。

 

Microsoft の見本の方では内部リソースによるメニュー群仕様を使っているため、そちらの操作かどうか( TraslateAccelerator の API 手続き )の判定が入っているのに対し、当ブログではそこを除外して、その部分がキー入力関連があったかどうかの処理に差し代わっているだけの違いになる。

 

この5赤枠の箇所は Windows 仕様の事情を察知できていないとだいぶややこしい話になるが、ここで呼び出されている GetMessage( Windows 標準 API  )によって、そのアプリケーション画面でどんな操作や現象などが起きたのか メッセージ というMicrosoft 概念の通知処理が行われ、事前に登録の WndProc 手続き側にそのメッセージ通知が、この GetMessage から内部的に呼び出される、という仕様になっている。

 

3赤枠の MyRegisterClass 呼び出しの方の

 

 

 

 

この手続き番地登録によって、メッセージ通知ごとに GetMessage の方から内部的に WndProc を呼び出す仕組みになっている。

 

この WndProc は Microsoft の仕様の濃い部分で、当ブログでは見本の WndProc のままにしているが

 

 

 

 

 

この手続きの戻り値型、引き数の変数型、指定子が合っていれば、手続き名の WndProc にしても各引き数の変数名にしても必ずしもこの通りである必要はなく、手続き名は例えば MessageProc などでもよい。

 

非MFCの場合、GetMessage でのキー入力関係のメッセージ通知自体はあっても、WndProc 側には通知しない仕様のようであるため、非MFCである当ブログでは、キー入力関係のメッセージがあった場合に手動で WndProc を呼ぶ作りにしてある。

 

さらに非MFCだと、文字や数字を入力するエディットボックスで Enter キーや Tab キーが押されると警告音 ポ~ン が鳴るのが素の仕様のようであるため、鳴らないようにするよう施しているが、非MFCの場合にこの5赤枠の部分に他に手を加えなければならないのは、あとはそんなに多くないと見られる。

 

GetMessage 関数 (winuser.h) - Win32 apps | Microsoft Learn

※ 右クリックポップメニューの リンクを新しいタブで開く を推奨

 

や CreateWindowExW 等のページでも、それらの事情は特に書かれていない。

 

MFC側では Tab キー処理の場合と同じくその辺りは内部リソースマクロ側で処理が組み込まれていると見られ、非MFCの場合はこのやり方でいいのか当ブログ筆者もよく解らないが、とりあえずこのような作りにしてある。

 

この GetMessage によって内部的に WndProc が呼び出されるという事情が、Microsoft のこの部分の見本をパッと見ただけでは解る訳もない所になるが、メイン画面のXボタンを押すなどの終了操作( メッセージ WM_DESTROY 通知 )や、プログラム側からの終了処理が行われたと GetMessage で認識した時( 戻り値が FALSE になった時 )に、この5赤枠の While の繰り返し処理の終了、それをもって wWinMain の終了、つまりプログラムそのものの終了という流れになる。

 

ちなみに、当ブログ筆者は普段は goto の多用はしないが、ここでは if の条件の見やすさ優先のためにあえてラベルジャンプの goto を使っている。

 

プロジェクト内共用手続きの説明は WindowBuild だけとして後は省略し、Windows C/C++ の特徴を掴むための WndProc 手続き( Windows プログラムの特徴のメッセージ処理 )について、最後にざっと説明しておく。

 

 

1.WndProc( GetMessage ) WM_COMMAND

 

※ 見本の方で使われていた、また一般でもよく使われる swich case は当ブログ筆者としては、C原点回帰に乖離的なマクロ観が強く、条件先の記述がCらしくないという理由で if に置き換えている。

 

 

 

 

WM_COMMAND メッセージ通知について、まず、WindowBuild 手続きの方での部品設置 API CreateWindowEx によって画面に部品が追加されていく際の、その部品種別が EDIT、BUTTON、LISTBOX 等、マウスクリックの動作が特徴的だと Windows 側が認識している部品に対し、CreateWindowEx 引き数の HMENU パラメータの所で指定した番号が、その部品がクリックされた際にWndProc の引き数 message に WM_COMMAND 、wParam にその番号で通知される仕組みになっている。


ここの WCOM_ 系の定数群はプロジェクト内定義、ここで呼び出されている WndCategory、WndCategorySearch、BrowseForFolder、CheckAll 手続きもいずれもプロジェクト内共用手続きになる。

 

当 WindowBuild プロジェクトでのこの HMENU 設定の考え方は、プログラミングにおける電子慣例に慣れていないと少しややこしいが、まず API CreateWindowEx の方で、それが WM_COMMAND の対象部品かどうかに関係なくテキスト情報側の設置番目通りに0、1、2と順番に設定していき、クリックされた部品番目が通知される wParam を元手に、その部品番目の役割番号を WndCategory で取得、その役割番号に該当する処理をここで実行、役割番号が特に指定されていない、つまり0指定の場合は何もしない、という仕組みにしてある。

 

画面構成情報 WindowBuild01.txt での

 

 

 

 

項目の7個目を、役割番号( 当事者都合のデータ設計。その部品に対する意味付け番号や処理番号 )の指定用にしてあり、メインソース上部の #define 定数群 の所で

 

 

 

 

想定計画的に定義している。

 

Windows C/C++ に慣れていないと、だからこうした電子慣例的な組み立て方の参考例を共有し合っていくことも重要で、それ以前にその定数や手続きが API なのか CRT なのかプロジェクト内定義によるものなのかがパッと見だと解りにくい、しかも MS-DOS 時代以来の30年以上前のC都合の伝統慣習も残り続けているため、理論統制的な解釈のしようのないものも多い、そこが Windows C/C++ の初動の難易度の高さだが、最初はどうしても慣れていくしかない所になる。

 

※ 開発環境やその仕様に対して、その当事者にとって疑問が根強く残り続けたその部分こそが、その当事者にとってののちの再細分化・再集約化の概念・名称設計どころ( 自己等族統制どころ )、という意欲的・積極的な視野が重要。


なお、この WM_COMMAND メッセージによる部品クリック方式が Microsoft の推奨ということで、ここではそれに合わせてあるが、以前も少し触れたが WM_LBUTTONDOWN または WM_LBUTTONUP のマウス左クリックメッセージからでも設計可能、こちらは HMENU と無関係にウインドウハンドル単位を基準にほとんどの部品で通知されるため、拡張的な設計をする際はそちらのメッセージ通知を基点に設計するも手になる。

 

 

2.WndProc( GetMessage ) WM_PAINT

 

 

 

 

画面構成関係ではここは基本的に触ることはないこともあり説明はしばらく省略、ここは Microsoft の見本のままにしてある。

 

デバイスコンテキスト( HDC。Windows 仕様概念の変数型 )について、別章の自由型画像表示 DIB 仕様の方でのちほど説明予定。

 

 

3.WndProc( GetMessage ) WM_KEYDOWN

 

 

 

 

A赤枠は、プロジェクト共用変数 g_bShift を使って Shilf キー押しっぱなし状態を認識、下述 WM_KEYUP メッセージの方で Shift キーが離された認識、で対になっている。

 

B赤枠は Enter キーが押された際を、C赤枠は Tab キーが押された際の部品フォーカス移動を、D赤枠は F1 ~ F3 キーが押された際という、キーボード押下( おうか )時の4仕様分の構造( 対象キーとしては計6個 )になっている。

 

< WM_KEYDOWN B赤枠 Enter キー >

 

 

 

 

この Enter キー処理内は、GetClassName が Windows API 手続き呼び出し、GetFocusIndex、WndCategorySearch、ListFolderBuild、ListFolderMove がプロジェクト内共有手続き呼び出しになる。

 

GetClassName では、Entet キーが押されたウインドウハンドル( 通知された WndProc の HWND Wnd )の部品種別名を取得し、それがエディットボックスでの Enter キーであれば次の操作部品にフォーカスを移動する合図としている bEnterFocus に true を設置し、さらにそのエディットボックスがもしフォルダ入力の役割のものなら、Enter キーによってリストボックスにファルダ情報を反映させるための ListFolderBuild の呼び出しを行っている。

 

リストボックスでの Enter キーの場合、リストボックスのセル選択中の項目フォルダに移動という意味で、リストボックスを移動先のフォルダに再表示、フォルダ入力のエディットボックスがあればそちらにもフォルダ構成を再表示させる処理を、ListFolderMove 手続きの呼び出しで実行する仕組みになっている。

 

エディットボックスかどうかの判定の所で、GetClassName 手続きによって文字列変数 pClassName に取得した先頭1文字目が E かどうかの判定の仕方をしているが、これは以前に Microsoft Spy++ の方で紹介した

 

 

 

 

各ウインドウハンドルごとの部品種別名( Windows 内部仕様の方でのクラス名 )の取得で、当 WindowBuild プロジェクトの仕様では入力系部品は EDIT、BUTTON、LISTBOX に限定、頭文字が E か B か L かという単純な判定方法にしている。

 

部品種別名の判定時のシングルコーテーションの L'E' リテラル記述は、文字コード値 0x45 と記述しているのと同じで、半角英数字の文字コードについては旧 ANSI SHIFT-JIS とほとんど同じのため L は付けなくてもよいが、UNICODE-16LE を基本としていることの強調のために L を付けるようにしている。

 

なお、部品種別名の取得用の文字列変数 WCHAR pClassName[ 8 ] は、次の Tab キーでも使用するため WM_KEYDOWN 条件に入ってすぐの所で定義しているが、Enter キーの判定内と Tab キーの判定内とでそれぞれ定義してしまってもよい。

 

※ 手続き内のスコープ内変数について、if や for / while のスコープ先( {  } 内の処理先。さらにその先の {  } 内 )で変数が多めな処理が行われる場合は、そのスコープ前にスコープ先全ての変数定義を固めておくことによって、スコープ入り前での事前の変数の想定計画観が作れて概念整理しやすくなる場合がある。一方でスコープ内の階層ごとで変数定義した方が、その階層ごとでの処理単位のまとまりが出てきて、処理単位の移動・引っ越しのしやすさや拡張処理の挟みやすさになる場合もあるため、変数の定義場所は工夫どころになる。

 

 

< WM_KEYDOWN C赤枠 Tab キー >

 

 

 

 

ここでの呼び出し手続き 1~8 は全て Windows API で、GetFocus、GetNextWindow、GetParent、GetWindow はいずれも都合ごとのウインドウハンドルの取得、GetClassName は上述したそのウインドウハンドルの種別部品名の取得になる。

 

ここでは汎用性を高めるために、共用変数のウインドウハンドル保管配列 HWND *g_hWnd はあえて参照せずにできるだけ API だけで、という狙いで Tab キーおよび Shift + Tab キーのフォーカス移動処理を作ったため、その分、Windows C/C++ に慣れていないと少し難しめな作りになっている。

 

※ MFCではこの Tab フォーカス移動処理は内部リソースマクロ側で自動化されるため確かに楽で、非MFCでの自前だとここだけやけに敷居が高くなってしまう。これが妥当な作りなのか当ブログ筆者もよく解っていないが、Windows 標準 API の特徴を知る機会ともいえる。

 

※ MFCは最初は楽かも知れないが、C原点回帰的な本来の仕様設計に乖離的な規則頼みの、用意されていないことはできない/してはならない制限一辺倒に向かわせがちになる。その離脱の非MFC側つまり Windows 標準 API との向き合い中心は最初は敷居が高く、把握できるようになるまでに少し時間がかかるかも知れないが結局は Windows C/C++の理解の近道、楽になる代償の規則縛りの敷居低下的・不都合権威的な制限を一切受けない仕様設計が可能な、結局は上達の近道になる。

 

SendMessage はここでは、フォーカスの移動先がエディットボックスの入力項目だった場合、青セルを引いた状態にする処理を行っているが、SendMessage 自体はそのウインドウハンドルに動作的な用件を指示・設定的に通知するための手続きになる。

 

メイン画面に所属する各部品ウインドウの機能への通知の大半は、この SendMessage 手続きを介して行われる。

 

この SendMessage を使って、例えばよそのプログラムの入力項目を編集したりボタンを押したことにするなどが可能ではあるものの、GetNextWindow などのウインドウハンドル取得の仕組みの把握力が重要だったり、他にも条件もだいぶややこしい等、それについては専門家でもない当ブログ筆者なりによる説明を、別章で予定している。

 

ここでは GetWindow や GetNextWindow の所で、引き数にも戻り値にも同じ変数 hWndNext を記述しているが、当ブログ筆者は基本的には引き数と戻り値に同じ変数を使うことは普段はしない、それぞれ変数を作ることにしているものの、変数の設置を面倒がったのではなくこの場合だとこの方が意味合い重視になると判断し、ここだけはあえてこうしてある。

 

 

< WM_KEYDOWN D赤枠 F1 ~ F3 キー >

 

 

 

 

ここでは、GetWindowLongPtrW が API 手続き、wcscpy_s が CRT 手続き、CloseWindowAndAlloc と WindowBuild がプロジェクト内共有手続きになる。

 

動作としては、F1 ~ F3 キーが押された際に、構成画面のいったんの消去と動的メモリのウインドウハンドル保管用変数の解放・初期化が CloseWindowAndAlloc 手続きで行われ、WindowBuild01 ~ 03.txt による再びの WindowBuild 手続きの呼び出しによる画面構成、というだけの、手順自体の概要は単純になる。

 

しかし概要としては単純でも、プログラムの起動のし直しによる再初期化・再表示に頼らない再構成・再表示機能の搭載は Windows C/C++ に慣れないと、思った以上の想定設計の問われどころで簡単ではない場合も多い。

 

実際、画面の環境変更をすると起動のし直しを前提としているアプリケーションが多いが、Windows C/C++ に慣れてきたら当例のように、起動し直さなくても初期化・再表示もできるようになっていくと、かなりの上達に結びつくため推奨する。

 

 

3.WndProc( GetMessage ) WM_KEYUP と WM_DESTORY と DefWindowProc

 

 

 

 

WM_KEYUP メッセージは、押されたキーボードが離された動作が起きた際の通知で、ここでは Tab キー動作の際のために Shift キーの現在の状況を、共用変数 g_bShift の方でその状態保存をしている。

 

当 WindowBuild プロジェクトでは、Shift キーが押された( WM_KEYDOWN )/離された( WM_KEYUP )時にどの入力項目にフォーカスがあたっている時なのかについては等は特に判定する必要は特にないため、その判定は特に入れていないが、逆言えば Shift キーが押された/離された際に、どのウインドウハンドル( HWND hWnd )からなのかという通知情報を元に、何らかの理由による動作処理を入れていくことも可能になる。

 

WM_DESTROY メッセージは、メインウインドウのXボタンを押す等の終了操作の通知で、wWinMain の GetMessage の While 部分の終了契機となる。

 

最後の bDefault の判定による DefWindowProc ( API )呼び出しのこの構造は、Microsoft 見本の WndProc の switch case 構造を if 構造に直し、構造を同じにしただけになる。

 

以前の章で Microsoft Spy++ を少し紹介をしたが、Windows の仕様ではこの WndProc に書かれているメッセージだけでなく、各振る舞いごとの様々なメッセージが絶えず通知される仕組みになっていて、WndProc の方で特に処理を加えないメッセージについてはこの DefWindowProc を呼び出すことが基本のようであるため、見本に合わせておいた。

 

---------------

---------------

 

ブログ機能の字数制限の都合で、各プロジェクト内手続きごとの説明や、また変数名や手続き名の概念名設計についてなど他にも説明していきたいことが多かったが、切りがよいと思ったため WindowBuild プロジェクトの説明はここまでにする。


Windows C/C++ の基本の手続きとなる wWinMain、WndProc のふたつをまずはざっと紹介しておくだけでも、全体の初歩的な説明になると思い、今回はそこに焦点を当てた説明をとりあえずしておくことにした。

 

今回、あまり触れることができなかった概念名設計の上達のコツなどは、以後も積極的に触れていく。

 

引き続き次回も議題次第にプロジェクトファイルのアップロードおよび、その説明を続けていく予定。

 

自身がしたことも人がしたことも粗探し悪意狩り減点のねじ伏せ合い低次元規律のみでは上達しない、そこから次の段階に向けての改善余地がいくらでも見つかるというISO9000系善用の回収視点が重要。