« 2006年11月 | メイン | 2007年01月 »

1  2  3  4  5  6  7  8  9  10

2006年12月 記事一覧

2006年12月01日

ファイルをゴミ箱に移動する

ファイルをゴミ箱に移動したいときはSHFileOperationを利用する。この関数は複数のファイルのコピーをコピー、移動、名前変更、削除できるように設計されている。ここではSHFileOperationの機能を一部だけ利用して、1ファイルの削除を行う処理を実装した。

注意しなければならないことは、SHFileOperationは処理するファイルを複数指定できるように設計されている。そのためファイルパスをNULL区切りで渡し、最後のファイルパス後にNULL文字を2つ付加しなければならない。このとき非ユニコードビルドのときはNULLを1バイト付加して合計2バイトのNULL文字が並ぶようにする。ユニコードビルド時は合計4バイトのNULLが並ぶようにする。

今回は1つのファイルを処理するため、動的に確保したメモリにファイルパスをコピーし、NULL文字を追加している。そのため作成したDeleteFileToRecycleBin関数にファイル名を指定するときは従来どおりのファイル名を渡せばいい。

#include "shellapi.h"

//
//	ファイルをゴミ箱へ削除
//
//SHFileOperationは複数ファイルを一括して処理できるが、ここでは1ファイルのみ削除できるようにした
//pszFileのファイル名部分にワイルドカード「*」や「?」を使うこともできる
//削除処理中の進行状況表示画面などは表示しない
//
bool	DeleteFileToRecycleBin(LPCTSTR pszFile)
{
	int		ret;
	size_t	nLen;
	TCHAR*	pszFrom;
	SHFILEOPSTRUCT	sShFileOp;

	if(pszFile == NULL)
		return	false;

	//ファイルパスの文字数取得
	nLen = _tcslen(pszFile);
	if(nLen == 0)
		return	false;

	//メモリ確保とファイルパスコピー
	pszFrom = new TCHAR[nLen + 10];
	if(pszFrom == NULL)
		return	false;
	_tcscpy_s(pszFrom,(nLen + 10) * sizeof(TCHAR),pszFile);

	//ファイルパスの後ろにNULL文字を付加(Unicodeビルド時は2つのNULLバイトが付加される)
	pszFrom[nLen + 1] = NULL;

	//ファイル削除
	::ZeroMemory(&sShFileOp,sizeof(SHFILEOPSTRUCT));
	sShFileOp.wFunc		= FO_DELETE;
	sShFileOp.pFrom		= pszFrom;
	sShFileOp.fFlags	= FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT;
	ret = ::SHFileOperation(&sShFileOp);

	//メモリ開放
	delete	pszFrom;

	return	(ret == 0) ? true : false;
}

void	Test(void)
{
	bool	ret;

	ret = DeleteFileToRecycleBin(_T("c:\\test.txt"));

	if(ret)
		::MessageBox(NULL,_T("削除しました"),_T(""),MB_OK);
	else
		::MessageBox(NULL,_T("削除に失敗しました"),_T(""),MB_OK);
}

プロジェクトファイルをダウンロード

ゴミ箱を空にする

ファイルなどをゴミ箱に削除するのはSHFileOperationを、ゴミ箱を空にするにはSHEmptyRecycleBinを利用する。
SHEmptyRecycleBinは各ドライブごとに存在するゴミ箱を個別に削除できるが、ここでは一括前ドライブのゴミ箱を空にしている。

#include "shellapi.h"

//
//	ゴミ箱を空にする
//
//ゴミ箱が既に空でもtrueが返る
//
bool	EmptyRecycleBin(void)
{
	HRESULT	hr;

	hr = ::SHEmptyRecycleBin(NULL,NULL,SHERB_NOCONFIRMATION | SHERB_NOPROGRESSUI | SHERB_NOSOUND);

	return	SUCCEEDED(hr) ? true : false;
}



void	Test(void)
{
	bool	ret;

	ret = EmptyRecycleBin();

	if(ret)
		::MessageBox(NULL,_T("ゴミ箱を空にしました"),_T(""),MB_OK);
	else
		::MessageBox(NULL,_T("ゴミ箱を空にできませんでした"),_T(""),MB_OK);
}

プロジェクトファイルをダウンロード

2006年12月02日

Internet Explorerの履歴をクリアする

IEの履歴を削除するにはIUrlHistoryStg2インターフェースを利用する。このCOMは実装されたのが比較的最近のためInternet Explorer 5.5以降、かつ、Windows Me、Windows 2000以降で利用できる。Windows 95/98/NT 4.0では利用できないので注意。

また、バグによりInternet Explorer 6 SP1でWindows Updateをしていない場合は実行した日の履歴が削除されないことがあるらしい。

#include "mshtml.h"
#include "shlguid.h"
#include "urlhist.h"


//
//	Internet Exploreの履歴を削除する
//
// IE5.5以降対応
// Windows Me/2000以降対応
//
bool	ClearInternetExplorerHistry(void)
{
	HRESULT		hr;
	IUrlHistoryStg2*	pIUrlHistoryStg2; 

	hr = ::CoCreateInstance(CLSID_CUrlHistory,NULL,CLSCTX_INPROC_SERVER,IID_IUrlHistoryStg2,reinterpret_cast<void**>(&pIUrlHistoryStg2));
	if(FAILED(hr) || pIUrlHistoryStg2 == NULL)
		return	false;

	hr = pIUrlHistoryStg2->ClearHistory();

	pIUrlHistoryStg2->Release();

	return	SUCCEEDED(hr) ? true : false;
}


void	Test(void)
{
	bool	ret;

	//COM初期化
	::CoInitialize(NULL); 

	ret = ClearInternetExplorerHistry();

	if(ret)
		::MessageBox(NULL,_T("IEの履歴を空にしました"),_T(""),MB_OK);
	else
		::MessageBox(NULL,_T("IEの履歴を空にできませんでした"),_T(""),MB_OK);

	//COM開放
	::CoUninitialize(); 
}

プロジェクトファイルをダウンロード

Visual Studio 2005ではWindows 95用アプリを作れない?!

MSDNライブラリを見ていてふと目に留まった項目があった。

test30_00.gif
サポートされるプラットフォームの中にWindows 95がない!ということだ。Windows NT 4.0も消えている。あるのはWindows 98以降とWindows 2000以降のみ。ちょっとこれにはビックリ。

test30_01.gif
本当にWindows 95をサポートしていないのかな?と思い簡単に確かめることにしてみた。
Visual Studio 2005を起動して「ファイル」メニューの「新規作成」から「プロジェクト」を選択する。そして「MFCアプリケーション」のプロジェクトを作成する。

test30_02.gif
MFCアプリケーションウィザードが開いたらすぐに「完了」ボタンを押さずに次へ進む。

test30_03.gif
デフォルトでは「ユニコードライブラリを使用する」にチェックが入っている。このチェックを外して「完了」ボタンを押す。Windows 9x系では基本的にユニコードは使えないために外している。


test30_04.gif
プロジェクトが作成できたら、左側の「ソリューションエクスプローラ」にある「stdafx.h」をダブルクリックして開く。そしてプラットフォーム用の定義を全て一番最低ラインの「0x0400」に変更する。


test30_05.gif
VC++で作成したEXEファイルは実行にいくつかのDLLファイルが必要なことが多い。依存環境を調べてDLLをコピーしてもいいが、手軽に実行用の環境を作るためにインストーラーを作る。
「ファイル」メニューにある「追加」から「新しいプロジェクト」を選択する。


test30_06.gif
プロジェクトの種類として「セットアップと配置」を選び、テンプレートは「セットアップウィザード」を指定して「OK」ボタンを押す。


test30_07.gif
これでインストーラーを作るためのセットアップウィザードが開いた。


test30_08.gif
プロジェクトの種類はデフォルトの「Windowsアプリケーションのセットアップを作成する」を利用する。


test30_09.gif
ここで「○○のプライマリ出力」にチェックを入れる。これで先ほど作成したMFCアプリケーションのEXEファイルがインストールされる。


test30_10.gif
必要な設定は済んだので「完了」ボタンを押してもいいが、一応内容を見るために順次「次へ」ボタンを押す。


test30_11.gif
これで「完了」ボタンを押してセットアッププロジェクトを作成する。


test30_12.gif
作成できたらVisual Studio 2005の画面上部にあるビルドモードの選択欄で「Release」を選択する。


test30_13.gif
そして「ビルド」メニューにある「ソリューションのビルド」を選択してビルドする。


test30_14.gif
この状態だとまだインストーラーまでは作成されないので、画面左側の「ソリューションエクスプローラー」内のセットアッププロジェクトを右クリックして現れるメニューから「ビルド」を選択してインストーラーを作成する。

test30_15.gif
ここまでできたらテスト環境を起動する。まずはWindows 98(Second Edition)でテストすることにした。テスト用のPCを用意してもいいが、今はVirtual PCが無料化されたのでこのような仮想マシン環境を使った方が楽だ。


test30_16.gif
Windows 98を起動したらVisual Studio 2005によって作成した「Setup.exe」と「Setup.msi」をコピーして起動する。これでインストーラーが起動する。


test30_17.gif
「次へ」ボタンをどんどん押してインストールを進める。インストール先のフォルダはデフォルトのままなので「c:\Program Files\既定の会社名\Setup1\」という変な場所になっている。


test30_18.gif


test30_19.gif
これでインストールが完了した。


test30_20.gif
エクスプローラでインストール先のフォルダを開く。するとちゃんと作成したMFCアプリケーションのEXEファイルがあることが分かる。これをダブルクリックして実行する。


test30_21.gif
するとエラーも出ずにちゃんと起動した。


test30_22.gif
Windows 98ではきちんと動作したので、次に問題のWindows 95でテストすることにする。ここではWindows 95 OSR2を用意した。


test30_23.gif
Windows 98のときと同じようにインストールする。インストーラーは正常に動くようだ。


test30_24.gif
そしてインストール先のEXEをダブルクリックして実行する。


test30_25.gif
...すると「プログラム開始エラー」のダイアログと「システムに装着してあるデバイスは動作していません。」というメッセージが表示された。本当にWindows 95では動かないようだ。


Dependency Walkerで調べるといくつかのDLLが使えていないようだった。がんばればWindows 95でも動作するEXEを作ることはできるだろう。しかしVisual Studio 2005でサポート外という事実は変わらない。そのためそこまでがんばるメリットもないだろう。
ということでWindows 95やWindows NT 4.0など古いプラットフォームでも動くソフトを開発したい場合はVisual Studio 2005以外を選択するしかないようだ。

プロジェクトファイルをダウンロード

DDKの無料ダウンロードが開始されていた!

ddk01.gif
Windows用のデバイスドライバー開発キット(DDK)と言えば、昔は無料でダウンロードできたがWindows 2000辺りからだったかダウンロード提供が中止されていた。手に入れるには有料のMSDNサブスクリプションに入るか、ホームページのオーダーフォームで3000円ぐらい払って購入するしかなかった。

ddk02.gif
以前(2004年年末)、私はMicrosoftのホームページ上で注文したことがある。クレジットカードで3000円ちょっと支払い、実際に引き落としまではあったが...いつになってもDDKは届かなかったということがある。そんな苦い思い出があるためDDKとは無縁の生活を送っていたのだが...

ddk03.gif
知らないうちに無料でダウンロードが開始されていた。ダウンロードページはhttp://www.microsoft.com/japan/whdc/DevTools/ddk/default.mspxにある。ISOイメージで236MB。ダウンロードできるのはWindows XP/2000/2003Server用のDDK「Windows Server 2003 SP1 DDK」のみとなっている。ファイル名は「1830_usa_ddk.iso」。
残念ながらWindows Vista用のDDK「Windows Vista WDK」はダウンロードできないようだ。

ddk04.gif
これで何度かちょっとかじっては諦め...というのを繰り返してきたDDKに再び挑戦できる環境は整った。後はやる気と根性だけかな?

ddk05.gif
インストール画面では、デフォルトではサンプルがインストールされない。

ddk06.gif
サンプルにはかなり色々なデバイス用のソースコードが含まれているのでインストールは必須だろう。全部インストールするのに必要な容量は746MBになる。

ddk07.gif
ちなみにDDKをダウンロードではなく注文する場合も2006年12月現在、無料のようだ。

ddk08.gif
開発環境にはx64やAMD64など64ビット環境向けのものも含まれる。またインストール後のフォルダざっとを見てみたらATL2.1、ATL3.0、MFC4.2など古いライブラリコードも入っているようだった。かなり新旧織り交ぜられている印象だ。

ddk09.gif
これでインストール終了。インストールの最終画面には要した時間が表示されている。私の場合は24分57秒かかったようだ。このDDKのインストーラーは起動時にスプラッシュ画面が表示されるし、インストールにかかった時間が計測されているし...かなり開発者の"趣味"が入っているようだ。


2006年12月03日

OSに関係なく特殊フォルダのパスを取得する

デスクトップやお気に入り、マイドキュメントなどの特殊フォルダにアクセスするとき、例えば「c:\windows\」や「c:\Program Files\」のようにソースコードに書いてはいけない。必ず専用のAPIを利用してパスを取得する必要がある。取得にはSHGetFolderPath、SHGetSpecialFolderPath、SHGetFolderLocationなどを利用する。

現在のプラットフォームでは何も考えずにSHGetFolderPathを利用すればいい。しかし古いプラットフォームもサポートしたプログラムにしようと考えるとやっかいなことになる可能性がある。SHGetFolderPathをshfolder.libに実装したりshell32.dllに変えたり...と過去に何回かの変更があるからだ。
ここで紹介する関数は現在のプラットフォームではSHGetFolderPathを、古いものではSHGetSpecialFolderPathを利用して特殊フォルダのパスを取得している。

取得できるフォルダには...
CSIDL_ADMINTOOLS
CSIDL_COMMON_ADMINTOOLS
CSIDL_APPDATA
CSIDL_COMMON_APPDATA
CSIDL_COMMON_DOCUMENTS
CSIDL_COOKIES
CSIDL_HISTORY
CSIDL_INTERNET_CACHE
CSIDL_LOCAL_APPDATA
CSIDL_MYPICTURES
CSIDL_PERSONAL
CSIDL_PROGRAM_FILES
CSIDL_PROGRAM_FILES_COMMON
CSIDL_SYSTEM
CSIDL_WINDOWS
などなどがある。これらはshlobj.hに定義されているのでそちらを参考にするといいだろう。

#include "shlobj.h"


//
//	SHGetSpecialFolderPathの全プラットフォーム対応バージョン
//
BOOL	SafeSHGetSpecialFolderPath(HWND hwndOwner,LPTSTR lpszPath,int nFolder,BOOL fCreate)
{
	BOOL	(CALLBACK* g_pfnSHGetSpecialFolderPath)(HWND,LPTSTR,int,BOOL);
	HRESULT	(CALLBACK* g_pfnSHGetFolderPath)(HWND,int,HANDLE,DWORD,LPTSTR);

	int			i;
	BOOL		ret;
	HRESULT		hr;
	HMODULE		hDLL;
	TCHAR		pszDllFile[][15] = {_T("shfolder.dll"),_T("shell32.dll")};

	if(lpszPath == NULL)
		return	FALSE;
	*lpszPath = NULL;

	ret = FALSE;
	for(i = 0; i < 2; i++)
	{
		hDLL = ::LoadLibrary(pszDllFile[i]);
		if(hDLL == NULL)
			continue;

		#ifdef UNICODE
			(*(FARPROC*)&g_pfnSHGetSpecialFolderPath = ::GetProcAddress(hDLL,"SHGetSpecialFolderPathW"));
			(*(FARPROC*)&g_pfnSHGetFolderPath = ::GetProcAddress(hDLL,"SHGetFolderPathW"));
		#else
			(*(FARPROC*)&g_pfnSHGetSpecialFolderPath = ::GetProcAddress(hDLL,"SHGetSpecialFolderPathA"));
			(*(FARPROC*)&g_pfnSHGetFolderPath = ::GetProcAddress(hDLL,"SHGetFolderPathA"));
		#endif

		if(g_pfnSHGetSpecialFolderPath)
			ret = g_pfnSHGetSpecialFolderPath(hwndOwner,lpszPath,nFolder,fCreate);
		if(ret == FALSE && g_pfnSHGetFolderPath)
		{
			hr = g_pfnSHGetFolderPath(hwndOwner,nFolder | (fCreate ? CSIDL_FLAG_CREATE : 0),NULL,SHGFP_TYPE_DEFAULT,lpszPath);
			ret = (SUCCEEDED(hr)) ? TRUE : FALSE;
		}

		::FreeLibrary(hDLL);

		if(ret)
			return	TRUE;
	}

	return	FALSE;
}



void	Test(void)
{
	BOOL	ret;
	TCHAR	pszPath[MAX_PATH*2];

	ret = SafeSHGetSpecialFolderPath(NULL,pszPath,CSIDL_DESKTOPDIRECTORY,FALSE);

	if(ret)
		::MessageBox(NULL,pszPath,_T(""),MB_OK);
	else
		::MessageBox(NULL,_T("取得に失敗しました"),_T(""),MB_OK);
}

プロジェクトファイルをダウンロード

物理メモリ容量を取得する

パソコンに積まれたメモリ容量を取得します。いくつか方法があるがここではIShellDispatch2を利用した。

このCOMインターフェースを利用するとCPUクロックも取得できるはずだが、Core Duo環境では失敗したのでクロック取得には使わないほうがいいだろう。それでもクロックを取得したい場合はL"PhysicalMemoryInstalled"の部分をL"ProcessorSpeed"にすればいい。

依存環境:ATL
#include "atlstr.h"
#include "shldisp.h"


//
//	PCに載っている物理メモリ量を取得する
//
//単位はbytes
//対応はWindows Me/2000以降
//
//失敗時はゼロを返す
//
ULONGLONG	GetPhysicalMemoryInstalled(void)
{
	IShellDispatch2*	pIShellDispatch2;
    HRESULT		hr;
	VARIANT		val;
	BSTR		bstr;

	pIShellDispatch2 = NULL;
	hr = ::CoCreateInstance(CLSID_Shell,NULL,CLSCTX_INPROC_SERVER,IID_IShellDispatch2,(void**)&pIShellDispatch2);
	if(FAILED(hr) || pIShellDispatch2 == NULL)
		return	0;

	::VariantClear(&val);
	bstr = ::SysAllocString(L"PhysicalMemoryInstalled");
	hr = pIShellDispatch2->GetSystemInformation(bstr,&val);
	::SysFreeString(bstr);
	pIShellDispatch2->Release();

	if(FAILED(hr) || val.vt != VT_R8)
		return	0;

	return	V_R8(&val);
}



void	Test(void)
{
	ULONGLONG	nMemory;
	CAtlString	strMessage;

	::CoInitialize(NULL);


	nMemory = GetPhysicalMemoryInstalled();

	strMessage.Format(_T("%ld MB"),nMemory / (1024*1024));
	::MessageBox(NULL,strMessage,_T(""),MB_OK);

	::CoUninitialize();
}

プロジェクトファイルをダウンロード

CPU数などのCPU関連情報を取得する

Windows XPから使えるようになったAPIにGetNativeSystemInfoがある。この関数を利用するとCPU数、CPUアーキテクチャ種(64ビット環境か32ビットかなど)の情報を取得できる。

依存環境:ATL
#include "atlstr.h"


//
//	CPU情報の取得
//
//取得できるのはCPU数など一部の情報のみ。
//実際のCPU型番(「Core Duo T2600」など)はこの関数では取得できない。
//とは言うもののCPU型番を推測するための情報として利用できる。
//
//pwProcessorArchitectureなどの詳しい情報はMSDNのSYSTEM_INFOを参照すること
//
//対応:Windows XP以降
//
bool	GetCPUInformation(DWORD* pdwNumberOfProcessors,WORD* pwProcessorArchitecture,DWORD* pdwProcessorType,WORD* pwProcessorLevel,WORD* pwProcessorRevision)
{
	SYSTEM_INFO	sInfo;
	HMODULE		hDLL;

	void	(CALLBACK* pfnGetNativeSystemInfo)(LPSYSTEM_INFO);

	if(pdwNumberOfProcessors)
		*pdwNumberOfProcessors = 0;
	if(pwProcessorArchitecture)
		*pwProcessorArchitecture = 0;
	if(pdwProcessorType)
		*pdwProcessorType = 0;
	if(pwProcessorLevel)
		*pwProcessorLevel = 0;
	if(pwProcessorRevision)
		*pwProcessorRevision = 0;

	hDLL = ::LoadLibrary(_T("Kernel32.dll"));
	if(hDLL == NULL)
		return	false;

	(*(FARPROC*)&pfnGetNativeSystemInfo) = ::GetProcAddress(hDLL,"GetNativeSystemInfo");
	if(pfnGetNativeSystemInfo == NULL)
	{
		::FreeLibrary(hDLL);
		return	false;
	}

	::ZeroMemory(&sInfo,sizeof(SYSTEM_INFO));
	pfnGetNativeSystemInfo(&sInfo);
	::FreeLibrary(hDLL);

	if(pdwNumberOfProcessors)
		*pdwNumberOfProcessors = sInfo.dwNumberOfProcessors;
	if(pwProcessorArchitecture)
		*pwProcessorArchitecture = sInfo.wProcessorArchitecture;
	if(pdwProcessorType)
		*pdwProcessorType = sInfo.dwProcessorType;
	if(pwProcessorLevel)
		*pwProcessorLevel = sInfo.wProcessorLevel;
	if(pwProcessorRevision)
		*pwProcessorRevision = sInfo.wProcessorRevision;

	return	true;
}




void	Test(void)
{
	bool		ret;
	DWORD		dwNumberOfProcessors;
	CAtlString	strMessage;

	ret = GetCPUInformation(&dwNumberOfProcessors,NULL,NULL,NULL,NULL);

	if(ret)
	{
		strMessage.Format(_T("CPU(コア)は %d 個"),dwNumberOfProcessors);
		::MessageBox(NULL,strMessage,_T(""),MB_OK);
	}
	else
		::MessageBox(NULL,_T("取得に失敗しました"),_T(""),MB_OK);
}

プロジェクトファイルをダウンロード

2006年12月04日

使うAPIの対応OSに注意しよう

test34_01.gif
MSDNライブラリを見ていると新しいOSやサービスパック、Internet ExplorerがリリースされるたびにAPIなどが増えていることに気づく。

例えばWindows XPから追加されたものの1つのGetNativeSystemInfoというのがある。これはCPUの数などのシステム情報を取得するためのAPIだ。MSDNには左の図のように掲載されている。

ここで赤く囲んだところが注意すべきところだ。このAPIの場合はWindows XP、Vista、Windows 2003 Serverなどに対応していることが分かる。


実際にこのAPIを利用して簡単なテストプログラムを作ってみる。搭載されているCPU数を取得して表示するだけの簡単なものだ。

#include "atlstr.h"

void	Test(void)
{
	CAtlString	strMessage;
	SYSTEM_INFO	sInfo;

	::GetNativeSystemInfo(&sInfo);

	strMessage.Format(_T("CPU(コア)は %d 個"),sInfo.dwNumberOfProcessors);
	::MessageBox(NULL,strMessage,_T(""),MB_OK);
}
プロジェクトファイルをダウンロード

test34_04.gif

私のパソコンはCPUにCore Duoが使われているのでコア数が2個。そのためWindows XP環境で実行するとこのように表示された。


次に作成した実行ファイルをWindows 2000へコピーして実行してみた。すると...

test34_02.gif

このようなエラーメッセージが表示されて実行できなかった。

作成したプログラムの中に1つでも対応OSがWindows XP以降のAPIが含まれていた場合、そのプログラムはWindows 2000では起動もしなくなってしまう。これが対応OSに注意を払わなければいけない理由だ。


ではどうすればWindows 2000でも起動するプログラムにできるかと言うと、LoadLibraryで使いたいAPIが実装されているDLLファイルを読み込み、GetProcAddressでそのAPIのアドレスを取得してAPIを実行する。そうすればAPIが対応していないOSの場合は、GetProcAddressに失敗するだけで起動しなくなるという問題は起きない。
GetNativeSystemInfoを例に具体的に書くと以下のようになる。

#include "atlstr.h"


//
//	GetNativeSystemInfoラッパー関数
//
//GetNativeSystemInfoはWindows XP以降でサポートされている。
//そのためWindows 2000以前ではfalseが返る
//
bool	SafeGetNativeSystemInfo(LPSYSTEM_INFO lpSystemInfo)
{
	HMODULE	hDLL;

	void	(CALLBACK* pfnGetNativeSystemInfo)(LPSYSTEM_INFO);

	if(lpSystemInfo == NULL)
		return	false;
	::ZeroMemory(lpSystemInfo,sizeof(SYSTEM_INFO));

	hDLL = ::LoadLibrary(_T("Kernel32.dll"));
	if(hDLL == NULL)
		return	false;

	(*(FARPROC*)&pfnGetNativeSystemInfo) = ::GetProcAddress(hDLL,"GetNativeSystemInfo");
	if(pfnGetNativeSystemInfo == NULL)
	{
		::FreeLibrary(hDLL);
		return	false;
	}

	pfnGetNativeSystemInfo(lpSystemInfo);
	::FreeLibrary(hDLL);

	return	true;
}




void	Test(void)
{
	bool		ret;
	CAtlString	strMessage;
	SYSTEM_INFO	sInfo;

	ret = SafeGetNativeSystemInfo(&sInfo);

	if(ret)
	{
		strMessage.Format(_T("CPU(コア)は %d 個"),sInfo.dwNumberOfProcessors);
		::MessageBox(NULL,strMessage,_T(""),MB_OK);
	}
	else
		::MessageBox(NULL,_T("取得に失敗しました。"),_T(""),MB_OK);
}
プロジェクトファイルをダウンロード

これでAPIが対応していないWindows 2000などで実行すると以下のようにプログラム中で実装したエラーメッセージが表示される。

test34_03.gif


1番上のMSDNライブラリ画像中の赤い枠で示した部分には対応OS以外にもLoadLibraryで利用するDLL名なども書かれている。普段はあまり目がいかないかもしれないが、かなり重要なデータだ。初めて実装に使うAPIの場合は必ず確認しよう。

フォルダ選択ダイアログを表示する

test35.gif
フォルダ選択ダイアログを表示するにはSHBrowseForFolderを利用する。これはダイアログを開いたときの初期選択フォルダ設定をコールバックで指定する必要があるなど少し使い方に癖のあるAPIだ。

#include "atlstr.h"
#include "shlobj.h"



//	初期フォルダ設定用のコールバック関数
int		CALLBACK	_SHBrowseForFolderCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
	if(uMsg == BFFM_INITIALIZED)
		::SendMessage(hwnd,BFFM_SETSELECTION,TRUE,lpData);

	return	0;
}


//
//	フォルダー選択ダイアログの表示
//
//		結果は"c:\windows\"のように末尾に必ず"\"が付加する
//
bool	SelectFolderDlg(HWND hWndParent,CAtlString* lpstrFolder,LPCTSTR pszIniFolder,bool bAvailNewFolder)
{
	bool			ret;
	TCHAR			lpszPath[MAX_PATH];
	LPMALLOC		lpMalloc;
	BROWSEINFO		sInfo;
	LPITEMIDLIST	lpidlRoot;
	LPITEMIDLIST	lpidlBrowse;
	CAtlString		strIniFolder;

	if(lpstrFolder == NULL)
		return	false;
	strIniFolder = pszIniFolder;

	if(::SHGetMalloc(&lpMalloc) != NOERROR)
		return	false;

	ret = false;
	*lpstrFolder = _T("");
	if(strIniFolder != _T(""))
	{
		if(strIniFolder.Right(1) == _T("\\"))
			strIniFolder = strIniFolder.Left(strIniFolder.GetLength() - 1);			//末尾の\\を除去
	}

	lpidlRoot = NULL;
	::SHGetSpecialFolderLocation(NULL,CSIDL_DRIVES,&lpidlRoot);	//選択可能フォルダ名取得

	::ZeroMemory(&sInfo, sizeof(BROWSEINFO));
	sInfo.pidlRoot		= lpidlRoot;
	sInfo.pszDisplayName = lpszPath;
	sInfo.lpszTitle		= _T("フォルダの選択");
	sInfo.ulFlags		= BIF_RETURNONLYFSDIRS;
	if(bAvailNewFolder == true)
		sInfo.ulFlags	|= BIF_EDITBOX | BIF_NEWDIALOGSTYLE | BIF_USENEWUI;
	sInfo.lpfn			= _SHBrowseForFolderCallbackProc;
	sInfo.lParam		= (LPARAM)strIniFolder.GetBuffer(0);
	sInfo.hwndOwner		= hWndParent;

	lpidlBrowse = ::SHBrowseForFolder(&sInfo);			//フォルダ選択ダイアログ表示
	if(lpidlBrowse != NULL)
	{
		::SHGetPathFromIDList(lpidlBrowse,lpszPath);	//フォルダ名の取得
		*lpstrFolder = lpszPath;

		if(*lpstrFolder != _T(""))
		{
			if(lpstrFolder->Right(1) != _T("\\"))
				*lpstrFolder += _T("\\");			//末尾に\\が付加することを保証
		}

		ret = true;
	}

	if(lpidlBrowse != NULL)
		::CoTaskMemFree(lpidlBrowse);
	if(lpidlRoot != NULL)
		::CoTaskMemFree(lpidlRoot);

	lpMalloc->Release();

	return	ret;
}



void	Test(void)
{
	bool		ret;
	CAtlString	strMessage;

	ret = SelectFolderDlg(NULL,&strMessage,_T("c:\\"),false);

	if(ret)
		::MessageBox(NULL,strMessage,_T(""),MB_OK);
	else
		::MessageBox(NULL,_T("取得に失敗しました"),_T(""),MB_OK);
}

プロジェクトファイルをダウンロード

1  2  3  4  5  6  7  8  9  10





usefullcode@gmail.com

About 2006年12月

2006年12月にブログ「UsefullCode.net」に投稿されたすべてのエントリーです。

前の記事は2006年11月です。

次の記事は2007年01月です。

他にも多くのエントリーがあります。メインページ記事一覧も見てください。