コマンドライン引数の謎。引数に、スペース(空白)や、引用符を含める方法。

本文

環境はWinXP。情報元などありません。実験に基づいた記事です。
以下、test.exeは、コマンドラインの第一引数をそのまま表示して終了するプログラムだとします。

int main(int, char *argv[])
{
	puts(argv[1]);
}
実行例1
>test.exe "あ い う え お"
あ い う え お

このように、「"」引用符(クォーテーションマーク)で囲んだ引数は、ひとまとめとして扱われます。
しかもクォーテーションマークは引数に含まれません。

実行例2

コマンドライン引数に「"」引用符(ダブルクォーテーションマーク/ダブルクォート)を含めるには、以下のように。

test.exe "\""
"

つまりおなじみ、「\"」の出番です。

実行例3-1

逆スラッシュ(円マーク/円記号)を含めるには、以下のように

test.exe "\\"
\
実行例3-2

しかし、「\\」を「"」引用符(クォーテーションマーク)で囲まない場合、

test.exe \\
\\

まとめ

「"」(引用符/クォーテーションマーク)で囲った引数は、囲まれた部分全体で一つの引数になる。
なので引数に空白を含みたい場合は、「"」で囲まないといけない。
「"」で囲まれた中では、「"」は「\"」、「\」は「\\」と表現しなければいけない。(でも\tや\nは使えませんでした。)

ファイルなのか、ディレクトリ(フォルダ)なのかの判別

IsFile/IsDirectoryっていうのを作ってみました。動作確認はXPのみ。

インクルードするやつ

まずこんな感じのをコピってください。

#include <windows.h>
#include <tchar.h>

// PathIsDirectory()
#include <shlwapi.h>
#pragma comment(lib, "shlwapi.lib")

IsFile関数

// ファイルかどうかを識別する。
// falseが返された場合は、フォルダかもしれないし、他のエラーかもしれない。
BOOL IsFile( LPCTSTR _name)
{
	DWORD attributes = GetFileAttributes( _name);
	if(attributes == INVALID_FILE_ATTRIBUTES)
		return false;
	if(attributes & FILE_ATTRIBUTE_NORMAL)
		return false;

	// not dir --> file
	return true;
}

将来、「フォルダじゃない→ファイルだ」なんて二元的な関係はなくなるかもしれないので注意。
その点、CreateFile関数のほうが安全か?

追記10/03/17

上のバージョンは、c:\pagefile.sysなど、ロックされているファイルを調べようとすると、失敗するので、FindFirstFileを使うことにした。

BOOL IsFile( LPCTSTR _name)
{
	WIN32_FIND_DATA FindData;

	HANDLE hFind = FindFirstFile( _name, &FindData);
	if(hFind == INVALID_HANDLE_VALUE)
		return false;
	FindClose(hFind);
	if(!(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
		return true;
	return false;
}

IsDirectory関数

// フォルダかどうかを確かめる
// trueが返されたらフォルダ。
// falseが返された場合は、ファイルかもしれないし、
// 何も存在しないかもしれないし、他のエラーかもしれない
BOOL IsDirectory( LPCTSTR _name)
{
	return PathIsDirectory( _name);
}

ファイル/フォルダどっちでもいいから、存在するかどうかだけ知りたいとき

FindFirstFile関数でもいけると思います。
きっと上の2つで代用できるので、書きませんが。

パスセパレータ(\ ←この記号)が重複してても、内部で消してくれるかもしれない

ちょっと気づいたことがあったので書いておきます。
たとえば、以下のようにメチャクチャなことをやっても、成功するんです。

if(PathIsDirectory( "C:\\\\\\\\\\\\\\\\windows")) {
// 中略
}

strcatとかでごちゃごちゃやって、パスセパレータが連続してしまっても、ちゃんと消してくれるってわけですね。
将来的にも保障されるかどうかはわかりませんけど。そもそも、探したけれど情報が見つけられませんでした。

Unicodeでprintf

前置き

printfじゃなくて、wprintfを使うらしいです。
char なら printf。w_char なら wprintf。そして、TCHAR なら _tprintf

_tprintfを使う

前処理が必要みたいです。

#include <locale.h>
_tsetlocale( LC_ALL, _T("Japanese")); // これが前処理
//
// ・・・
// ・・・
// ・・・
//
_tprintf(_T("前処理をしないと、この日本語もうまく表示できない。\n"));

とにかく、これをやらないと、_tprintfはUnicodeの日本語が表示できないみたいです。
ローカル・・・じゃなくって、ロケールって何だろう・・・?
なんとなくわかりますけど、適当なことは書きません。とにかく、ロケールの設定をしましょう。

参考

参考
MSDN
MSDNの質問サイト
先達に感謝ですね。なんだか、質問サイトの投稿内容のまとめみたいな記事になってしまいました。

WinAPIでディスプレイの解像度を取得する(まとめ)

WindowsAPIで画面のサイズを得る方法は、調べてみたらいくつかあるようです。
中には、タスクバーの領域を除いたサイズを返す関数もあるようです。

GetSystemMetrics式

これはフツーのやり方。

int dispx = GetSystemMetrics(SM_CXSCREEN);
int dispy = GetSystemMetrics(SM_CYSCREEN);

参考 http://sho1blog.exblog.jp/7992890/

GetDeviceCaps式

これもまあフツー?

HWND hWnd = GetDesktopWindow();
HDC hdc = GetDC( hWnd);
int dispx = GetDeviceCaps( hdc, HORZRES);
int dispy = GetDeviceCaps( hdc, VERTRES);
int res = ReleaseDC( hWnd, hdc);

参考 http://homepage1.nifty.com/MADIA/delphi/Win32API/kaizoudo.htm
VBは読めないので、関数名だけ斜め読みしました。)

以下、変なやつ

マルチディスプレイの時は、各ディスプレイで、解像度が違うこともあります。
(普通、全部同じ解像度に統一する気もしますけど。)
そういう時のヒントになればさいわいです。

デュアルディスプレイ、マルチディスプレイのとき、全部まとめたサイズを取得する

デュアルディスプレイとかじゃない場合、上記のフツーのやり方と同じ結果になるはず。)

int dispx = GetSystemMetrics( SM_CXVIRTUALSCREEN);
int dispy = GetSystemMetrics( SM_CYVIRTUALSCREEN);

ただ、複数のディスプレイを繋げた時に全体の形がデコボコだった場合、どんな値が返されるのか・・・。

デュアルディスプレイ、マルチディスプレイのとき、個々のディスプレイのサイズを調べる

ごめんなさい、面倒なのでヒントっぽいのだけ。
EnumDisplayDevices()を使えば、各ディスプレイごとのサイズがわかるらしいです。
参考 http://www.winapi-database.com/System/SystemSet/EnumDisplayDevices.html

タスクバーを除いた領域のサイズ(要検証)

RECT rcDisp, rcWnd;
SystemParametersInfo( SPI_GETWORKAREA, NULL, &rcDisp, NULL);

でも、タスクバーを左端タテ向きに移動すると、変な値になった。

ミスのメモ

検索で飛んで来たあなたのために書いてみました。お役に立てれば幸いです。

std::tolower、ないですよ、どこなんですか。

#include としましょう。

エラー 11 error C2039: 'tolower' : 'std' のメンバではありません。

ですって。(VC++2008EEにて)
そういえば、Cでもctype.hというのがあって、文字の判別や変換ができるらしい。
string.hにまとめてくれればいいのにと思った記憶があります。
(けど、string.hは文字操作関数、ctype.hは文字専門。よって、string.hはお門違いです。)
C++でもではなくというところにまとめられています。
実際にやってる事といえば、#include して、stdの名前空間に宣言しなおしてるだけなんですけどねー。
参考リンク

代入してどーすんのー!

assert(i = num);

代入文を評価すると、代入した値になります。つまりnumの値と同じになります。
しかも、Release版では、これはなくなります。デバッグ版限定のバグですね。

Failed to save the updated manifest to the file

訳:失敗した。保存すること。更新されたマニフェストをザ・ファイルへ。
VC++2008EEにて。(マニフェストってなんなんですかね。よくわかりません。)
とにかく、このようなエラーが出て困っていて、検索してみたら、こちらに漂着。
http://www.river.sannet.ne.jp/yuui/kowaza.html
こういうサイト、大好きです。

ビルドしたらFailed to save the updated manifest to the fileと表示された → リビルドする

・・・・。ありがとうございました・・・。

unsigned __int64から、上位DWORD、下位DWORDを取り出すマクロ

注意

コード中にも書きましたが、符号なし__int64に対して使うと、値が負のときは、
バグの原因になるかもしれません。

コード

/* QWORDな値から、上位/下位DWORDを取り出す。
 * 符号なしの__int64に対して使うときは、おかしなことになるかもしれない。
 * (一旦、-1をかけて正の数にしてからのほうがいいかも。)
 */
#define HIDWORD(x)	(((x)>>32) & 0xffffffff)
#define LODWORD(x)	((x) & 0xffffffff)

ひとこと

HIDWORDの方、& 0xffffffff って必要なのかな・・・。
とりあえず、下記のサイトに載っていたまま、残しておきました。

参考URL

ほぼパクりました。(一応、xって所を(x)に書き直しただけ)
http://www.experts-exchange.com/Programming/Languages/CPP/Q_20534471.html

DWORD値2つから、QWORDを作る

DWORDは32Bits、QWORDは64Bitsってことで、ここはひとつよろしくお願いします。

typedef unsigned __int64 __uint64;	// QWORDと同じってことで。

__uint64 MakeQWord( DWORD hi, DWORD low)
{
	return ((__uint64)hi << 32) | low;
}

HBITMAPからBITMAP構造体を得る

やり方

まさに一目瞭然ですので以下のコードをご覧ください。

// hBmp という HBITMAP型の変数があるとします

BITMAP bmp;
if(!GetObject( hBmp, sizeof(BITMAP), &bmp)) {
	// 失敗
	return 0;
}
// 成功

その先

参考にしたこちらの質問サイトのコードは、こうして得たBITMAPから色々な情報を取り出しています。
さらにはBITMAPからBITMAPINFOまで作ってるようです。
ありがとうございます。