注:ブラウザでご覧になる際,ブラウザのフォントを固定ピッチフォントにしてください.プロポーショナルだとレイアウトが崩れる箇所があります.
はじめに
フォルダ構成
C++Builder3.0への移植について
C++Builderコンソールアプリケーション版について
VC++バージョンへの変更について
VC++Tips
g++(Cygwin:UNIX風環境)のインストール
g++Tips
VC++バージョンの修正について
はじめに
このCD-ROMには,本文で紹介したプログラムのソースをフォルダに分けて収録しています.
また,読者の方々の便宜を図るために,g++の処理系も収録しています. 本書の,コンソールアプリケーションとして紹介したプログラムは,g++でコンパイルして実行形式を作ることができます. また,本文では,GUIアプリケーションとして,C++Builderを仮定したプログラムを紹介していますが,CD-ROM中には,VC++バージョンも開発して収めてあります. なお、パーソナルメディアのホームページにて関連情報をご案内しております。
フォルダ構成
CD-ROMには,以下のフォルダが収められています.
おまけ
以下は,拙著のディスクサービスで提供しているソースファイルを含んだフォルダです.
omake
|
NNBook
|
右書籍で取り扱ったすべてのソースファイルを章ごとにまとめています. |
Cでつくるニューラルネットワーク
パーソナルメディア刊(1991)
定価 3,675円 (本体価格 3,500円) |
WinNN
|
右書籍のGUI版で,C++Builderで開発しています. |
GaBook
|
右書籍で取り扱ったすべてのソースファイルを章ごとにまとめています.
WindowsAPIを使ってGUI版として開発しています16bit版(オリジナル)とVC++版(32bit)が含まれています. |
応用事例でわかる
遺伝的アルゴリズムプログラミング
パーソナルメディア刊(1995)
定価 3,990円 (本体価格 3,800円) |
Gadelphi
|
右書籍のDelphi版です. |
遺伝的アルゴリズム:g++バージョン
Ga |
Gpp |
リーフフォルダ名 |
部/Chapter |
説明 |
CGaFrameWork |
第1部 |
汎用フレームワーク.これを元にして拡張を行う. |
ConJsp |
第2部/
Chapter 10 |
遊びじゃないスケジュール:ジョブショップスケジューリング問題の解法 |
ConTsp |
対応なし |
おまけ.第2部/1章の参考 |
TimeTable |
第2部/
Chapter 8 |
時間割は奥深い:Time Tabling Problem |
TspGrf |
第2部/
Chapter 7 |
どの順序で作ろうか?:巡回セールスマン問題の応用 |
遺伝的アルゴリズム:C++Builderバージョン
Ga |
CppBuilder |
リーフフォルダ名 |
部/章 |
説明 |
GaFrameWork |
第1部 |
汎用フレームワーク.これを元にして拡張を行う. |
Pack |
第2部/
Chapter 9 |
後片づけはむずかしい?! :箱詰め問題の解法 |
遺伝的アルゴリズム:C++Builder Console AP
Ga |
CppBuilder |
リーフフォルダ名 |
部/Chapter |
説明 |
CGaFrameWork |
第1部 |
汎用フレームワーク.これを元にして拡張を行う. |
ConJsp |
第2部/
Chapter 10 |
遊びじゃないスケジュール:ジョブショップスケジューリング問題の解法 |
ConTsp |
対応なし |
おまけ.第2部/1章の参考 |
TimeTable |
第2部/
Chapter 8 |
時間割は奥深い:Time Tabling Problem |
TspGrf |
第2部/
Chapter 7 |
どの順序で作ろうか?:巡回セールスマン問題の応用 |
遺伝的アルゴリズム:VC++バージョン
Vcpp |
GeA |
リーフフォルダ名 |
部/Chapter |
説明 |
GaFrame |
第1部 |
Windows AP汎用フレームワーク.これを元にして拡張を行う. |
CGaFrame |
第1部 |
Console AP汎用フレームワーク.これを元にして拡張を行う. |
CTspGrf |
第2部/
Chapter 7 |
どの順序で作ろうか?:巡回セールスマン問題の応用 |
CTimeTable |
第2部/
Chapter 8 |
時間割は奥深い:Time Tabling Problem |
CJsp |
第2部/
Chapter 10 |
遊びじゃないスケジュール:ジョブショップスケジューリング問題の解法 |
VCPack |
第2部/
Chapter 9 |
後片づけはむずかしい?! :箱詰め問題の解法 |
遺伝的プログラミング:g++バージョン
Gp |
Gpp |
リーフフォルダ名 |
部/章 |
説明 |
CGpFrameWork |
第1部 |
汎用フレームワーク.これを元にして拡張を行う. |
MajorityOn |
第3部/
Chapter 11 |
まずは多数決をとってみよう :多数決判定プログラムの合成の解法 |
Sequence |
第3部/
Chapter 12 |
この次に来る数はなんだろう :数列規則を見出す問題 |
ADFTwoBoxes |
第3部/
Chapter 13 |
体積の差がわかるかい :体積差を計算するプログラム合成 |
遺伝的プログラミング:C++Builderバージョン
Gp |
CppBuilder |
リーフフォルダ名 |
部/章 |
説明 |
GpFrameWork |
第1部 |
汎用フレームワーク.これを元にして拡張を行う. |
Ant |
第3部/Chapter 14 |
人工蟻を進化させる :Santa Fe trail問題の解法 |
StoreKeeper |
第3部/Chapter 15 |
15 倉庫番はつらいかも :倉庫内の荷物の片付け問題 |
遺伝的プログラミング:C++Builder Console AP
Gp |
CppBuilder |
リーフフォルダ名 |
部/章 |
説明 |
CGpFrameWork |
第1部 |
汎用フレームワーク.これを元にして拡張を行う. |
MajorityOn |
第3部/
Chapter 11 |
まずは多数決をとってみよう :多数決判定プログラムの合成の解法 |
Sequence |
第3部/
Chapter 12 |
この次に来る数はなんだろう :数列規則を見出す問題 |
ADFTwoBoxes |
第3部/
Chapter 13 |
体積の差がわかるかい :体積差を計算するプログラム合成 |
遺伝的プログラミング:VC++バージョン
Vcpp |
GeP |
リーフフォルダ名 |
部/章 |
説明 |
GpFrame |
第1部 |
Windows AP汎用フレームワーク.これを元にして拡張を行う. |
CGpFrame |
第1部 |
Console Ap汎用フレームワーク.これを元にして拡張を行う. |
CMajorityOn |
第3部/
Chapter 11 |
まずは多数決をとってみよう :多数決判定プログラムの合成の解法 |
CSequence |
第3部/
Chapter 12 |
この次に来る数はなんだろう :数列規則を見出す問題 |
CADFTwoBoxes |
第3部/
Chapter 13 |
体積の差がわかるかい :体積差を計算するプログラム合成 |
VCAnt |
第3部/
Chapter 14 |
人工蟻を進化させる :Santa Fe trail問題の解法 |
VCStoreKeeper |
第3部/
Chapter 15 |
15 倉庫番はつらいかも :倉庫内の荷物の片付け問題 |
C++Builder3.0への移植について
本文で紹介しているGUI版はC++Builderの1.0で開発しています.CD-ROM にも1.0版を入れてあります.これをC++Builder3.0へ移植するには以下の注意が必要です.
◆移植
各フォルダの *.mak をダブルクリックで起動するか,C++Builder3.0へドラッグ&ドロップして起動します.ビルダーが立ち上がると「1.0から3.0へのバージョンが変更されました」というダイアログが出るので,OK
ボタンで応答します.
これで,移植は完了です.
◆再構築
移植が完了すると,プログラムの構築に移りますが,必ず「再構築」で行ってください.
◆環境の修正
各アプリケーション中の一部にはインクルードパスのため,再構築中にコンパイルエラーが
出る場合があります.そのときは以下のことを行ってください.
- [プロジェクト]-[オプション]で,プロジェクトオプションダイアログを開きます.
- 同ダイアログで,「ディレクトリ/条件」タグを指定してします.
- インクルードパスのエディットボックスに表示されているパスの先頭に,「.;」を追加します.すなわち,現在のディレクトリを認識させるようにしておきます.設定後は,OK
ボタンをクリックして,同ダイアログを閉じます.
- 再度,再構築を行います(必ず[再構築]で行います).
C++Builderコンソールアプリケーション版について
本文では,一部コンソールアプリケーションとして,g++バージョンを作りました. これは,C++Builderでのコンソールアプリケーションとしてもコンパイル・リンクが可能であって欲しいからです.CD-ROMには,このC++Builderコンソールアプリケーションバージョンも含まれています.基本的には,g++バージョンから移植し,一部変更を加えています.
変更箇所は以下です.
◆GA
GaFrame.cpp |
|
VCLクラス等を使いインクルードファイルを指定している. |
GaAppTpl.h |
|
stdio.hを条件マクロの外に出した. |
TimeTable |
|
ViewTimeT.cpp中のエスケープシーケンスをかき出しているところを削除した.
g++版ではCygnusのウインドウがそれを受け取り文字の色を変えることができたためのもの. |
◆GP
GpFrame.cpp |
VCLクラス等を使いためインクルードファイルを指定している. |
GpAppTpl.h |
stdio.hを条件マクロの外に出した. |
各アプリケーションのファイル中のコンストラクタの書き方を SubjectType を使って 表現するようにした. |
なお,実行形式のファイル名は,GaFrame または GpFrame となります.
VC++バージョンへの変更について
本文では解説していませんが,フレームワークを含めて本文で取り扱った問題をVC++で 実装しました.VC++4.2で開発し,VC++5.0での動作確認を行い,両者で動作可能なソース
としてありますが,一部,コメント化の操作をしなければならない部分が残っています.
また,C++Builderやg++と実行結果が異なっています.
・クラステンプレート定義ファイルの違い
・GUIバージョンにおける基本的な違い
・VC++におけるプロジェクト
・VC++4.2におけるコンパイル等
・VC++5.0におけるコンパイル等
・VC++6.0におけるコンパイル等
・VC++ .NETスタンダード版 におけるコンパイル
・VC++バージョンにおけるviewString関数の仕様違い
クラステンプレート定義ファイルの違い
GaAppTpl.hとGpAppTpl.hについては,本文で扱ったものと多少の差があります.
本文中のものは,g++との共用のために,インクルードファイル(strstream.h とstrstrea.h)名の長さを,選択するようにしていますが,VC++版では,後者のみとなっています.
また,VC++4.2と5.0でのnamespaceの扱いが異なっていることもあり,コメント化の有無で逃げています.さらに,クラスライブラリの差や,Treeコントロールの部分も違いが出るところです.したがって,C++Builderやg++との共用はできません.
もうひとつVC++バージョン固有の内容ですが,遺伝的プログラミングのGpAppTpl.hは,GUIバージョン用とコンソールアプリケーション用とでは異なっていますので注意してください.
▲VC++バージョンへの変更についてへ
GUIバージョンにおける基本的な違い
フレームワークの作り方で,大きく異なるのは,進化処理を繰り返すしくみとその途中でリアルタイムに途中経過を印字するしくみです.
C++Builder版では,ユーザ定義メッセージを送りあって同期をとるようにしましたが,VC++版では,ワーカースレッドとして進化処理を構成し,途中経過の状況印字やグラフの描画などは,そのスレッドから各ウインドウへユーザ定義メッセージをSendMessageで送りつけています.
その他のフォーム(C++BuilderでのWindowの呼び方)やダイアログ(VC++流)の構成は同じになるようにしていますが,解表示のダイアログのみVC++では,スクロールなしの簡易版としました.他のダイアログもデザインの詳細は異なります.
なお,プロジェクトタイプはMFC AppWizard(exe)として作りましたが,Doccument−View構造は使っていません.ApplicationとFrameを主として使っています.
▲VC++バージョンへの変更についてへ
VC++におけるプロジェクト
VC++版では,4.2と5.0で動作可能なようにしてありますが,これらの環境には大きな違いが
存在しています.ただし,4.2のプロジェクトファイルは5.0に読み込ませると,変換されますので,基本的に4.2で開発して5.0へ変換する方法をとりました.
VC++版の各フォルダ中には,プロジェクトファイルのそれぞれを入れてあります.
VC++4.2 *.mdp
VC++5.0 *.dsw
環境に合ったものを使って,プロジェクトを起動(ダブルクリック等)してください.
なお,これらと*.mak,*.dspは消去しないようにしてください.
▲VC++バージョンへの変更についてへ
VC++4.2におけるコンパイル等
目的のフォルダ中の,*.mdp をダブルクリックするなどして環境を立ち上げます.
- [ビルド]-[ビルド]で実行形式を作ります.
- 何事もなければ,リンク終了しますが,ビルト時,大量のコンパイルエラーが出る場合がありました.
- GUI系は,[ビルド]-[実行]で実行します.デフォルトのパラメータはあらかじめ組み込んであります.詳細は,本文を参照してください.
- CUI系は,DOS窓を開いて,それぞれの実行形式が作られているフォルダへ移り,コマンドラインで実行します.パラメータについては本文を参照してください.
なお,実行形式が作られるフォルダは,各アプリケーションのフォルダ内に作られる,DebugまたはReleaseというフォルダのどちらかに入ります.これは環境の設定によるため,VC++のマニュアルを参照してください.
なお,次のアプリケーションでは,実行形式があるフォルダに入力ファイル等を準備しておかなければなりません.
CTimeTable: |
|
CTimeTable中のDataフォルダごと,実行形式が存在するフォルダへコピーしておくこと. |
CTspGrf: |
|
CTspGrf中のProduct.txtを実行形式が存在するフォルダへコピーする. |
CSequence: |
|
CSequence中のLdata.txtを実行形式が存在するフォルダへコピーする. |
- GPのCUI系アプリケーションでは,進化から得られた合成関数をテストするためのプログラムを生成しています.これは,コンソールアプリケーションを仮定していますので,できたソースプログラムの実行は,それぞれのプロジェクトを作成して確認してください.
プロジェクトの作成についてはVC++のマニュアルを参照してください.
- なお,CSequenceでのテストプログラムでは,ゼロ割が発生する場合があります.
これは,同アプリケーションの合成関数の解釈で,0が除数となる場合は,便宜上1に読み替えているのですが,合成関数では0のままとなります.
この問題は,定数としての0だけではなく演算途中で0となる場合もありますので,
単純なようでいて,対応は結構難しくテストプログラムでの対応はしておりません.
▲VC++バージョンへの変更についてへ
VC++5.0におけるコンパイル等
目的のフォルダ中の,*.dsw をダブルクリックするなどして環境を立ち上げます.
1 [ビルド]-[ビルド]で実行形式を作ります.
2 何事もなければ,リンク終了します.
3 以降は,上記VC++4.2を参照してください.
なお,CD-ROM中のソースファイルは,4.2版となっていますので,5.0でコンパイル等を行う場合には,一部コメント化などを行っておく必要があります.
詳しくは,VC++4.2とVC++5.0の互換ソースを参照してください.
▲VC++バージョンへの変更についてへ
VC++6.0におけるコンパイル等
コンパイル要領はVC++5.0と同じです.
目的のフォルダ中の,*.dsw をダブルクリックするなどして環境を立ち上げます.
1 [ビルド]-[ビルド]で実行形式を作ります.
2 何事もなければ,リンク終了します.
3 以降は,上記VC++4.2を参照してください.
なお,VC++6.0でも,GaAppTpl.h中の以下のVC++5.0と同様,コメント化を解除してください.
// VC++4.2では以下のnamespaceをコメント化するが,VC++5.0では有効にする.
using namespace std;
なお,プロジェクトの中には,GaAppTpl.hがFileタグで開かれるウインドウに出てこない場合があります.このときには,[プロジェクト]-[プロジェクトへの追加]-[ファイル]により,そのファイルを指定して追加してください.
詳しくは,VC++4.2とVC++5.0の互換ソースを参照してください.
▲VC++バージョンへの変更についてへ
VC++.NETスタンダード版におけるコンパイル
VC++.NET に関しては,スタンダード版でのみで確認しました.
VC++.NET のコンパイラはVC++6.0と同等ということです.したがって,コンパイル要領はVC++6.0と同じです.VC++.NET のプロフェッショナル版も,コンパイル要領はVC++6.0と同じだと推測できます.アカデミック版については,確認していません.
なお,詳細な修正箇所は,VC++6.0におけるコンパイル等を参照してください.
※ご注意:すべてのプロジェクトについて「.NET版」を確認したわけではありませんので、ご了承ください.
▲VC++バージョンへの変更についてへ
VC++バージョンにおけるviewString関数の仕様違い
GPにおいて,IndividualクラスのviewString関数の仕様が異なっています.
本文バージョンでは,AnsiStringを関数値で返すようにしていますが,VC++バージョンでは
引数経由としています.したがって,VC++バージョンでの引数は1個多くなります.
GAにおいては,同じ仕様となっていて,ともに引数経由で文字列を返すようにしています.
▲VC++バージョンへの変更についてへ
VC++Tips
VC++とC++Builderとでは,プログラムの構成の仕方に大きな差があります.一言で表現するとC++Builderはコントロール等をすべてカプセル化して必要な部分以外は表に出さないようにしていること,またオブジェクトの取り扱いなどコンセプトが一貫しているといえます.
一方,VC++は,かなり素朴な感覚で,その分理解すると手数はかかりますが細かなことができます.
別な言い方をすると,C++BuilderはそのクラスライブラリであるVCLと環境とがうまく整合を
とっていますので,直感的な類推が可能で,プログラミングする上で負担を軽減してくれていることは確かです.VC++は,MFCと環境とが遊離しています.そのぶん直感ではなく比較的時間をかけた慣れが必要になるのでしょう.ここでは,両者の比較をするわけではありませんが,VC++の理解を促すにはこの程度の違いを自覚しておいたほうがよさそうです.
なお,下記に示すTipsは,VC++版を開発する過程で得られた物ですので,VC++版ではすべてこれらは折り込み済みです.ただ,コードを理解する上で,これらのTipsは役に立つと思います.
・VC++4.2からVC++5.0へのプロジェクト変換
・VC++4.2とVC++5.0の互換ソース
・Dialogの継承とメッセージ処理
・ClassWizardにクラスが表示されない
・メインフレームに張付いているViewをコンソール風に使う
・ビルト時,大量のコンパイルエラーが出る場合
・プロパティダイアログを用いずに,Staticコントロールの3D表示時くぼみ表示とする方法
・cgaframe.cppのVC++6.0でのコンパイルエラー
VC++4.2からVC++5.0へのプロジェクト変換
VC++版の各フォルダには,VC++4.2とVC++5.0用の両方のプロジェクトファイルを準備してありますので,お手持ちの環境により使い分ければ問題ないはずです.
ただ,両バージョンに共通のコードを作る場合,ファイルの追加等があると,4.2で開発してから5.0へコンバージョンするほうが楽になります.この場合5.0用のプロジェクトファイルは同一フォルダに入れないようにして,4.2用のみの*.dspとしておきます.
5.0へ移行するときには,この*.dspから起動すると,旧バージョンを変換する旨のダイアログが2回でますが,ともにOKで応答します.これで5.0への移行は完了です.
なお,両バージョンのプロジェクトファイルを削除した場合には,最初からプロジェクトを構築し直す必要があり,DeveloperStudioが自動生成したソースに手を加えることになりますので,注意が必要です.
▲VC++Tipsへ
VC++4.2とVC++5.0の互換ソース
VC++4.2とVC++5.0の差がどれだけあるのかは調べていませんが,今回の開発でわかった範囲を参考として記述しておきます.
1 bool宣言
4.2では将来の拡張用として予約されたトークンになっています.5.0では有効です.
ただし,yvals.h にプリコンパイルのマクロとして定義されていて,GUIバージョンのときには,stdafx.hを介してそのヘッダーファイルが展開されているようで,boolについては特別の対応はしなくていいのですが,コンソールアプリケーションの場合には,yvals.hを明示的にインクルードしておく必要があります.コンソールアプリケーションの場合には,すべてSubjDef.hでインクルードしておきます.
2 GaAppTpl.hとGpAppTpl.hの互換性
次の方法で対処しています.
// VC++4.2では以下のnamespaceをコメント化するが,VC++5.0では有効にする.
using namespace std;
つまり,using namespace std;をコメント化すると4.2対応,有効にすると5.0対応ということです.
3 VCStoreKeeperのViewStKp.cpp
5.0では,math.hをインクルードする必要がありませんが,4.2ではその必要があります.ところが,同インクルード文を有効にしたまま,5.0でコンパイルするとコンパイルが終わらないという現象が発生しました.したがって,互換性確保のためにコメント化法を採っています.
▲VC++Tipsへ
Dialogの継承とメッセージ処理
C++Builderでは,Form(Dialog)の継承を環境が直接サポートしているので,アプリケーション固有のダイアログに容易に変身させることができます.VC++では,そのレベルの継承はできません.
そのため,ダイアログを持つベースクラスのヘッダーと実装ソースファイルから継承したファイルを作成して,その中で,ベースクラスのダイアログの設計を変更することになります.
ベースクラスのコントロールのサイズや位置を変更したり,スタティックなコントロールを追加することは簡単なのですが,コントロールからのイベントを受け取る必要がある場合には少々めんどうになります(C++Builderではそれも含めて容易).
イベントを導出クラスで処理する方法としては,今回2つの方法を用いています.
1 単純(縁なし)ダイアログを用いる
イベントを発生するコントロールを貼りつけた単純(縁なし)なダイアログを新規に生成して,それを導出クラスの実装ファイルのプログラムとして貼り付ける方法です.結果として,導出クラスで,ベースクラスのダイアログに貼りつけることになります.要するに,ダイアログは,イベントを受け取るコンテナクラスとして使います.こうすることで,ClassWizardが認識できるクラスになりますので,あとはClassWizardでイベント処理を追加していけます.この方法を採ったのは,VCPackのSetPack.cpp(SetDlgからの導出クラス)とSetAdd.cpp(単純ダイアログ)です.
2 イベント受け取りのメッセージマップをコーディング
導出クラスのファイル中に,メッセージマップを扱うためのマクロを書き込む方法です.
これは,VCStoreKeeperフォルダのResultStKp.cppと同ヘッダーファイルで対応しています.
// ResultDlgから継承して,そのべースクラスが持っているボタンの
// 配置などを変更し,新たなボタン(IDC_RUN_BTN)を追加した.
// したがって,新規ボタンが生成するメッセージを受けつけるメッセージマップが
// 必要となる.これは,Class Wizardに頼るのではなく,直にコードを記述して
// 実現した.なお,IDC_RUN_BTNは,リソースタグのString Tableに新規追加で
// 登録しておいた.
// 以下のメッセージマップは,マニュアルで挿入
// なお,ResultStKp.hへの追加もある.
BEGIN_MESSAGE_MAP(ResultStKp, ResultDlg)
//{{AFX_MSG_MAP(ResultStKp)
ON_BN_CLICKED(IDC_RUN_BTN, OnRun)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
ベースクラスでは,ボタン等のイベントを受け取るイベントハンドラー(関数)を,ClassWizardで追加することができます.また他のメッセージも同様です.このように実装されたハンドラーは,ほとんどが仮想関数となっています.したがって導出クラスでは,これらをオーバーライドして,アプリケーション固有の振る舞いをインプリメントできます.
ただ,WM_PAINTメッセージのハンドラーにはafx_msgという指定がされていますので,導出クラスでオーバーライドすることができません.このため,いったん別のインタフェース関数を用意して,導出クラスで,WM_MESSAGEに対応できるようにしています.
▲VC++Tipsへ
ClassWizardにクラスが表示されない
他の,フォルダ等からファイルを当該フォルダへコピーしプロジェクトに追加して,ClassWizardで扱おうとしても,表示されません.どうもDevelopper
StudioとClassWizardとが連携していないようです.このようなときは,いったんプロジェクトを閉じて,*.cls(ClassWizardが生成するファイル)を削除して,再びプロジェクトを開いてください.
なお,削除は,ウィンドウズのレベルで行います.プロジェクトを開いた後に,ClassWizardを起動すると,ダイアログが出ますので,躊躇なくOKボタンをクリックします.これで,必要なクラスが扱えるようになります.
▲VC++Tipsへ
メインフレームに張付いているViewをコンソール風に使う
プログラムを立ち上げたときに広いクライアント領域が表示されます.ここを状況の表示エリアとしてコンソール風に使うわけです.したがって,複数の行を印字したり表示領域があふれたらスクロールするようにします.デフォルトではViewコントロールからの継承になっていますが,容易にスクロールを実現するため,プロジェクトの新規作成時にEditViewを親クラスとして指定します.
スクロールや複数行の表示を行うには,GaFrameView(またはGpFrameView)のPreCreateWindowに,次のようなコードを追加しておく必要があります.
BOOL CGaFrameView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: この位置で CREATESTRUCT cs を修正して Window クラスまたはスタイルを
// 修正してください。
BOOL bPreCreated = CEditView::PreCreateWindow(cs);
cs.style &= ~(ES_AUTOHSCROLL|WS_HSCROLL); // ワード ラップを使用可能にします
// 複数行を扱えるようにする(CR,LFで改行が行われるようにする)
cs.style |= ES_MULTILINE;
nL = 0;
return bPreCreated;
}
なお,C++Builder版では,MemoコンポーネントをFormに貼り付けています.
また,EditViewを使ったため,終了時にファイルへの書き出し確認ダイアログが出ますが,これを出さないようにするために MainFrm.cpp に以下の処理をつけ加えています.
void CMainFrame::OnClose()
{
:
//ドキュメント保存確認のダイアログを出さないようにする.
GetActiveDocument()->SetModifiedFlag( FALSE );
:
}
▲VC++Tipsへ
ビルト時,大量のコンパイルエラーが出る場合
◆回避策1----------------------------------------------------
ルト時,以下のようなコンパイルエラーが出た場合には,再度「ビルト」操作を行うと無事リンクまで済みます.
「再ビルト」ではなく「ビルト」です.
C:\MSDEV\INCLUDE\crtdbg.h(506) : error C2833: 'operator DEBUG_NEW' は演算子または型指定子のどちらでもありません。
C:\MSDEV\INCLUDE\crtdbg.h(506) : error C2059: 構文エラー : 'newline'
C:\MSDEV\MFC\include\afx.h(648) : error C2833: 'operator DEBUG_NEW' は演算子または型指定子のどちらでもありません。
C:\MSDEV\MFC\include\afx.h(648) : error C2059: 構文エラー : 'newline'
:
:
C:\MSDEV\MFC\include\afxtls_.h(145) : error C2143: 構文エラー : ';' が '*' の前に必要です。
C:\MSDEV\MFC\include\afxtls_.h(145) : error C2501: 'GetDataNA' : 識別名を宣言するのに、型が指定されていません。
C:\MSDEV\MFC\include\afxtls_.h(153) : fatal error C1061: コンパイラの制限 : プログラム内のブロックのネスティンクレベルが最大値を超えました
◆回避策2----------------------------------------------------
回避策1でもコンパイルエラーが出る場合,対象ソースファイルの中の以下の部分をコメント化します.
//#ifdef _DEBUG
//#define new DEBUG_NEW
//#undef THIS_FILE
//static char THIS_FILE[] = __FILE__;
//#endif
ただし,この方法では,このソースファイルのデバッグ時に何らかの支障がでるかもしれません.
以上の現象の原因は追求してはいませんが,メモリの量(筆者の環境は32M)が関係しているのかもしれません.
▲VC++Tipsへ
プロパティダイアログを用いずに,Staticコントロールの3D表示時くぼみ表示とする方法
以下のようにCreateメソッドのウインドウタイプ指定部分で行います.
CStatic* cS = new CStatic();
cS->Create( buf,
WS_CHILD | // 常時,約束事
WS_VISIBLE | // 表示させるために必要
SS_CENTER | // 文字列を横方向中央に置く
SS_SUNKEN | // これで,くぼみ表示とする.
WS_EX_CLIENTEDGE, // 縦方向中央に置ける.
rc,this );
ただし,WS_THICKFRAME を指定していると,SS_SUNKEN が無効になります.これは,VCAnt の SetAnt.cpp 中の SetAnt::OnInitDialog() で行っています.
▲VC++Tipsへ
cgaframe.cppのVC++6.0でのコンパイルエラー
cgaframe.cppのコンパイル時以下のコンパイルエラーがでることがあります.
「構文エラー : ';' が '--' の前に必要です。」
対応
前の行のコメント行が長すぎて,改行された結果です.この余計な行を削除してください.
▲VC++Tipsへ
g++Tips
本書を出版したあと,g++について判明したことを以下に記述します.
コンパイルエラーがなかなかとれない
コンパイルエラーがなかなかとれない
本CD-ROMにふくまれている Cygnus B20.1(gcc ver. egcs-2.91.57 199801(egcs-1.1 release)) で下記の現象がありました.
◆現象
class TRoomTApplication : public TSubject
{
protected:
.....
//何かのコメント
Period rm;
.....
};
struct Period { ..... }; は,このクラス定義の前に存在している.
このとき,あるメソッド内で,rmを参照すると,そこで未定義のコンパイルエラーとなる.
◆原因
「//何かのコメント」に起因していることが判明.
コンパイラのバグか?
◆対策
コメントを/* .... */形式に代える,コメント行を削除する.
▲g++Tipsへ
VC++バージョンの修正について
ここでは,VC++バージョンの各プログラムについて,これまでに判明したバグについてその修正個所をまとめておきます.
本書初版第1刷(2000/2/29発行)に付属のCD-ROMのVC++バージョンが対象となります.
本書初版第2刷(2001/2/28発行)以降に付属のCD-ROMに含まれるVC++バージョンの各プログラムについては,これらの修正は済んでいます.
なお,これらの修正については,すべて以下のバグについてのものです.
◆現象
多くの繰り返し処理を行っていると,「リソースが足りない」といったメッセージや特定メモリからリードできないなど,あるいは表示がおかしくなるなどの不都合が起こります.
Windows2000では,実行中にマウスのボタンクリックなどイベントが発生すると,動きがおかしくなることもあります.
◆原因
すべて,メモリーを解放すべき個所でそれを行っていなかったため,処理を繰り返していくうちにメモリが使えなくなったためです.以下の場合があります.
- new演算子でオブジェクトを確保し,役目を果たした後.この場合はdelete演算子でオブジェクトを削除しておかねばなりません.一部これを行っていない個所がありました.
- GetDC() を使いデバイスコンテキストを獲得したら,処理を行った後は,それを解放しなければなりません.
◆対処法
以下の変更点を参照してください.
・FrameWorkフォルダの共通の変更について
・VcPackフォルダ中の変更点について
・VcAntフォルダ中の変更点について
・VcStoreKeeperフォルダ中の変更点について
・変更上の注意点
FrameWorkフォルダの共通の変更について
(注) 次の1.の対象ファイルについては,GeAのGaFrameとVcpack及びGePのGpFrame,VcAntとVcStoreKeeperの各フォルダ中のFrameWorkフォルダに共通の変更です.
1.対象ファイル
- ・Fitgrpdlg.cpp 及び Fitgrpdlg.h
- ・Stagrpdlg.cpp 及び Stagrpdlg.h
変更点
(1) いずれも,DrawFitness,DrawRemarks,DrawStateなどの関数内で,GetDCを呼ぶようにし,その解放もそれら関数内で行うようにした.したがって,それらの引数 "CDC* pDC" を削除し,引数無しとした.
これに,関連する変更は以下である.
◆Fitgrpdlg.cpp
・WindowProc(....)の関数内で、以下のように,整理した.
if ( message == UWM_DRAWFITNESS )
{
SetGraphData();
DrawFitness();
}
return CDialog::WindowProc(message, wParam, lParam);
・OnPaintの関数内で、DrawFitnessとDrawRemarksを呼ぶ前のGetDC()をコールしている文を削除し,それぞれの関数の引数をなしとする.
.......
CDC* pDC = m_Graph.GetDC();
DrawFitness( pDC );
pDC = m_Remark.GetDC();
DrawRemarks( pDC );
.......
即ち,上記部分を,下記のように書き換える
.......
DrawFitness();
DrawRemarks();
.......
・DrawFitnessの関数内で、最初に以下の行を追加
CDC* pDC = m_Graph.GetDC(); // 必ずReleaseDCをコールすること
・最後に以下の行を追加
m_Graph.ReleaseDC( pDC ); // GetDCの後片付け
・DrawRemarksの関数内で、最初に以下の行を追加
CDC* pDC = m_Remark.GetDC(); // 必ずReleaseDCをコールすること
・最後に以下の行を追加
m_Remark.ReleaseDC( pDC ); // GetDCの後片付け
・以下の様にdelete cBを追加
//---- 背景を塗りつぶす
CBrush* cB = new CBrush( clTeal );
......
pDC->SelectObject( oldBrush );
delete cB; <--- この行を追加
....
◆Stagrpdlg.cpp
・WindowProc(....)の関数内で、以下のように,整理した.
if ( message == UWM_DRAWFITNESS )
{
DrawState();
}
return CDialog::WindowProc(message, wParam, lParam);
・OnPaintの関数内でDrawStateを呼ぶ前のGetDC()をコールしている文を削除し,それぞれの関数の引数を無しとする.
.......
CDC* pDC = m_State.GetDC();
DrawState( pDC );
.......
即ち,上記部分を,下記のように書き換える
.......
DrawState();
.......
・DrawStateの関数内で、最初に以下の行を追加
CDC* pDC = m_State.GetDC(); // 必ずReleaseDCをコールすること
最後に以下の行を追加
m_State.ReleaseDC( pDC ); // GetDCの後片付け
◆Fitgrpdlg.h
・DrawFitness,DrawRemarksのプロトタイプ宣言から引数をなくした.
◆Stagrpdlg.h
・DrawStateのプロトタイプ宣言から引数をなくした.
(2) new CBrush(...)の後片付け
◆Stagrpdlg.cpp
・DrawStateの関数内、以下の部分の最後の行(delete cB;)を追加した.
//---- 背景を塗りつぶす
CBrush* cB = new CBrush( clTeal );
CBrush *oldBrush = (CBrush*)pDC->SelectObject( cB );
RECT rc;
m_State.GetClientRect( &rc );
pDC->Rectangle( &rc );
pDC->SelectObject( oldBrush );
delete cB; <--- この行を追加
....
2.対象ファイル
- GeAのGaFrameとVcpackのFrameWorkフォルダのResultdlg.cpp
変更点:OnPaint関数内で,GetDCに対する解放処理を追加した.以下の様に追加
gI.cv = cw->GetDC();
gI.ox = orgX; gI.oy = orgY;
gI.wx = ImWid; gI.wy = ImHgt;
ViewApp->DrawBestSolution( gI );
cw->ReleaseDC( gI.cv ); <--- この行を追加
3.対象ファイル
- GePのGpFrame,VcAntとVcStoreKeeperの各フォルダ中のFrameWorkフォルダのResultdlg.cpp
変更点:OnPaint関数内で,GetDCに対する解放処理を追加した.以下の行を最後に追加
cw->ReleaseDC( gI.cv );
4.対象ファイル
- GePのGpFrame,VcAntとVcStoreKeeperの各フォルダ中のFrameWorkフォルダのConfmdlg.cpp
変更点:OnPaint関数内で,GetDCに対する解放処理を追加した.以下の行を最後に追加
cw->ReleaseDC( gI.cv );
▲VC++バージョンの修正についてへ
VcPackフォルダ中の変更点について
1.対象ファイル
- Setpack.cpp
変更点:DrawItems関数内で,GetDCに対する解放処理を追加した.以下の行を最後に追加
ReleaseDC( pDC );
▲VC++バージョンの修正についてへ
VcAntフォルダ中の変更点について
1.対象ファイル
- Setant.cpp
変更点:DrawItems関数内で,GetDCに対する解放処理を追加した.以下の行を最後に追加
ReleaseDC( pDC );
▲VC++バージョンの修正についてへ
VcStoreKeeperフォルダ中の変更点について
1.対象ファイル
- Setstkp.cpp
変更点
・DrawItems関数内で,GetDCに対する解放処理を追加した.以下の行を最後に追加
ReleaseDC( pDC );br>
2.対象ファイル
- Rundlg.cppbr<br>
変更点
・OnPaint関数内で,GetDCに対する解放処理を追加した.以下の行を最後に追加
wD-&gt;ReleaseDC( pDC );<
▲VC++バージョンの修正についてへ
変更上の注意点
本書の初版2刷に添付のCD-ROMには,上記の変更が反映されていますが,初版のCD-ROMの該当ファイルを修正する場合,以下の点にご注意ください.
- 原則として,各アプリケーションフォルダ内のFrameWorkフォルダの中身は同一です.したがって,いずれかのFrameWorkフォルダ中の該当ファイルを変更したら,FrameWorkフォルダごと,他のアプリケーションフォルダ内のFrameWorkフォルダと置換えることができます.
- ただし,リソースが追加されているような場合は,FrameWorkフォルダ内にリソースファイルがありますから,無闇に置換えると,ビルド時に「IDC_****が無い」などのエラーに遭遇することになります.
したがって,修正が完了したファイル単位で移し替えておいたほうがいいでしょう.
VcStoreKeeperの場合が,それにあたります.
- その他,CD-ROMご案内も参照してください.
▲VC++バージョンの修正についてへ
ご注意
※CD-ROMから各ファイルをコピーした後に「書き込み禁止」属性を取り除いてください.
README更新履歴
2000/01/25 |
初版 |
2000/09/01 |
「VC++6.0におけるコンパイル等」、「VC++6.0でのコンパイルエラー」、「g++Tips」の項目を追加 |
2001/02/16 |
「VC++バージョン修正について」を追加 |
2003/06/04 |
「VC++ .NETスタンダード版におけるコンパイル」を追加 |
|