C/C++」タグアーカイブ

Visual Studio x64 build test

時間が掛かりすぎるので休日にしかできない仮想 Vista 構築の続き。

前回はただ OS のインストールだけで終わったので Vista に SP を当てないと。
Windows Update では自動で当ててくれないのが忌々しい。

sp1 を当てないと sp2 が当てられないのね、面倒すぎ。
4 時間使ってやっと両方が終わったところで IE8 への自動更新が出る。
一度にやってくれよ、何回再起動させればいいのやら…

やっと Visual Studio をインストールする環境が揃う。
インストール DVD を立ち上げ今回は忘れずに「すべて」を選択。

vs_all

やっぱり一時間半掛かって、んで一時間使って MSDN ヘルプを入れて…
そして sp1 にするのにまた一時間半と、更に Update が掛かって…
そして今回も丸々一日使うはめになったとさ。

あーもうなるべくコイツは使いたく無い、Visual Studio 専用 OS にしよう。
FTP ができないと困るがこれでやればイイや。

[IE]Internet Explorer で FTP サイトのパスワードを入力する方法

Explorer のエディット部にコレやればとりあえずファイル転送はできるのよね。
パーミッション変更とかはできるはずがない、それらはホストの Mandriva からやる。
パスワードに記号とか入れている人は URI 変換をお忘れなく。
でも何故か Windows 7 ミニノートからではできない…

とにかく minipoli のソースを落として実験だ。
Visual Studio 起動、初回は遅いけど二回目以降は起動が早いというより一瞬。
仮想 OS になっても Vista の SuperFetch は完璧である。
でなきゃ困る、だから XP も 7 も持っているのに Vista を使うんだから。
7 の SuperFetch は効きがイマイチなんだよなぁ…

select_x64

「すべて」を選択したので今回はしっかり x64 の選択肢があった。
ソースコードはまったく弄くらずに minipoli をビルド、何事もなくビルド完了。
ちょっと拍子抜け、本当に 64bit 用にビルドされたのかな?
実験で 32bit であるこの Vista で使ってみる。

minipoli64.zip

32bit_test

わーい 64bit ですってエラーになった!
次に x64 Windows 7 であるミニノートに持っていき試す。

64bit_test

あたりまえのように動く、マジでコードは一行も変更しないで済みそうだ。
後は 64bit 用インストーラを作成すれば minipoli の x64 化は完了。
それがやりたいだけの為に二回も休日を全部使ってしまった…
好きでやっているのだから別にイイのだが。

OSASK 公開停止か? – スラッシュドット・ジャパン

いやいや、皆が何を言いたいかよく解るなぁ。
開発者が望んでいるようなユーザーが一人でもいるなんて奇跡に等しい世界ですから。
情報公開もオープンソースも自己満足、それでいいじゃない。

Windows でもゴミ箱

Linux ばかりに触っていたらマニアックになるので Windows を久々に。

せっかくゴミ箱について興味をもったので Windows でも色々調べてみる。
OS の仕様としてゴミ箱を持つ Windows ではコマンドとかはどうなっているのかな?

コマンドプロンプトでごみ箱へファイルを移動させるにはどうすればよいのでしょうか? -OKWave

XP では c:\recycler 以下のはずだけど…てかドライブ毎ユーザー毎に存在するんだが何時の話?
試しにやってみた、ごみ箱に残らないとか書いているけどつまりこうなっているだけだと思う。

cmd_move

アプリを紹介しているけど VC++ を持っているならの SHFileOperation を使って簡単に作(略
なんにせよ Windows でも Shell API からしかアクセスできないんだ、ふむふむ。

OS 非依存の仮想マシンであるはずの .NET Framework はどうなのかな?

ファイルをゴミ箱へ削除(C#)について – Insider.NET

やはり P/Invoke でアクセスしなさい!にしているようで。
そんな糞面倒なことをするより VC++ でラッピングした dll を作って(略
それにしても「がっかり」って人… .NET Framework が何なのか解っているのかな?

Python は…当然 gio モジュールなんか使えるはずもなく。
これも VC++ でラッピングした dll を作って(もういいよ

Windows Power Shell なら結構簡単に

Windows Script Programming: PowerShellでファイルやフォルダをごみ箱に捨てる。

全然簡単じゃネェ!デフォルトで手段を用意してくれている分マシなだけだ。

うわぁ…つまりシェルてかこの手のことをやろうとすると VC++ が必要になるわ。
ま、こんなことを書いたしせっかくなのでゴミ箱へ送る DLL の作り方を書いておこう。
Visual Studio の入っている Vista の HDD に繋ぎ替えて…メンドクサ。

VisualStudio を起動する、VC++ Exp でも同じはず。
trash という名前の新規 Win32 コンソールプロジェクトを作る。
ウイザードを進めてアプリケーションの種類を「DLL」にして完了。
そして Python から使う場合にはまずやらなきゃいけないこと。

stdcall

と呼び出し規約を __stdcall にする、意味は勝手に調べてね。
達人なら違うと言うだろうけど普通の人ならそれ以外はデフォルトのままでいい。
つまりデフォルトの UNICODE ビルドだが今はそのほうが自然だろう。

追記
忘れていた!Releace 版だけでいいんだが
コード生成のランタイムライブラリを「マルチスレッド」にして。

multi

「マルチスレッド DLL」のままだと VC9 ランタイムも配らなきゃいけなくなる。
7kb が 41kb に増えるけどこれで DLL 単体で配布できるようになる
VC++ が入っている環境だと普通に動くので忘れがちなんですよねココ。
追記おわり

stdafx.h の最後の行に下記を追記

#include <shellapi.h>

コード

#include "stdafx.h"

extern "C" __declspec(dllexport)
BOOL trash(LPCWSTR szFileName)
{
	SHFILEOPSTRUCT sfos;
	ZeroMemory(&sfos, sizeof(SHFILEOPSTRUCT));
	wchar_t szOpFile[1024];
	wcscpy_s(szOpFile, 1024, szFileName);
	szOpFile[wcslen(szOpFile) + 1] = L'?0';
	sfos.hwnd = NULL;
	sfos.wFunc = FO_DELETE;
	sfos.pFrom = szOpFile;
	sfos.fFlags = FOF_SILENT | FOF_ALLOWUNDO | FOF_NOCONFIRMATION;
	if (!SHFileOperation(&sfos))
	{
		return TRUE;
	}
	return FALSE;
}

trash.zip

DllMain を書いて Visual Studio 2008 でビルドしたら警告になった。
分離されているのか、targetver.h といい親切なのか余計なお世話なのか。

細かいことは→の「APIで学ぶWindows徹底理解」に書いています。
ちなみに私が買ったこの本はもう読み直ししすぎてボロボロです。

後はそのままビルドで DLL の完成。
Python.exe があるディレクトリに trash.dll をコピーします。

exp

ここまでくれば python からは毎度のように ctypes を利用して

import ctypes

dll = ctypes.windll.trash
if dll.trash("C:\\Python30\\gomi.txt"):
    print("ok")
else:
    print("miss")

こんな感じであっさりゴミ箱へ捨てられます。
2.* ではファイル名を UNICODE にするのをお忘れなく。
どうしても Python でやらなきゃいけない場合以外は VC++ で作ったほうが(略

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つあるんですけど、デフォルト引数でもないし…

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

Ubuntu で C# と C++

まてよ、mono の実行エンジンはインストールされているのかな?
とりあえず Vista でコンソールアプリを作り Ubuntu に持って行って実行してみる。
java じゃないんだからコンソールでないと動くはずがない。

まあ結果は動く、軽く調べるとどうやら実行エンジンは標準搭載らしい。
標準状態では C 言語さえコンパイルできないんだから C# は当然ムリか。

Mono 1.9.1のインストール – Programming/Mono – 総武ソフトウェア推進所

なんかイッパイ入れなきゃいけないみたいですけど…
そういえば Visual Studio 2008 のインストールは二時間掛かったっけか。
たった二分でインストールできた mono Develop で同等なわけがない。

特に Linux の場合 GUI アプリは gtk+ か Qt とか様々なわけで。
Windows 版のようにまとめて一気にインストールはそりゃ無謀かと納得。

2008-02-03 – ままならない日記

とりあえず mono-gmcs だけをインストール。
結果はコンパイルできた、よしよし、後は気が向いたら(ぉい!)

ちなみに、コード補完は C# でしかやってくれない。
思わず Ctrl+Space を押して SCIM を…略。

それより知らなかったのだがソースコードは UTF-8 で保存されるんだね。
ローケルのとうりになるのか、こりゃ日本語の扱いが更に面倒そう。
だけどコードページ 932 (つまり Shift-JIS)の呪縛が無いのは嬉しいね。

ということは…

やはり search.ini なんかも普通に char 配列で読み書きできるわな。
Firefox も Opera も設定が全部 UTF-8 なわけだよ、よく解った。
Windows も…バイナリ配布が普通の Windows では無理だと解っているけど。

C# テストが目的だったけど C++ コンパイラとして使うのも悪くないなコレ。
続く…かもしれない。