[[BORLAND C++ CWCC]]
RETURN
CWCC#11 CWCC Evolution #1
あれから2年…以上か??,いや〜!さぼったなぁ〜!いつの間にか周囲の環境もWindowsXpが定着してきたし、頭の片隅に、あんなの造ったっけって記憶は有ったが、こちらが本業じゃないからねぇ。仕事も色々忙しかったし,ユーザの方からの要望は有ったけど…ってか、ソースコードの暗号化解く方法を教えてくれって要望が、結構多くて…一応、断っておくけど、暗号化掛けてるのは、意地悪してる訳じゃ無くて、ヤキソバの様なソースコードで、人目に晒すのが恥ずかしいからってのと、おいらの頭の中で、「なんでこうなるの??」って疑問が解決してない部分が有って、「なんとなく、こうしたら上手くいった…」的な、いわば結果オーライで使ってしまっている部分が幾つか有ったので、そんなものを人目に晒すのもって気持ちが有ったからで、メールで連絡してもらえれば、暗号の解き方は簡単に教えるので、気軽に声掛けてちょ〜だい。(今後のバージョンで暗号化するか否か?ソースコード公開するか否かについては、未定ですが、少なくとも、現行暗号化して公開している部分については、問題無いので…)
さて、今回、なぜ重い腰を上げたかって言うと、仕事で本編のWinlibを使ってツールを開発するという場面が、3件程続いていて,一部、CWCCの方を利用したりしたので、この機会に、以前に開発していた頃から要望が有って、対応してなかった点を幾つかやっつけようと考えたからなのだ。具体的には,
    • フォントの変更,フォント色の変更
      やろうと思えば、簡単なのだが、色々と問題が有って、今まで未着手だったのだ。問題点は、ユーザがコードを記述する段で、既にスレッドが走り初めているので、フォントや文字色を設定した時点から、いきなり変わってしまうという点,まぁ、この点は何とか納得させるとしても、フォントの色は、一部分だけ変えたいという向きが多いと思うのだが、現在の仕様上から考えると、色を指定するとコンソール上の文字の全ての色が変わってしまう。これも、どうしたものか??という事で、仕様を決めあぐねていたというのが正直なところだ。素直にRichEditを使うって手も有りだが、実はここ、おいらの趣向で、DLLになってるのが気にくわない…(ナマいってんじゃね〜と言われそうだが…)なのである。まぁ、RichEdit.dllは、Winodwsに標準で付いて来るし、ぶっちゃけて言うと、これ、使い方をマスター出来てないってだけなので、そのうち、しれ〜っと対応しちゃってる可能性もあるが、とりあえず、現行は、EDITコントロールで何とかしたいってのが本音である。

    • ESCシークエンスが使いたい
      これも、以前から要望多数だった案件だが、おいら自身,MS-DOSでプログラムしてた頃は常用してたし、欲しいなぁとは思っていた。ただ、これを実現させようとすると、上記のフォント色とも絡んでくるし、結局、コンソール部分はオーナドローするしか無いのだ。あと、そうなると、コンソール上でマウスも使える様にしたいし…色々問題あるのだ。

    • メインのウインドウを隠す
      以前,ダイヤログだけで動作させるから、メインのウインドウが邪魔になる。隠せないのか?との質問を受けた事がある。て〜か、それなら、CWCC使わずに、WinMainの内部で処理すれば対応出来るんじゃないのかなぁ?って答えたら、Dialogの連携でアプリを造るんだけど、ログは、CWCCのコンソールに吐き出して、デバッグして、ツールとして発行する時には、メインのウインドウを消して出したいらしい。あと、CWCCのタイマとCanvasは使いたいらしい。これ,出来るのかどうかは別として、ちょっと考えてみる事にした。

  • 考え方って〜かお膳立て
    さて、それぞれの機能をどの様に実装するか?は後回しとして、現行のCWCCでは、WinMain開始後、メインのコンソールを表示→スレッドを立ち上げ→ユーザのプログラムに繋ぐという流れになっていて、この間はCWCC内部で動作してしまうので、上記の対応をしようとすると無理がある。突然画面を書き直したり、最初一瞬、コンソールウインドウが表示されて消えるなど..見た目がどうでも良いって言うのであれば、何とかなるが、それでは、何だかなぁ…なのだ。つまり、フォントや色,コンソールの設定ってのは、メインのコンソールを表示する前に指定した方が良いのだ。ここに、何か、ユーザから操作出来る部分を用意してやらないと、いけない訳だ。要は、CWCCの中に押し込んであるWinMainの中の何処かで、ユーザプログラムを呼び出す様にしておいて、ここに、初期化コマンドを記述して貰う様にすれば良いのだが...。ただ、CWCCの主旨は、あくまでも「Hello Worldを10行以下のプログラムで実現」であり、これを壊す様ではいけない。あと、やむを得ない場合を除いては、現行までCWCC用に作成したプログラムを、そのままコンパイル出来る事も条件となる。

  • クラスライブラリ的アプローチ(Step1:WinMain開始以前)
    こんな時に、クラスライブラリ的なアプローチが有効になってくるのである。まずは、試作コードから,

    inittest.h

    inittest.cpp

    test.cpp

    この試作コードは、実際にリリースするcwccに照らし合わせると、inittest.hは、cwcc.h,inittest.cppは、cwcc.objのソース,test.cppは、ユーザプログラムに相当する。コンパイルは、
    bcc32 -c inittest.cpp
    bcc32 -c test.cpp
    bcc32 test.obj inittest.obj

    test.exeが生成される筈である。
    この時、test.cpp//#define CWCC_USER_INIT部分のコメントを外して有効にした場合と、コメントアウトして、無効にした場合を試してみると、違いが分かると思う。
    #define ..を有効にした場合は、main()関数が実行される前にUINIT Xが生成され、UserInitialize()関数が呼ばれているが、
    #define ..を無効にした場合は、UINIT Xも生成されないし、UserInitialize()関数も呼ばれない。これをCWCCに当てはめると、ユーザが、ユーザプログラムの中で、cwcc.hをインクルードする前に、#define CWCC_USER_INITを宣言しておけば、WinMain()が始まる前に、UserInitialize()と言う関数が呼ばれる様になるので、ユーザプログラム側で、この関数を定義し、ここに、メインのコンソールを造る前の初期化コマンドを記述しておけば良い事になる。当然、以前の版で作成したユーザプログラムは、#define CWCC_USER_INITなどと言うdefineは切ってない筈なので、UserInitialize()は呼ばれないし、そのままコンパイル出来るという寸法である。
    因みに、変数UserInitは、CWCCのライブラリ関数の有効/無効を切り分ける為に用意したフラグであり、メインのコンソールが生成されてからでなければ使えない関数をガードする目的で使用するつもりである。

  • クラスライブラリ的アプローチ(Step2:WinMain開始以降)
    さて、実を言うと、Step1の施策のみで乗り切ろうと思っていたのだが、WinMain()が始まる前では、Instance等が取得できず、設定に支障を来す場合が予想出来たので、もう一歩、踏み込んでおく事にした。何処までが必要か?については、ライブラリを構築していく上で見いだすとして、少なくとも、WinMain開始直後、CreateWindow後辺りに、ユーザ初期化を挟める様にしておく。但し、この場合、Step1の様に、#ifdefで区切る事は出来ない(ライブラリ側は、先行でコンパイルされてしまうから)ので、もう少し、面倒な手順を踏む事になる。では、試作コードをば…

    inittest.h

    inittest.cpp

    test.cpp


    基本的には、Step1の試作に追加した形だが、変数名などは少々変更したりしている。まぁ、実際に実装する段になったら、色々とチューニングするので、クラス名や変数名は、この段階では、(仮)と言う事で…また、初期化メソッドの引数についても、INSTANCEやらHWNDやら渡したいので、実装の段でチューニングが入る予定…。ともかく、test.cppの、//#define CWCC_USER_INITのコメントを外した場合,更に、// PresetUserClass(new MyInit()) ;のコメントを外した場合の動作の違いから、ユーザに対して、3段階の初期化手段を提供する事が出来る様になる。即ち、

    1. 現状通り、#define CWCC_USER_INITは記載しない。
      UserInitialize()が呼ばれないので、UserDesignクラスをCwccUserDesignクラスにセット出来ない。この為、デフォルトの初期化が実行されて、現状までの通りにCwccMainに至る。

    2. #include "cwcc.h" 前に、#define CWCC_USER_INITを記述する。
      UserInitialize()が呼ばれるので、ここに、WinMainに至る前の設定を記載する事が出来る。

    3. 上記に加え、UserDesignクラスを継承したクラスを、PresetUserClass()関数にて、CwccUserDesignクラスに登録する。
      タイミングとして、WinMainが始まる前のUserInitialize()時に、この処理を実施すれば、WinMain先頭,若しくはコンソールが生成された後に、ユーザの初期化を行う事が出来る。

    まず、お膳立ては、こんなところだろうか??
    苦労話って〜か、覚え書き…
    上の試作(Step2)で、CwccUserDesignクラスと、CwccUserDesign CwccUserInitをユーザに公開して、ユーザにCwccUserInit.SetUserClass()で登録させれば、PresetUserClass()は要らなくなると思って、当初は、そんな造りだったのだが、どうしても、CwccUserDesign CwccUserInitがインスタンス生成される前にUserInitialize()が呼ばれてしまうので、ここでSetUserClass()を実行しちゃうと、変な状態になってしまうのだ。そこで、一旦、PresetUserClass()で、ユーザクラスを仮登録しておいて、CwccUserInitが生成される段,若しくは、情報が出そろう筈のWinMain(ここではmainだが…)の先頭で、仮登録したものを、CwccUserInitに登録する様にした。
2004/11/04
HomeSweetHome2
Ozzy's Software