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

前の10件 1  2  3  4  5  6  7  8  9  10

2006年12月 記事一覧

「ハードウエアの安全な取り外し」ウインドウを表示する

検索エンジンから来る方はプログラミングには興味なく、「ハードウエアの安全な取り外し」ウインドウが表示できなくて困っているようですので以下のソフトを用意しました。
ShowEjectDeviceWindow.exe
このソフトをダウンロード後、実行すると、「ハードウエアの安全な取り外し」ウインドウが表示されます。Windows Vistaでも利用可能です。

test57_02.gif
「ハードウエアの安全な取り外し」ウインドウを表示するlコマンドとして

rundll32 shell32.dll,Control_RunDLL hotplug.dll

がよく知られている。プログラムの中からこれを呼んでもいいのだが、ここでは直接hotplug.dll内の関数にアクセスして表示している。直接利用すると親ウインドウを設定できるというメリットがある。


test57_01.gif
hotplug.dll内の「HotPlugDeviceTree」という関数を利用している。この関数の第一引数は親ウインドウのハンドル指定、第二引数は不明で0を指定、第三引数はTRUEを指定する。もしも第三引数にFALSEを指定すると...図のようにデバイスが一覧された画面が開く。ただしこの方法はWindows Vistaでは利用できない。Vistaでは「HotPlugDeviceTree」という関数が実装されなくなったためだ。


ちなみにデバイスを取り外す正攻法は「CM_Request_Device_Eject_Ex」を利用する方法だ。

//
//「ハードウエアの安全な取り外し」ウインドウを開く
//
//対応OSは不明
//
bool	ShowHotPlugDeviceTree(HWND hParentWnd=NULL)
{
	HMODULE	hDLL;

	//戻り値は2が返る。第2、第3引数は(0,TRUE)にする
	int		(CALLBACK* pfnHotPlugDeviceTree)(HWND,DWORD,BOOL);

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

	(*(FARPROC*)&pfnHotPlugDeviceTree) = ::GetProcAddress(hDLL,"HotPlugDeviceTree");
	if(pfnHotPlugDeviceTree)
		pfnHotPlugDeviceTree(hParentWnd,0,TRUE);

	::FreeLibrary(hDLL);

	return	true;
}



void	Test(void)
{
	ShowHotPlugDeviceTree();
}

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

アイコンファイルを読み込んで描画する

test58.gif
アイコンを.icoファイルから読み込むにはLoadImageを利用する。DCへの描画はDrawIconでできる。
取得したHICONは使い終わったら必ずDestroyIconにより破棄する。
ここではデスクトップ上に読み込んだアイコンを並べて表示した。

bool	Test(void)
{
	HDC		hDC;
	HICON	hIcon;

	//icoファイルの読み込み
	hIcon = (HICON)::LoadImage(NULL,_T("test58.ico"),IMAGE_ICON,0,0,LR_DEFAULTSIZE | LR_LOADFROMFILE); 
	if(hIcon == NULL)
		return	false;

	//描画用DC取得
	hDC = ::GetDC(NULL);

	//描画
	{
		int		i;
		for(i = 0; i < 10; i++)
			::DrawIcon(hDC,100 + i*30,100,hIcon);
	}

	//描画用DCの破棄
	::ReleaseDC(NULL,hDC);

	//アイコンの破棄
	::DestroyIcon(hIcon);

	return	true;
}

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

実行ファイルのアイコンを取得して描画する

test59.gif
実行ファイルに使われているアイコンを取得したい場合はSHGetFileInfoを利用すると楽だ。この関数は第5引数に指定するフラグによってさまざまな情報をファイルから取り出せる。利用する前にMSDNライブラリでチェックするといいだろう。アイコン(HICON)は使い終わったらDestroyIconで破棄する必要がある。

ここではSHGetFileInfoで取得したレジストリエディタのアイコンをデスクトップ上に並べて描画した。

#include "shellapi.h"


bool	Test(void)
{
	HDC			hDC;
	HICON		hIcon;
	SHFILEINFO	sShFileInfo;

	//アイコンの読み込み
	::ZeroMemory(&sShFileInfo,sizeof(SHFILEINFO));
	::SHGetFileInfo(_T("c:\\windows\\regedit.exe"),0,&sShFileInfo,sizeof(SHFILEINFO),SHGFI_ICON | SHGFI_LARGEICON);

	hIcon = sShFileInfo.hIcon;
	if(hIcon == NULL)
		return	false;


	//描画用DC取得
	hDC = ::GetDC(NULL);

	//描画
	{
		int		i;
		for(i = 0; i < 10; i++)
			::DrawIcon(hDC,100 + i*30,100,hIcon);
	}

	//描画用DCの破棄
	::ReleaseDC(NULL,hDC);

	//アイコンの破棄
	::DestroyIcon(hIcon);

	return	true;
}

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

2006年12月11日

シェルバージョン情報を表示する

test60_01.gif
図のようなバージョン情報画面を表示するためのAPIとしてShellAboutが用意されている。
このAPIは自分が開発したアプリケーションで利用できるように作られている。図の例であれば「aaaaのバージョン情報」やCopyrightの下に「bbbbb」というような表示があったり、レジストリエディタのアイコンが使われている。これらを自由に指定できる。

test60_02.gif
このShellAboutはWindows 95以降でサポートされているのでOS依存性もなく使いやすい。しかしながら、OSによって見た目が大きく変わるのが難点。

図はWindows VistaでのShellAbout。

test60_03.gif
こちらはWindows 2000。

test60_04.gif
そしてWindows 98 SE。


#include "shellapi.h"


bool	Test(void)
{
	BOOL		ret;
	HICON		hIcon;
	SHFILEINFO	sShFileInfo;

	//アイコンの読み込み
	::ZeroMemory(&sShFileInfo,sizeof(SHFILEINFO));
	::SHGetFileInfo(_T("c:\\windows\\regedit.exe"),0,&sShFileInfo,sizeof(SHFILEINFO),SHGFI_ICON | SHGFI_LARGEICON);

	hIcon = sShFileInfo.hIcon;
	if(hIcon == NULL)
		return	false;

	ret = ::ShellAbout(NULL,_T("aaaa"),_T("bbbbbb"),hIcon);


	//アイコンの破棄
	::DestroyIcon(hIcon);

	return	ret ? true : false;
}

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

Windows Vistaでブルースクリーンに遭遇した

vista01.gif
私はWindows Vistaを無線LAN上に置いた仮想HDDにインストールして利用している。Windows Vistaを再起動したとき無線LANの接続が一瞬途切れたら...図のようなブルースクリーンが現れた。「STOP: c000021a Unknown Hard Error」とか言われてしまっている。

vista02.gif
その後自動的に再起動がかかり、Windows Vistaが起動すると「Windowsは予期しないシャットダウンから回復しました」の表示。

vista03.gif
よくあることだが問題の詳細を見てもサッパリわからない不親切さは相変わらず。しかしWindows Vistaでは「解決策の確認」ボタンが用意されていた。押してみると...

vista04.gif
Mirosoftのサイトのアクセスしているのだろうか?「この問題の解決策を確認しています...」と表示された。

vista05.gif
そしてすぐにその画面は自動的に消えた。しかし肝心の解決策とやらが表示される気配がない!少し中途半端な実装になっているようだ。


色選択ダイアログを表示する

test61.gif
色選択ダイアログを表示するための関数としてChooseColorが用意されている。
この関数では引数にパラメータを指定することである程度自由がきくため使いやすい。しかし今回は図のようなダイアログを表示するだけとした。

#include "commdlg.h"


//
//	色選択ダイアログの表示
//
//pDefaultAndResultにはデフォルトで選択されている色を代入すること
//結果はpDefaultAndResultに返る
//
bool	ShowChooseColorDialog(HWND hParentWnd,COLORREF* pDefaultAndResult)
{
	BOOL		ret;
	CHOOSECOLOR	sChooseColor;
	static	COLORREF	pRGB[16];	//必ずstatic!

	if(pDefaultAndResult == NULL)
		return	false;

	::ZeroMemory(pRGB,sizeof(COLORREF) * 16);	//16個ともRGB(0,0,0)
	::ZeroMemory(&sChooseColor,sizeof(CHOOSECOLOR));
	sChooseColor.lStructSize= sizeof(CHOOSECOLOR);
	sChooseColor.Flags		= CC_ANYCOLOR | CC_RGBINIT | CC_FULLOPEN;
	sChooseColor.rgbResult	= *pDefaultAndResult;
	sChooseColor.lpCustColors = pRGB;
	sChooseColor.hwndOwner	= hParentWnd;
	ret = ::ChooseColor(&sChooseColor);
	if(ret == FALSE)
		return	false;

	*pDefaultAndResult = *sChooseColor.lpCustColors;

	return	true;
}





void	Test(void)
{
	bool		ret;
	COLORREF	sColor;

	//デフォルトで赤を選択
	sColor = RGB(0xff,0,0);
	ret = ShowChooseColorDialog(NULL,&sColor);
	if(ret)
		::MessageBox(NULL,_T("色を選択しました"),_T(""),MB_OK);
	else
		::MessageBox(NULL,_T("色に変更はありません"),_T(""),MB_OK);
}

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

2006年12月12日

IEを起動してGoogleで検索する

Internet ExploreはCOMインターフェースで操作できる。ここではCoCreateInstanceでIEを起動してGoogle検索を実行した。
Googleの既定の文字コードはUTF8。UnicodeやShift-JISからUTF8へ変換するのはちょっとだけ面倒なので、ここではShift-JISをそのまま検索に用いている。

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

#include "exdisp.h"
#include "mshtml.h"


//
//	IEによるGoogle検索
//
//Internet Explorerを新たに起動してGoogleで検索する
//
bool	SearchByGoogle(LPCTSTR pszWord)
{
	HRESULT		hr;
	VARIANT		vEmpty;
	BSTR		bstrURL;
	CAtlString	strURL;
	CAtlString	strWord;
	IWebBrowserApp*	pIWebBrowserApp;

	if(pszWord == NULL || *pszWord == NULL)
		return	false;

	//IE起動
	pIWebBrowserApp = NULL;
	hr = ::CoCreateInstance(CLSID_InternetExplorer,NULL,CLSCTX_SERVER,IID_IWebBrowserApp,(void**)&pIWebBrowserApp);
	if(FAILED(hr) || pIWebBrowserApp == NULL)
		return	false;


	//検索語のエンコード
	//面倒なのでa-zや0-9など必要ないものも%xx形式にしている
	{
		int			i;
		int			nSize;
		CAtlStringA	strTmp1;
		CAtlString	strTmp2;

		strTmp1 = pszWord;
		nSize = strTmp1.GetLength();
		for(i = 0; i < nSize; i++)
		{
			strTmp2.Format(_T("%%%02x"),(BYTE)strTmp1[i]);
			strWord += strTmp2;
		}
	}

	//URLを開く
	::VariantInit(&vEmpty);
	strURL.Format(_T("http://www.google.co.jp/search?q=%s&ie=sjis&hl=ja&lr=&num=100"),strWord);
	bstrURL = strURL.AllocSysString();
	hr = pIWebBrowserApp->Navigate(bstrURL,&vEmpty,&vEmpty,&vEmpty,&vEmpty);
	::SysFreeString(bstrURL);

	//IEの可視化
	if(SUCCEEDED(hr))
		hr = pIWebBrowserApp->put_Visible(VARIANT_TRUE);

	if(FAILED(hr))
	{
		pIWebBrowserApp->Quit();
		pIWebBrowserApp->Release();
		return	false;
	}

	return	true;
}




void	Test(void)
{
	::CoInitialize(NULL);

	SearchByGoogle(_T("プログラミング"));

	::CoUninitialize();
}

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

2006年12月14日

ウインドウを探す

現在開いているウインドウを列挙するAPIとしてEnumWindowsがある。この関数は引数として"コールバック関数"を指定して使う。
ここでは使用例としてInternet Explorerを見つけるクラスを作成した。コールバック関数EnumWindowsProc_をクラスのメンバ関数として定義して利用している。

class	CDnpEnumInternetExplore
{
	//
	//	EnumWindowsのコールバック関数
	//
	//※ユーザーは直接呼ばないこと!
	//
	static	BOOL	CALLBACK	EnumWindowsProc_(HWND hwnd,LPARAM lParam)
	{
		if(lParam == NULL)
			return	FALSE;
		return	((CDnpEnumInternetExplore*)lParam)->EnumWindowsProc(hwnd);
	}

public:


	//
	//	列挙開始
	//
	bool	EnumStart(void)
	{
		BOOL	ret;

		ret = ::EnumWindows(EnumWindowsProc_,(LPARAM)this);

		return	ret ? true : false;
	}


	//
	//	EnumWindowsのコールバック実処理関数
	//
	//※ユーザーは直接呼ばないこと!
	//
	BOOL	EnumWindowsProc(HWND hwnd)
	{
		int		nRet;
		TCHAR	pszName[1024];

		//ウインドウクラスの取得
		nRet = ::GetClassName(hwnd,pszName,1024);
		if(nRet == 0)
			return	TRUE;

		//IEはクラス名が"IEFrame"
		nRet = ::_tcscmp(pszName,_T("IEFrame"));
		if(nRet != 0)
			return	TRUE;

		//ウインドウタイトル取得
		nRet = ::GetWindowText(hwnd,pszName,1024);
		if(nRet == 0)
			return	TRUE;

		//ウインドウタイトル表示
		::MessageBox(NULL,pszName,_T(""),MB_OK);

		return	TRUE;
	}
};




void	Test(void)
{
	CDnpEnumInternetExplore	cEnum;

	cEnum.EnumStart();
}

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

IEを探し出してIHTMLDocument2を取得する

現在開いているInternet Explorerを探し出して、アクセスしているURLを表示する。
Internet Explorerのウインドウを探し出すにはEnumWindowsとEnumChildWindowsを利用する。そして求めたウインドウハンドルからCOMインターフェースを取得してURLを表示している。ここではIHTMLDocument2へのポインタを取得したが、これを用いればHTMLソースの取得から改変。新しいURLへのジャンプ…IE上での操作をほぼすべて行える。
またこの方法はIE6までの従来スタイルのIEからタブブラウザタイプのIE7にまで対応する。

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

#include "exdisp.h"
#include "mshtml.h"



//
//HWNDからIHTMLDocument2の取得(MSDN改変)
//
//HWNDは"Internet Explorer_Server"のウインドウハンドル
//bHwndIsServer==falseのときは"Shell DocObject View"のウインドウハンドルとして処理
//
bool	GetHTMLDocument2FromHWND(HWND hWnd,IHTMLDocument2** ppIHTMLDocument2,bool bHwndIsServer=true)
{
	HINSTANCE	hInst;
	LRESULT		lRes;
	UINT		nMsg;
	LRESULT		ret;

	LPFNOBJECTFROMLRESULT pfObjectFromLresult;

	if(ppIHTMLDocument2 == NULL || hWnd == NULL || ::IsWindow(hWnd) == FALSE)
		return	false;

	if(bHwndIsServer == false)
	{
		//"Shell DocObject View"へのハンドルとして処理
		hWnd = ::FindWindowEx(hWnd,NULL,_T("Internet Explorer_Server"),NULL);
		if(hWnd == NULL)
			return	false;
	}

	hInst = ::LoadLibrary(_T("OLEACC.DLL"));
	if(hInst == NULL)
		return	false;

	nMsg = ::RegisterWindowMessage(_T("WM_HTML_GETOBJECT"));
	ret = ::SendMessageTimeout(hWnd,nMsg,0,0,SMTO_ABORTIFHUNG,1000,(DWORD*)&lRes);
	if(ret == 0)
		return	false;

	pfObjectFromLresult = (LPFNOBJECTFROMLRESULT)::GetProcAddress(hInst,"ObjectFromLresult");
	if(pfObjectFromLresult)
		(*pfObjectFromLresult)(lRes,IID_IHTMLDocument2,0,(void**)ppIHTMLDocument2);

	::FreeLibrary(hInst);

	return	*ppIHTMLDocument2 ? true : false;
}





class	CDnpEnumInternetExplore
{
	//
	//	EnumWindowsのコールバック関数
	//
	//※ユーザーは直接呼ばないこと!
	//
	static	BOOL	CALLBACK	EnumWindowsProc_(HWND hwnd,LPARAM lParam)
	{
		if(lParam == NULL)
			return	FALSE;
		return	((CDnpEnumInternetExplore*)lParam)->EnumWindowsProc(hwnd);
	}



	//
	//	EnumChildWindowsのコールバック関数
	//
	//※ユーザーは直接呼ばないこと!
	//
	static	BOOL CALLBACK	EnumChildProc_(HWND hwnd,LPARAM lParam)
	{
		if(lParam == NULL)
			return	FALSE;
		return	((CDnpEnumInternetExplore*)lParam)->EnumChildProc(hwnd);
	}
public:


	//
	//	列挙開始
	//
	bool	EnumStart(void)
	{
		BOOL	ret;

		ret = ::EnumWindows(EnumWindowsProc_,(LPARAM)this);

		return	ret ? true : false;
	}


	//
	//	EnumWindowsのコールバック実処理関数
	//
	//※ユーザーは直接呼ばないこと!
	//
	BOOL	EnumWindowsProc(HWND hwnd)
	{
		int		nRet;
		TCHAR	pszName[1024];

		//ウインドウクラスの取得
		nRet = ::GetClassName(hwnd,pszName,1024);
		if(nRet == 0)
			return	TRUE;

		//IEはクラス名が"IEFrame"
		nRet = ::_tcscmp(pszName,_T("IEFrame"));
		if(nRet != 0)
			return	TRUE;

		//子ウインドウの列挙方法
		::EnumChildWindows(hwnd,EnumChildProc_,(LPARAM)this);

		return	TRUE;
	}



	//
	//	EnumChildWindowsのコールバック実処理関数
	//
	//※ユーザーは直接呼ばないこと!
	//
	BOOL	EnumChildProc(HWND hwnd)
	{
		int		nRet;
		bool	ret;
		HRESULT	hr;
		BSTR	bstrURL;
		TCHAR	pszName[1024];
		IHTMLDocument2*	pIHTMLDocument2;

		//ウインドウクラスの取得
		nRet = ::GetClassName(hwnd,pszName,1024);
		if(nRet == 0)
			return	TRUE;

		//クラス名"Internet Explorer_Server"を取得
		nRet = ::_tcscmp(pszName,_T("Internet Explorer_Server"));
		if(nRet != 0)
			return	TRUE;

		//HWNDからIHTMLDocument2の取得
		pIHTMLDocument2 = NULL;
		ret = GetHTMLDocument2FromHWND(hwnd,&pIHTMLDocument2);
		if(ret == false || pIHTMLDocument2 == NULL)
			return	TRUE;

		//URL取得
		bstrURL = NULL;
		hr = pIHTMLDocument2->get_URL(&bstrURL);
		if(SUCCEEDED(hr))
		{
			CAtlString	strURL;

			//BSTRからCString(TCHAR)への変換
			strURL = (WCHAR*)bstrURL;
			::SysFreeString(bstrURL);

			//URL表示
			::MessageBox(NULL,strURL,_T(""),MB_OK);
		}

		pIHTMLDocument2->Release();

		return	TRUE;
	}

};




void	Test(void)
{
	::CoInitialize(NULL);

	CDnpEnumInternetExplore	cEnum;

	cEnum.EnumStart();

	::CoUninitialize();
}

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

2006年12月15日

ファイルを開く/保存するダイアログを表示する

test65.gif
「ファイルを開く」や「ファイルを保存」ダイアログはそれぞれGetOpenFileName、GetSaveFileNameで表示することができる。これらの関数は引数にOPENFILENAME構造体を使う。
OPENFILENAMEにより複数ファイルを開くなどさまざまな処理が可能だが、ここでは普段利用するであろう機能に絞って実装した。

#include "atlstr.h"


#include "commdlg.h"


//
//	ファイルを開く/保存するダイアログ表示
//
//bSaveDialog==trueで保存用、falseで開くためのダイアログを表示
//pszInitFolerで初期選択フォルダ指定(ex._T("d:\\"))
//pszFilterExt、pszFilterNameでファイルの拡張子指定(ex.pszFilterExt=_T("*.txt")、pszFilterName=_T("テキストファイル"))
//bUseAllFilter==trueで全てのファイル(*.*)を使うかどうかの指定
//pszTitleでダイアログタイトルの指定
//
bool	ShowFileOpenSaveDialog(HWND hParentWnd,CAtlString* pstrFileName,bool bSaveDialog,LPCTSTR pszInitFoler=NULL,LPCTSTR pszFilterExt=NULL,LPCTSTR pszFilterName=NULL,bool bUseAllFilter=true,LPCTSTR pszTitle=NULL)
{
	BOOL			ret;
	TCHAR			pszName[2048];
	TCHAR			pszFilter[2048];
	OPENFILENAME	sOpenFileName;

	if(pstrFileName == NULL)
		return	false;
	*pstrFileName = _T("");

	/////////////////////////////////
	//フィルター作成
	//

	//\0の代わりに\1を使っていることに注意!
	pszFilter[0] = NULL;
	if(pszFilterExt && pszFilterName)
		::_stprintf_s(pszFilter,2048 * sizeof(TCHAR),_T("%s\1%s\1"),pszFilterName,pszFilterExt);
	else if(pszFilterExt)
		::_stprintf_s(pszFilter,2048 * sizeof(TCHAR),_T("%s\1%s\1"),pszFilterExt,pszFilterExt);
	else if(bUseAllFilter == false)
		return	false;

	if(bUseAllFilter)
	{
		if(pszFilter[0])
			::_tcscat_s(pszFilter,2048 * sizeof(TCHAR),_T("All file\1*.*\1"));
		else
			::_stprintf_s(pszFilter,2048 * sizeof(TCHAR),_T("All file\1*.*\1"));
	}
	else
		::_tcscat_s(pszFilter,2048 * sizeof(TCHAR),_T("\1"));

	//\1を\0に置換
	{
		size_t	i;
		size_t	nSize;

		nSize = ::_tcslen(pszFilter);
		for(i = 0; i < nSize; i++)
		{
			if(pszFilter[i] == '\1')
				pszFilter[i] = '\0';
		}
	}

	/////////////////////////////////
	//パラメータ初期化
	//
	pszName[0] = NULL;
	::ZeroMemory(&sOpenFileName,sizeof(OPENFILENAME));
	sOpenFileName.lStructSize	= sizeof(OPENFILENAME);
	sOpenFileName.hwndOwner		= hParentWnd;
	sOpenFileName.lpstrFile		= pszName;
	sOpenFileName.nMaxFile		= 2048;
	sOpenFileName.lpstrFilter	= pszFilter;
	sOpenFileName.nFilterIndex	= 1;
	sOpenFileName.lpstrTitle	= pszTitle;
	sOpenFileName.nMaxFileTitle	= pszTitle ? (DWORD)::_tcslen(pszTitle) : 0;
	sOpenFileName.lpstrInitialDir = pszInitFoler;
	sOpenFileName.Flags			= OFN_PATHMUSTEXIST | OFN_DONTADDTORECENT | OFN_EXPLORER | (bSaveDialog ? OFN_OVERWRITEPROMPT : OFN_FILEMUSTEXIST);


	/////////////////////////////////
	//ダイアログ表示
	//
	if(bSaveDialog)
		ret = ::GetSaveFileName(&sOpenFileName);
	else
		ret = ::GetOpenFileName(&sOpenFileName);

	if(ret == FALSE)
		return	false;

	*pstrFileName = pszName;

	return	true;
}



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

	ret = ShowFileOpenSaveDialog(NULL,&strFile,true,_T("d:"),_T("*.txt"),_T("テキストファイル"));

	if(ret)
		::MessageBox(NULL,strFile,_T(""),MB_OK);
}

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

前の10件 1  2  3  4  5  6  7  8  9  10





usefullcode@gmail.com

About 2006年12月

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

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

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

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