64bit Windows C++の最近のブログ記事

ウィンドウサイズを固定する

| コメント(0) | トラックバック(0)   このエントリーをはてなブックマークに追加 このエントリーを含むはてなブックマーク

続いて、ウィンドウサイズを固定することを考える。

前回の「設定」と今回の「固定」はどう違うかというと、
ここで「固定」とは、一度決めたサイズはユーザーが変更できないようにするということである。

前回作成したウィンドウだが、
ウィンドウエッジにマウスカーソルを持っていけば、マウスカーソルの形が変わって
ウィンドウサイズを自由に変更できるようになっている。
これでは、せっかく設定したウィンドウサイズも意味がない。

手っ取り早くウィンドウサイズを固定するには、
CreateWindow関数の第3引数から、WS_THICKFRAMEの値を引けばよい。
現在のプログラムは、WS_OVERLAPPEDWINDOWなので、
ここからWS_THICKFRAMEの値を引くには、

WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME

とする。(ビット演算なので、単なる引き算ではダメ)

ついでに、ウィンドウの最大化も封印(使用不可)としよう。
この場合は、同じようにWS_MAXIMIZEBOXを引けばよい。

よって、プログラムのCreateWindow関数の呼び出しは、次のようになる。

hWnd = CreateWindow(szClassName, lpCmdLine,
                    WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX,
                    CW_USEDEFAULT, CW_USEDEFAULT, 320, 240, NULL, NULL, hInstance, NULL);

ちなみに、winuser.hでWS_OVERLAPPEDWINDOWの定義を見てみると、

#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU
                           | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)

となっている。
WS_OVERLAPPEDWINDOWがそもそも、他の値を組み合わせて作られたもののようだ。

ウィンドウサイズを設定する

| コメント(0) | トラックバック(0)   このエントリーをはてなブックマークに追加 このエントリーを含むはてなブックマーク

前回作成したウィンドウだが、
ゲームの場合は、背景画像が固定サイズなので、ウィンドウサイズを設定する必要がある。
(小さなチップ画像を組み合わせて背景を作成するなら、その必要はない)

今回は、背景画像のサイズを800×600とする。
スマートフォン向けアプリを作るならもっと小さいサイズを検討せねばなるまいが、
PC用のWindowsアプリを作成するなら、この程度のサイズが要るだろう。

まず、ウィンドウのサイズを800×600にするといっても、
以前作成したプログラムのCreateWindow関数の引数320, 240を変えればよいというわけではない。
800×600というのは、ウィンドウのクライアント領域(内容を表示する領域)のサイズなので、
実際のウィンドウサイズは、これにタイトルバーやウィンドウエッジが含まれたサイズとなる。

clientwindowsize.png

ウィンドウサイズを設定するには、SetWindowPos関数を呼ぶ。
第1引数にウィンドウハンドル、
第2引数にZオーダー(ウィンドウが重なる場合に表示される順)を指定するためのウィンドウハンドル
第3引数にディスプレイの表示位置(左端からのピクセル数)、
第4引数にディスプレイの表示位置(上端からのピクセル数)、
第5引数にウィンドウの幅、
第6引数にウィンドウの高さ、
第7引数にウィンドウ位置のオプションを指定する。

クライアント領域を設定するところがどこにもないじゃないか、
と、途方に暮れる前に、まず現在のウィンドウから、
タイトルバーやウィンドウエッジの部分のサイズを取得することにしよう。
設定するクライアント領域のサイズに、これらのサイズを加えれば、設定したいウィンドウサイズになる。

タイトルバーやウィンドウエッジの部分のサイズを取得する最も楽な方法は、
現在のウィンドウサイズから、現在のクライアント領域のサイズを引けばよい。

現在のウィンドウサイズはGetWindowRect関数、
現在のクライアント領域のサイズはGetClientRect関数で取得できる。
いずれの関数も、第1引数はウィンドウハンドルで、第2引数はRECT構造体だ。

CreateWindow関数の後に、次のようなコードを追加しよう。

RECT rx; //ウィンドウ領域
RECT cx; //クライアント領域
GetWindowRect(hWnd, &rx);
GetClientRect(hWnd, &cx);

これでそれぞれのRECT構造体に左端(left)、上端(top)、右端(right)、下端(bottom)が入る。
それを踏まえて、新しいウィンドウサイズは、次のように指定することになる。

const int new_width = 800 + (rx.right - rx.left) - (cx.right - cx.left);
const int new_height = 600 + (rx.bottom - rx.top) - (cx.bottom - cx.top);

幅new_widthについては、
rx.right - rx.leftはウィンドウの幅を表し、
cx.right - cx.leftはクライアント領域の幅を表す。
上から下を引けば、ウィンドウエッジのサイズとなるから、これに設定したいクライアント領域の幅を足せばよい。

それでは、SetWindowPos関数を呼んでみよう。

SetWindowPos(hWnd, NULL, 0, 0, new_width, new_height, SWP_SHOWWINDOW);

コンパイルして実行したら、クライアントサイズが800×600のウィンドウが表示されたはず。

しかし気になるのは、必ずディスプレイの左上にウィンドウが表示されることだ。
できればディスプレイの中央に表示するようにしたい。

表示位置は、先のSetWindowPos関数の第3,4引数で指定すればよいのだが、
その値はどのように取得すればよいだろうか。

これにはまずディスプレイのサイズを取得する必要がある。
次のように、GetSystemMetrics関数で取得する。
SetWindowPos関数の前に追加しよう。

const int disp_width = GetSystemMetrics(SM_CXSCREEN);
const int disp_height = GetSystemMetrics(SM_CYSCREEN);

横方向は、(ディスプレイの幅-ウィンドウの幅)/2、
縦方向は、(ディスプレイの高さ-ウィンドウの高さ)/2
とすると、ウィンドウが画面の中央に表示される。

では改めてSetWindowPos関数を呼んでみよう。

SetWindowPos(hWnd, NULL, (disp_width - new_width) / 2, (disp_height - new_height) / 2,
             new_width, new_height, SWP_SHOWWINDOW);

今度はディスプレイの中央に表示された。

最後に。
最近のPCのディスプレイは従来のような4:3のサイズ比ではなく、16:9のサイズ比が多いようだ。
もしも実行環境が16:9のサイズ比であっても、ウィンドウそのものは4:3で構わないのだが、
もしフルスクリーン化することを考えるなら、ウィンドウを16:9のサイズで作成し
4:3のサイズからはみ出る両端部分を
黒帯(や見栄えのよい画像)で埋めることも考えなければならないだろう。

バージョン情報を付加する

| コメント(0) | トラックバック(0)   このエントリーをはてなブックマークに追加 このエントリーを含むはてなブックマーク

本題からは離れるが、実行ファイルにバージョン情報を付加することを考える。
本来なら、ソフトが出来上がった後にやればいいことだ。
なぜこの段階でこんなことする気になったのだろうか。謎だ。

さて、ここでのバージョン情報とは、
エクスプローラー上で実行ファイルを右クリックして表示されるポップアップメニューから
「プロパティ」を選択して、「詳細」タブに表示される各種情報のことだ。
ファイルの説明とかバージョンとか、著作権を表示することができる。
Visual StudioやBCBであれば、プロジェクトのプロパティで
それぞれの項目を指定してビルドすると、自動的にバージョン情報が実行ファイルに付加されるのだが
これを自力で行う場合、リソースファイルというものを使用する。

こんなファイルを用意する。(version.rc)

#include <winver.h>
 
//
// Version Information
//
 
VS_VERSION_INFO    VERSIONINFO
FILEVERSION     1,0,0,0
FILEFLAGSMASK   VS_FFI_FILEFLAGSMASK
FILEFLAGS       VS_FF_PRERELEASE
FILEOS          VOS_NT_WINDOWS32
FILETYPE        VFT_APP
{
    BLOCK "StringFileInfo"
    {
        BLOCK "041104b0"
        {
            VALUE "CompanyName",      "ColorWorks\0"
            VALUE "FileDescription",  "SampleWindow\0"
            VALUE "FileVersion",      "<FILEVERSION>\0"
            VALUE "InternalName",     "Sample\0"
            VALUE "OriginalFileName", "Sample.exe\0"
            VALUE "LegalCopyright",   "(C)ColorWorks\0"
            VALUE "ProductName",      "Sample\0"
            VALUE "ProductVersion",   "3.10\0"
        }
    }
    BLOCK "VarFileInfo"
    {
        VALUE "Translation", 0x411, 1200
    }
}

それぞれの項目の詳細は...誰か教えてくださいorz
これに関わるネット上の情報が古いことから、
最近ではバージョン情報を実行ファイルに付与すること自体がナンセンスなのかもしれない。

いくつか、ポイントを書いておく。

1行目のwinver.hは、代わりにwindows.hでも可。
なぜならwindows.hの中でwinver.hをインクルードしているため。

ファイルのバージョンは、8行目のFILEVERSIONの後に記載する。
数字はカンマ区切りであり、ピリオドでは区切らない。

16行目の"041104b0"は、日本語のコードページを表す。
英語のコードページだと"040904b0"になるらしい。

30行目の0x411, 1200は、16行目の"041104b0"に合わせる。
上4桁の0411はそのまま16進数で0x0411、下4桁の04b0は10進数に変換して1200。
合わせなくてもコンパイルできるが、合わせないとバージョン情報が適切に表示されない。

18行目のCompanyNameは会社名。サークル名でも良いと思う。
19行目のFileDescriptionはファイルの説明。
20行目のFileVersionはファイルのバージョン。<FILEVERSION>とすると、先に指定した値が参照される。
21行目のInternalNameは内部名。ハッキリ言って要らない気がする。
22行目のOriginalFileNameは元のファイル名。同上。
23行目のLegalCopyrightは著作権。
24行目のProductNameは製品名。
25行目のProductVersionは製品バージョン。ファイルバージョンとは異なる。

さて、ファイルが出来上がったら、ビルドすればOKなのだが、
これがEclipse+MinGW環境ではかなり厄介であった。

ちなみに、コマンドラインからMinGWでビルドするなら、次のようにすればよい。
1.windresでversion.rcをコンパイルし、version.oを出力
> windres ..\src\version.rc src\version.o
2.SampleWindow.cppをコンパイルし、SampleWindow.oを出力
> g++ -Wall -c -o src\SampleWindow.o ..\src\SampleWindow.cpp
3.SampleWindow.oとversion.oをリンクし、実行ファイルを作成
> g++ -mwindows -o Sample.exe src\SampleWindow.o src\version.o -lgdi32

これを踏まえて、Eclipseでは次のように行う。
1.プロジェクトのプロパティから左側のツリービューで「C/C++ビルド」→「設定」を選択
2.設定ウィンドウの中で「ビルド・ステップ」タブを選択し、ビルド前のステップのコマンド欄に
  windres ../src/version.rc -o version.o と入力する。
3.設定ウィンドウを閉じて、一度ビルドする。(「プロジェクト」→「すべてビルド」)
4.プロジェクトエクスプローラーを選択してリフレッシュする(F5キーでも可)
  すると、プロジェクトエクスプローラー上にversion.oが表示される。
5.再度プロジェクトのプロパティを開き、
  設定ウィンドウの「ツール設定」タブを選択し、「MinGW C++ Linker」→「その他」を選択
  「その他のオブジェクト」の右にある追加アイコンを選択すると、ファイルの入力ダイアログが表示される。
  「ワークスペース」ボタンを押し、上で出力されたversion.oを選択してダイアログを閉じる。
6.もう一度ビルドする。

ああ面倒くさい。

さらに面倒なことに、Eclipseは一度ビルドしたプログラムを再度ビルドしようとしても
ソースコードが変わっていなければ「再ビルドの必要なし」と判断してしまうのだが
リソースファイルはソースコードでないと思われているのか、
リソースファイルだけを変更して再ビルドしようとしても反映されない。
また、一度「プロジェクト」→「クリーン」で生成されたオブジェクトファイル等をクリアしてしまうと
再ビルドそのものがエラーになってしまう。

**** Internal Builder is used for build ****
Build error
Path must include project and resource name: /Sample

こうなってしまった場合は、
上記5で設定したversion.oのリンク設定を一旦削除し、
3以降の手順を行えば生成される。

ああ面倒くさい。
makefileで片づける方がよっぽど楽な気がする。

ウィンドウを表示する

| コメント(0) | トラックバック(0)   このエントリーをはてなブックマークに追加 このエントリーを含むはてなブックマーク

VBやDelphiやBCBなら、わざわざプログラムを書かなくても
プロジェクトを作成して実行ボタンを押すだけで表示されるウィンドウだが、
敢えて自分でプログラムを書くなら、最低限これだけ書かなければならない。

今回はSampleWindow.cppというファイルを作成した。


#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

char szClassName[] = "SampleWindow";

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPreInst, LPSTR lpCmdLine, int nCmdShow) {
HWND hWnd;
MSG msg;
WNDCLASS wndcls;
if (!hPreInst) {
wndcls.style = CS_HREDRAW | CS_VREDRAW;
wndcls.lpfnWndProc = WndProc;
wndcls.cbClsExtra = 0;
wndcls.cbWndExtra = 0;
wndcls.hInstance = hInstance;
wndcls.hIcon = NULL;
wndcls.hCursor = LoadCursor(NULL, IDC_ARROW);
wndcls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndcls.lpszMenuName = NULL;
wndcls.lpszClassName = szClassName;
if (!RegisterClass(&wndcls)) {
return FALSE;
}
}
hWnd = CreateWindow(szClassName, lpCmdLine, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 320, 240, NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0L;
}

このプログラム自体はWeb上にいくらでも(解説つきで)転がっているので、
個々の処理が何をしているものなのか、説明は割愛させていただく。

ではコンパイルしてみよう。
Eclipseのメニューから「プロジェクト」→「すべてビルド」を選択すると、
コンパイル・ビルド・リンクが自動的に行われ、
問題なければ実行ファイルがプロジェクトのDebugフォルダに出力される。

で、コンパイルしてみたら、エラーが表示された。
Eclipseのエラー表示ビューに、こう表示されている。


undefined reference to `__imp_GetStockObject' SampleWindow.cpp /Sample/src 行 19 C/C++ 問題

原因が分からないときはとりあえずググる。
GetStockObjectというAPIが、gdi32に入っているので、これをリンクしないといけないらしい。
MinGWだけでコンパイルするなら、コンパイルオプションに-lgdi32を加えればよいだろう。

Eclipseでリンクの設定を行う場合、プロジェクトエクスプローラーでプロジェクト(ここではSample)を選択し、
メニューの「プロジェクト」→「プロパティー」を選択する。
現れたウィンドウの左側にあるツリービューから「MinGW C++ Linker」→「ライブラリー」を選択し
追加ボタンを押して現れるウィンドウにgdi32を入力すればOK。

link_gdi32.png

では再びコンパイルしてみよう。今度はエラーは表示されない。
Debugフォルダに、Sample.exeが出力されている。

いざ実行!
...してみたが、ウィンドウらしきものは表示されない。代わりにコマンドプロンプトが表示されている。

Eclipseからでもこのファイルを実行できる。
メニューの「実行」→「実行構成」で実行構成ウィンドウを表示し、
実行構成を作成すれば、自動的にこのファイルを実行する構成ができるだろう。
もちろん、Eclipseから実行しても、ウィンドウらしきものは表示されない。

ググってみたところ、MinGWでウィンドウを表示するプログラムを作成する場合、
コンパイルオプションに-mwindowsをつけなければならないようだ。
それでは先程の要領で、-mwindowsをコンパイルオプションに追加してみよう。
ただし、今度は-lオプションではないため、
「MinGW C++ Linker」→「その他」を選択し、
リンカー・フラグ(分かりにくいが、ウィンドウの右上にある)欄に-mwindowsを追加する。

再度コンパイルし、出力されたSample.exeを実行してみよう。

味もそっけもないウィンドウ

ようやくウィンドウが表示された。今度はコマンドプロンプトも表示されていない。

Eclipse CDT + MinGW

| コメント(0) | トラックバック(0)   このエントリーをはてなブックマークに追加 このエントリーを含むはてなブックマーク

MinGWのセットアップが終わったところで、
統合開発環境EclipseからMinGWを実行することを試みる。

MinGWだけでコンパイルできるんだから、
わざわざ統合開発環境なんぞ使わなくてもいいのだが、
プロジェクトを構成するファイルが複数にまたがってくると管理が覚束ないし、
コードフォーマット整形やインテリセンス(入力候補の提示)といった機能はありがたい。
Eclipseなら無料で使用できる上に、生成されたバイナリがEclipseに依存するわけでもない。

というわけでEclipseを導入する。

まず、というか、そもそも、EclipseはJavaの開発環境であったが、
有志により他の言語向けのプラグインが開発され、
そのうちの一つがC++用プラグインCDTである。

Eclipseそのものは、JavaVM上で動作するので、まずJavaVMを入手する。
(面倒な人は、All in One Eclipseを導入すればJVMごと入手できるが、
 現在のところ32bit向けしか公開されていない)

OracleのJava SEサイトからJava SE 6の最新バージョンを入手してインストールする。
(Java SE 7も公開されているのでそれでも大丈夫だと思うが、
 個人的には6の方が安定していそうな気がするので6を使用する)
JDKとJREが公開されているが、JDKの中にJREが入っているので、どちらでも構わない。

次にEclipse CDTのサイトから
"Download"のページを開き、最新版のCDTを入手する。
現在は"Eclipse package: Eclipse C/C++ IDE Indigo SR-1."が最新版のようだ。
ちなみにIndigoはEclipse3.7の別名。
ダウンロードページにて、"Download Links"から"Windows 64-bit"を選択し、
適当なミラーサイトからダウンロードする。

ダウンロードファイルはzip形式であるため、
ダウンロードしたら、適当な(間に半角スペースが存在しない)パスに展開する。

次に日本語化を行う。
英語版のままでも問題ない人はスルーで。

MergeDoc Projectから
Pleiadesの最新版を入手し、展開してEclipseのインストールフォルダにコピーする。
(詳しいインストール方法は、Pleiadesのreadmeを読むこと)

ではようやくEclipseを起動する。Eclipseインストールフォルダのeclipse.exeを実行するだけ。
「ようこそ」画面が表示されたらOK。

「ようこそ」画面の右上にある×ボタンを押して閉じ、新規プロジェクトを作成してみよう。
メニューの「ファイル」→「新規」→「C++ プロジェクト」を選択すると、新規作成ウィンドウが表示される。
プロジェクト名に"Sample"、プロジェクトタイプを「実行可能」→「空のプロジェクト」を選択する。
ここで、コンパイラを選択する。ウィンドウ右側の「ツールチェーン」にMinGWが表示されていれば、それを選択して
「完了」ボタンを押したらプロジェクトが生成される。

が、自分はツールチェーンにMinGWが表示されなかった。
何故だろう。
方々のWebサイトでは、環境変数PATHに(MinGWのインストールフォルダ)\binを追加すれば良いと書かれていたが、
自分はこれをやっても改善されず。

他のEclipse+MinGW導入手順サイトを見たり、
上のMergeDocで32bit用のAll in one Eclipseをダウンロードして
構成を比較したりしたところ、以下のいずれかのようにすればEclipseにMinGWが認識され、
Eclipseのツールチェーンに表示されることが判明した。

・MinGWをC:\MinGWにインストールする(これ以外のドライブやフォルダはNG)
・Eclipseのインストールディレクトリ配下にMinGWをコピーする

前者は、MinGWを他のパスに置いて、Eclispeの設定画面からMinGWのパスを設定してもダメなようだ。
逆に、C:\MinGWに置いてあれば、Eclipseで設定せずとも認識された。
後者は、Eclipseインストールフォルダ直下にmingwフォルダを配置する必要がある。

では次回は、この作成したプロジェクトでサンプルプログラムをコンパイルしてみよう。

MinGW (64bit)のインストール

| コメント(0) | トラックバック(0)   このエントリーをはてなブックマークに追加 このエントリーを含むはてなブックマーク

まず、MinGWの64bit版を入手する。
なお、以下のリンク先は本記事作成時の情報であるため、
今後の状態は変更されている可能性があることをご留意いただきたい。

SourceForgeのMinGW-w64から、
"Browse All Files"→"Toolchains targetting Win64"→"Personal Builds"
→"sezero_4.5_20111101"の順にリンクを辿ると、次の5つのファイルが表示される。

  • mingw-w64-bin_i686-linux_20111101_sezero.tar.gz
  • mingw-w64-bin_i686-mingw_20111101_sezero.zip
  • mingw-w64-bin_x86_64-linux_20111101_sezero.tar.gz
  • mingw-w64-bin_x86_64-mingw_20111101_sezero.zip
  • README-mingw-w64-20111101_sezero.txt

解説ページによると、ファイル名の形式は次のようになっているとのこと。

<Target>[-Version]-<Src/Bin>-<Host>[-Cygwin Version]_<Date Code>[_personal tag].[extension]

<Target>は、"mingw-w32"または"mingw-w64"で、
前者はWin32用のバイナリを生成するバージョン、後者はWin64用のバイナリを生成するバージョン。
ここはWin64用のMinGW配布サイトであるため、前者のファイルはここでは公開されていない。

[-Version]は、"-1.0"または欠落。

<Src/Bin>は、配布されているアーカイブがソースコードであるか、実行形式であるか。
今回はコンパイラが手に入ればよいため、Binで良い。
というかBinしか公開されていない。

<Host>は、"i686-cygwin"または"i686-mingw"または"i686-darwin"または"x86_64-linux"または"i686-linux"で
MinGWを実行させる環境、つまり開発環境を選択する。
i686なら32bit用、x86_64なら64bit用となる。
上の5ファイルは、ここのいずれにも該当していないが、
x86_64-mingwで問題ないだろう。

[-Cygwin Version]はCygwinのDLLのバージョンらしいが、ここではどのファイル名でも欠落している。

<Date Code>はアーカイブが生成された年月日で、YYYYMMDD形式。
ここでは、2011年11月01日に生成されたようだ。

[_personal tag]は、作成者が個人でビルドしたパッケージに対して、その作成者名が付くらしい。
ここではsezeroさんがビルドしたようだ。

[extension]は拡張子。
ここでは、tar.gzか、zipとなる。

以上から、今回取得するパッケージは、上から4つ目の
mingw-w64-bin_x86_64-mingw_20111101_sezero.zipとなる。

ダウンロードしたら、適当なフォルダに展開する。
今回はD:\mingw64\に展開してみた。

さて、早速何かコンパイルしてみよう。
Cのプログラムを用意する。(test1.c)

#include <stdio.h>
 
int main()
{
    printf("hello,world.\n");
    return 0;
}

コマンドプロンプトから、
> D:\mingw64\bin\gcc test1.c -o test1.exe
と入力すると、コンパイルとリンクが行われ、test1.exeが出力される。
実行すると、標準出力にhello,world.と表示される。

方々のWebサイトでは、MinGWと同時にMSYSも入れているようだが、
少なくともコマンドプロンプトでコンパイルできることが分かった。
MSYSは最低限のUNIXコマンドを提供してくれるようだが、
特に必要でなければ、入れなくてもよさそうだ。
MinGWはzipを展開するだけでよかったが、
MSYSはインストール作業(いわゆるsetup.exeやmsiを起動すること)が要るみたいだから、
setup.exeで何がインストールされるか分からないことに比べると、
個人的には幾分抵抗が小さい。

開発環境を考える

| コメント(0) | トラックバック(0)   このエントリーをはてなブックマークに追加 このエントリーを含むはてなブックマーク

では退路を確保したところで、冒険に出てみよう。(←大げさな)

このカテゴリでの条件は、先述のとおり次の3つである。
・無料で準備できる
・ゲーム用のライブラリを使わない
・ランタイムを必要としない

また、作成したものを配布するためには、ライセンスを考慮する必要がある。
ライセンスといっても様々であるが、端的に言えば
「作成した実行ファイルを配布しても法律上・社会通念上、問題にならない」ようなものであればOKだ。

気を付けなければならないのは、GPLライセンスのように、
「そのライブラリを用いて作成したソフトウェアは、ソースコードを含めて公開しなければならない」ような
厳しいライブラリを使用してしまうと、
ソースコードを非公開としたいソフトを作ることができなくなってしまうことだ。
(厳密にはやや異なるかも。解釈が難しいライセンスなので)

一般的には、有償の開発環境で開発したソフトウェアは、
(条件付きの場合もあるが)ソースコードを非公開として配布することができる。
無償の開発環境でこの条件に合致するものは、実は数えるほどしかない。

有償・無償を区別せず、昨今のC++言語用開発環境をまとめてみよう。

No.開発環境名有償/無償開発したソフトの配布64bit対応(開発側)64bit対応(動作側)認知度
1Microsoft Visual C++両方あり(※1)対応対応(※2)
2Embarcadero C++ Builder有償対応対応(※3)
3Borland C++ Compiler無償非対応(※4)非対応
4MinGW無償対応対応
5Qt両方あり(※5)(※5)不明不明不明

※1:
 Visual C++ Expressは無償。インストール後30日以内に製品の登録が必要。

※2:
 Visual C++ Express単体では64bitアプリケーションを開発できないため、
 Windows SDKと合わせて利用する。こちらも無償。

※3:
 エディションによる。高価なエディションほど(以下略)

※4:
 64bit環境で動作しないとされているのは、提供元が動作を保証していないという意味で、
 実際には動作する可能性もある。(未検証)

※5:
 製品ライセンスは有償。オープンソース版は無償。
 オープンソース版はLGPLライセンスのため、条件により開発したソフトのソースコードも公開する必要あり。


64bit対応(開発側)とは、64bitのOSで開発環境が動作するということ。
64bit対応(動作側)とは、64bitアプリケーションが開発できるかということ。

なぜ「認知度」なんて項目があるか?
そりゃ、困ったときにググればどれほど頼りになる情報が手に入るか(ry

そんなわけで。
無償で入手できて、開発したソフトをライセンスを気にせず公開できて、
64bit対応なのは、VC++とMinGWくらい。

ググった感じではVC++派が多そうな気がするんだが、
なんとなく個人的にMSのお世話になりたくないので(Windows使ってる時点で世話になってるけど)
・まずMinGWでチャレンジ
・どうしようもなくなったらVC++のお世話になるかも
くらいの気持ちで行こうかな。

では次回から開発環境を準備してみよう。

まず退路を確保する

| コメント(0) | トラックバック(0)   このエントリーをはてなブックマークに追加 このエントリーを含むはてなブックマーク

何やってんだかと思わないでもないが、
64bit C++での開発が頓挫した場合の手段を講じておく。
そうしておかないと、頓挫した際に新作のプログラムを用意できないから。

で、今まで書いたことがなかったかもしれないが、
「えすてぃ」以降の作品は、すべてBorland C++ Builder6 (Professional Edition)で作成している。
(以下BCB6と略す)
BCB6はWindows XPには対応しているが、Windows VistaやWindows 7には公式には対応していない。
そしてBCB6は発売から10年ほど経過し、すでに発売した会社もなくなっている。
※厳密には、売却やら買収やらで残った会社が後継のソフトを販売しているが、
 本カテゴリのポリシーに従い、それに頼るのは最後の手段とする。

公式には対応していなくてもいいから、使用できないか試してみた。
その手順を記す。


1.管理者権限を持つユーザーで、プロダクトCDからインストールする。
  標準インストールでは、"C:\Program Files (x86)\Borland\CBuilder6"にインストールされる。
2.メーカーのWebサイトから、最新版(と言っても公開されたのは9年近く前だが)の
  アップデートを入手し、インストールする。
3.ショートカット「すべてのプログラム」→「Borland C++ Builder 6」→「C++ Builder 6」で起動する。

起動すると、次のエラーダイアログが表示された。


'C:\Program Files (x86)\Borland\CBuilder6\Bin\bcb.$$$' から 'C:\Program Files (x86)\Borland\CBuilder6\Bin\bcb.dro' に変更できません.

エラーダイアログが表示されるが、ソフトそのものは起動する。

でも起動の都度エラーダイアログが表示されるのも目障りだ。
調べてみると、どうもUAC(ユーザーアカウント制御)が原因らしい。
3.のショートカットの実体は"C:\Program Files (x86)\Borland\CBuilder6\Bin\bcb.exe"なので、
このプログラムのプロパティを開き、互換性タブで「管理者として実行」にチェックを入れる。

bcb1.png

再度起動してみると、
起動時にUACの確認ダイアログ(このプログラムを起動してよいか尋ねられる)が表示されるが、
先ほどのエラーダイアログは表示されなかった。


次に、既存の作品のプロジェクトファイルをダブルクリックしてBCB6を起動してみる。
従来なら、拡張子.bprが関連付けられているため、ダブルクリックするだけで
BCB6が起動し、そのプロジェクトが開かれるのだが...。


プログラムにコマンドを送信しているときにエラーが発生しました。

またエラーダイアログだ。
一応ソフトは起動するが、プロジェクトは開かれない。
その状態で再度bprファイルをダブルクリックするか、
BCB6のメニューで「ファイル」→「プロジェクトを開く」でbprファイルを選択すれば、
プロジェクトを開くことができた。


どうやらこのエラーはBCB6に限ったものではなく、
アプリケーションのデータファイルから起動すると発生するもののようだ。
Web上でよく見られたのは、Excelのxlsファイルをダブルクリックしたら表示された等々。

このエラーもUACに関係するものらしく、方々のWebサイトでは
先述の互換性タブにて「管理者として実行」をチェックするとか、しないとか、
互換モードでWindows XP(SP3)に変更するとか、しないとか、
統一されていなかった。
どうもケースバイケースらしい。
※他にも、ウィルス対策ソフトを止めたらエラーが表示されなかった、等

こちらで試してみたところ、次の結果だった。
・管理者として実行ON+WinXP互換モードON→エラー
・管理者として実行OFF+WinXP互換モードON→エラー
・管理者として実行ON+WinXP互換モードOFF→エラー
・管理者として実行OFF+WinXP互換モードOFF→エラー
つまり、結局エラーが出たということ。


他のアプローチとして、
assocコマンドとftypeコマンドで関連付けを変えることを考える。
まず、コマンドプロンプトを管理者権限で起動し、次のコマンドで確認した。

> assoc .bpr
.bpr=BCBProject
> ftype BCBProject
BCBProject=C:\Program Files (x86)\Borland\CBuilder6\Bin\bcb.exe /np

bcb.exeのオプション/npは、起動時に新規プロジェクトを開かないようにするらしい。
次のように、コマンドプロンプト上で直接コマンドを入力して起動すると、
エラーなく起動し、プロジェクトも開かれた。
"C:\Program Files (x86)\Borland\CBuilder6\Bin\bcb.exe" D:\xxx.bpr

次に、ftypeコマンドでBCBProjectの関連付けを変更してみた。

> ftype BCBProject=C:Program Files (x86)\Borland\CBuilder6\Bin\bcb.exe %1
BCBProject=C:\Program Files (x86)\Borland\CBuilder6\Bin\bcb.exe %1

その後、
・コマンドプロンプトからbprファイルを実行→エラー変わらず
・bprファイルをエクスプローラ上でダブルクリック→エラー変わらず
やっぱりエラーが表示される。
exeファイルのフルパスや%1をダブルクォートで括っても、結果は同じ。

対処法が他に思い当たらないし、起動しないわけではないことが分かったので、これで良しとする。
少なくともショートカットからBCB6を起動し、その後メニューからプロジェクトを開けば使えるのだから。

試していないが、BCB6をC:\Program Files (x86)\以下にインストールすると
UACの対象となり、正常に動作しないかもしれないので、他のフォルダにインストールする方がいいかもしれない。


プロジェクトを開けたところで、再構築(フルビルド)を行う。
旧PCでは結構時間がかかった再構築が、あっという間に終了。
実行ファイルが生成され、起動してみたが特に問題はなかった。

64bit Windows7でC++プログラムを書く

| コメント(0) | トラックバック(0)   このエントリーをはてなブックマークに追加 このエントリーを含むはてなブックマーク

以前の記事
パソコンを買い替えたら開発環境をどうしよう?なんてことを書いたわけだが、
つい先日パソコンを買い替え、開発環境で悩むこととなった。

さてどうしよう。
64bit Windows用の開発環境製品を購入すれば解決なのだが、それではプログラマとして面白くない。
よって、それは最後の手段にして、とりあえずタダでできるところまでやってみようか。

まずは目標を立てよう。
当サークルの「アドベンチャーゲーム設計論」で作成したサンプルを
64bit Windows7 でC++言語を用いて作成する。
そのために検証用のサンプルプログラムを作成し、試行錯誤することを繰り返す。

期間は...特に設けない。
自分が飽きるか、技術的に無理だと分かったところで終了とする。
願わくば、前者とならないことを祈るばかりだ。後者も嫌だが。

次に制約事項を考える。

1.費用をかけない
 先述のとおり、とりあえずタダでできる範囲でやってみたい。
 (値段の差はあるだろうが)ソフトや書籍を買うくらいなら、開発環境を買えば終わりだからだ。

2.無償のツール類を使わない
 と書くと語弊が生じそうだが、ここでのツール類とは
 いわゆるツクール系のソフトや、ゲーム開発支援用の各種ライブラリを指す。
 これらは使わない。使ったら負けだ(意味不明)。
 逆に、汎用ソフト向けに公開されているライブラリは使用することもあるであろう。

3.何かのランタイム上で動作させるソフトにしない
 汎用ソフト向けとはいえ、.NET FrameworkやJava VM上で動作させるソフトにはしない。
 最近のWindows7なら.NET Frameworkはインストール済みのようであるが、
 細かいバージョンの差異によって、作成したソフトが動作しないことはあるだろうし、
 かと言って動作するランタイムごと配布するのはPCのシステム設定を変えてしまう。
 これは利用者にとって二の足を踏むだろうから、避けたい。
 律儀にWin32API(Win64API?)を利用して開発していきたいと思う。
 

ここまで書いてみて、目標を達成することは
茨の道
であろうと思う。いや間違いなく。
ここまで書いただけで嫌になりそうだ。

まぁ頑張ってみよう。所詮は自己満足なのだから。