Posts Tagged ‘Windows SDK’

msi

Vista 状態の今はとりあえず minipoli を msi インストーラ化しようと考えた。
作るのは SeeMe で一度作ったので簡単だったけど「送る」がまったく反応しない…
Palepoli でリンク先を調べるとなんだこりゃ?

pale

「リンク先」がグレーアウトしているのはそういうことか。
そりゃ実体へのリンクじゃないならコマンドライン引数なんか無意味だわ。
なのにプロパティには引数の指定項目が…この msi を作った開発者ってバカなの?
検索すると、あぁ皆さんご苦労様。

アドバタイズショートカットではなく、普通のショートカットを作成する: .NET Tips: C#, VB.NET, Visual Studio

どっちをやっても私の環境では下記エラーダイアログが出るだけなんですけど…
と思ったけど Orca で開いていたのを閉じるだけだった、皆さん気をつけて。

err

どっちにしろメンドイ。
Visual Studio のプロパティだけでなんとかできないか模索しているが駄目っぽい。
Windows での開発ってマジでもう嫌!Linux ならシェルスクリプトだけでなんとかなるのに。

てか、コレをどうにかするより別のインストーラを探したほうがよさそうな雰囲気。
SeeMe は引数やドラッグ&ドロップが関係無いから別にイイと思うけど変更したいな。

OPENFILENAME は古い 2

SHCreateItemFromParsingName についてだが3番目の引数に

IShellItem *psi = NULL;
SHCreateItemFromParsingName(szDoc, NULL, IID_IShellItem, (LPVOID *)&psi);

なんてありがちな IID を付けたらすんなり通ってしまった。
しかしどこを探しても引数が3つなのは何故?
まあこれで IFileDialog 関連はなんとかなりそうだ。

自前関数とかそのままだけーがこんな感じで。

/*
 * (*.mpg|*.mpeg) を (*.mpg;*.mpeg) に変換
 * セミコロンって INI の仕様ではコメントなのよね
 */
BOOL SemicolonReplace(LPWSTR _Dst, LPWSTR _Src)
{
	for (int i=0; i<256; i++)
	{
		if (_Src[i] == '\0') {
			_Dst[i] = '\0';
			return TRUE;
		} else if (_Src[i] == '|') {
			_Dst[i] = ';';
		} else {
			_Dst[i] = _Src[i];
		}
	}
	return FALSE;
}

void CCinemaWindow::DoOpenDlg()
{
	IFileDialog *pDlg = NULL;
	IShellItem *psi = NULL;
	HRESULT hr;

	hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_IFileDialog, (LPVOID *)&pDlg);
	if (FAILED(hr)) {
		DoMessage(hWnd, L"Errer IFileDialog Create");
		pDlg->Release();
		return;
	}
	//拡張子フィルタの登録
	wchar_t filter[3][256];
	SemicolonReplace(filter[0], IniSetting.szExt01);
	SemicolonReplace(filter[1], IniSetting.szExt02);
	SemicolonReplace(filter[2], IniSetting.szExt03);
	COMDLG_FILTERSPEC filterspec[] =
	{
		{IniSetting.szExtA, filter[0]},
		{IniSetting.szExtB, filter[1]},
		{IniSetting.szExtC, filter[2]}
	};
	hr = pDlg->SetFileTypes(3, filterspec);
	if (FAILED(hr)) {
		DoMessage(hWnd, L"Errer SetFileTypes1");
		pDlg->Release();
		return;
	}
	//フィルタの選択インデックス変更(先頭は 1 である)
	hr = pDlg->SetFileTypeIndex((UINT)IniSetting.nExtNo + 1);
	if (FAILED(hr)) {
		DoMessage(hWnd, L"Errer SetFileTypeIndex");
		pDlg->Release();
		return;
	}
	//初期選択フォルダ
	if (fname::FileExists(PlayFileInfo.FullPath))
	{
		hr = SHCreateItemFromParsingName(PlayFileInfo.FilePath, NULL, IID_IShellItem, (LPVOID *)&psi); //IID_PPV_ARGS(&si)
	} else if (fname::DirectryExists(IniSetting.szSFolder)) {
		hr = SHCreateItemFromParsingName(IniSetting.szSFolder, NULL, IID_IShellItem, (LPVOID *)&psi);
	} else {
		wchar_t szDoc[256];
		SysUtils::get_MyDocumentString(szDoc);
		hr = SHCreateItemFromParsingName(szDoc, NULL, IID_IShellItem, (LPVOID *)&psi);
	}
	if (FAILED(hr)) {
		DoMessage(hWnd, L"Errer CreateItemFromParsingName");
		psi->Release();
		pDlg->Release();
		return;
	}
	hr = pDlg->SetFolder(psi);
	if (FAILED(hr)) {
		DoMessage(hWnd, L"Errer SetFolder");
		psi->Release();
		pDlg->Release();
		return;
	}
	psi->Release();
	psi = NULL;
	//ダイアログの表示
	hr = pDlg->Show(hWnd);
	if (SUCCEEDED(hr))	// FAILED ではキャンセルを拾ってしまう
	{
		wchar_t *pFileName = NULL;
		hr = pDlg->GetResult(&psi);
		if (FAILED(hr)) {
			DoMessage(hWnd, L"Errer GetResult");
			psi->Release();
			pDlg->Release();
			return;
		}
		hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &pFileName);
		if (FAILED(hr)) {
			DoMessage(hWnd, L"Errer GetFileName");
			psi->Release();
			pDlg->Release();
			CoTaskMemFree(pFileName);
			return;
		}
		UINT nIndex;
		hr = pDlg->GetFileTypeIndex(&nIndex);
		if (FAILED(hr)) {
			DoMessage(hWnd, L"Errer GetFileTypeIndex");
			psi->Release();
			pDlg->Release();
			CoTaskMemFree(pFileName);
			return;
		}
		hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &pFileName);
		if (FAILED(hr)) {
			DoMessage(hWnd, L"Errer GetDisplayName");
			psi->Release();
			pDlg->Release();
			CoTaskMemFree(pFileName);
			return;
		}
		//完走したので処理
		int nExtNo = (int)nIndex - 1;
		if (IniSetting.nExtNo != nExtNo)
		{
			SetPlayFileInfo(L"c:\\a\\a"); //拡張子が無いのでクリアになる
			SetListupMenu(nExtNo, TRUE);  //本体のセレクトを変更
		}
		DirectA->SetURL(hWnd, pFileName);
		//end
		CoTaskMemFree(pFileName);
		psi->Release();
	}
	pDlg->Release();
}

長いよぉ!だから COM は…

を選択したら本体のリストアップ選択も変更したかっただけなのに。

さて、問題は XP 版をどうするかだ…又 #ifdef で分けるしかないか。
こっちに都合がイイように仕様変更しまくったのだどうしよう…

OPENFILENAME は古い

C# ばかりやっていたら頭が腐りそうなので今日は慣れた C++ を。

今回は Cinema にリストアップ拡張子選択機能を付けて更新しようと考えた。
ついでに開くダイアログを改造していたのであるが…

OPENFILENAME 構造体に lpfnHook を指定したら古いダイアログになっちまった。
なんでじゃい!

CFileDialog::m_ofn

なんてこった、GetOpenFileName 関数はこんなに変わっていたのか。
このサポートされなくなったメンバを使わなければコンパイル時に新しいのに置き換えられる。
ということみたい。

ExpLZH の保存ダイアログが古いのとかが気になっていたのだがそういうことだったか。
でも秀丸とかはカスタマイズしているのに Vista スタイルになっているよな?
何か方法があるのだろう、調べてみよう。

で。

どうやら Vista 型式のダイアログは COM の IFileDialog を使うようである。
何故 COM なんだ?と文句を書いてもしゃーないので作るしかない。

MSDN じゃ全然解らない!サンプルにも見あたらない!
日本語で探しても解りにくいので「ウエブ全体」でググる。

CodeProject: Vista Goodies in C++: Using the New Vista File Dialogs. Free source code and programming help

流石に老舗のココは解りやすい。
CComPtr なので ATL での解説だけどなんとかなるだろうと書いてみる。

何故だろう?
SHCreateItemFromParsingName の引数がどこを探しても3つなんですけど…
私の Visual Studio では4つあるんですけど、デフォルト引数でもないし…

あぁ更に解らない!ということで更新は又今度。

ウインド表示直後に処理

久々に SDK チップスネタでも書こう。

WM_SHOW を捕まえて処理するとウインド表示に時間が掛かる場合がある。
このイベント処理が終わった後でないと実際の描写が行われないからだ。

だから表示された直後に作成や描写を行えば見た目の起動速度が向上する。
しかしそんな都合のよいメッセージは飛んでこない。

が、実はデルヒャァにはある。

procedure CMShowingChanged(var Message:TMessage);message CM_SHOWINGCHANGED;

をフォームの private に定義してハンドラを書くだけ…
但し表示状態が変わる毎に飛んでくるので一番最初に捕まえた時以外は弾くこと。
Y901 はそのツマラン方法で見た目の起動時間を短縮するセコイことをやっていた。

はて、CM_SHOWINGCHANGED なんて無い VC++ ではどうすんだ?
で考えた、PostMessage を使ってまえ!

SendMessage は処理が終わるまで制御を戻してくれない。
PostMessage はキューにメッセージを放り込んで即制御を戻す。
だから WM_SHOW 処理の一番最後で適当なメッセージを投げればよい。

#define WM_SHOWEND (WM_APP + 3)

とか定義しておいて WM_SHOW 処理の一番最後に

PostMessage(hWnd, WM_SHOWEND, 0L, 0L);

とすればキューに自分宛の WM_SHOWEND がセットされる。
キューって何?な人は Windows をもっと勉強してください。
後は WndProc で普通に

case WM_SHOWEND:

を処理、これで見た目の起動時間が早いアプリのできあがり!
詳しくは Cinema のソースコードで、オープンソースは楽だ。

フォーム表示直後に実行されるメソッド OnShowed を作る – Sakura scope

他にも同じコトを考える人がいるのね。
ビルダァ(名古屋弁化できん…)には CM_SHOWINGCHANGED は無いのかな?
でも WM_USER を使うのは止めておいたほうがいいみたいよ

WM_APPの薦め。

それより Windows SuperFetch がある Vista ではあまり意味が無い…

Aero の TextOut

唐突に気がついたのだが…
以前 WPF の描写について

※ボタンを押して文字を描写した
※アプリの上に他のウインドを被せた
※そのウインドをどかしたら文字が消えていた

なんて初心者が必ず迷う事柄はもう二度と起こらないんだし。

と書いてしまったが、よく考えたら Aero 自体も DirectX 描写だ。
もしかして?と思って実験。

20080309.JPG

を Aero で動かして左クリックで文字を描写して上にウインドを被せる。
どかしたら…やっぱりコレでは描写が消えなくなっていたのね。

ウインドをリサイズすると当然のように消えるのは変わっていない。
正確に書くとリサイズでは WM_PAINT が飛んでくる。

WPF は何をしようが消えない、うーややこしいぞ。
つーか WPF では Paint イベントなんて定義が無いので消えたら困る。

文字を表示する
かの赤坂氏の解説も今は通じなくなってしまっているわな。
なんか何を今更という感じですが Vista って本当に困った OS です。