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

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

2006年12月 記事一覧

MFCアプリケーションウイザードでのプロジェクトがユニコードビルドにならないようにする

mfc_01.gif
MFCアプリケーションウィザードではデフォルトで「ユニコードライブラリを使用する」にチェックが入っている。そのためそのままの状態で作成するとユニコードビルドされるプロジェクトになる。

毎回このチェックを手動で外して非ユニコードビルドにしている人もいるのではないだろうか?ちょっと変更するだけでデフォルトでチェックが入っていない状態にできる。

mfc_04.gif
Visual Studio 2005のインストールフォルダにあるMFCアプリケーションウィザード用のHTMLをテキストエディタなどで開く。

標準であれば以下のパスになる。
C:\Program Files\ Microsoft Visual Studio 8\ VC\ VCWizards\ AppWiz\ MFC\ Application\ html\ 1041\ default.html


mfc_03.gif
そして618行目、InitDocument()内にある「window.external.AddSymbol("UNICODE", true);」の部分を「window.external.AddSymbol("UNICODE", false);」に変更する。要はtrueをfalseに変えればいい。

mfc_02.gif
これで次回からMFCアプリケーションウイザードでは標準で「ユニコードライブラリを使用する」のチェックが外れた状態になる。


IProgressDialogによるプログレスダイアログを使う

test73.gif
ファイルコピー中などに表示される進行ダイアログはCOMインターフェースのIProgressDialogにより表示できる。このインターフェースはAVIファイルの指定によるアニメーション設定などきめ細かく設定できるので便利に使える。
ここでは楽に実装できるようにラッパークラスを作成し、Test2で利用している。

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

#include "shlobj.h"


class	CDnpProgressDialog
{
	IProgressDialog*	_pIProgressDialog;

public:
	CDnpProgressDialog()
	{
		_pIProgressDialog = NULL;
	}

	~CDnpProgressDialog()
	{
		Uninitialize();
	}


	//
	//	解放処理
	//
	void	Uninitialize(void)
	{
		if(_pIProgressDialog == NULL)
			return;

		_pIProgressDialog->StopProgressDialog();
		_pIProgressDialog->Release();
		_pIProgressDialog = NULL;
	}



	//
	//	プログレスダイアログの表示
	//
	bool	ShowProgressDialog(HWND hParentWnd,LPCTSTR pszTitle,LPCTSTR pszCancelMsg,UINT nAVIResource=0)
	{
		HRESULT	hr;

		if(_pIProgressDialog)
			return	false;

		hr = ::CoCreateInstance(CLSID_ProgressDialog,NULL,CLSCTX_INPROC_SERVER,IID_IProgressDialog,(void**)&_pIProgressDialog);
		if(_pIProgressDialog == NULL)
			return	false;

		if(SUCCEEDED(hr))
			hr = _pIProgressDialog->SetTitle((CStringW)pszTitle);

		if(SUCCEEDED(hr) && nAVIResource)
			hr = _pIProgressDialog->SetAnimation(NULL,nAVIResource);

		if(SUCCEEDED(hr))
			hr = _pIProgressDialog->SetCancelMsg((CStringW)pszCancelMsg,NULL);

		if(SUCCEEDED(hr))
			hr = _pIProgressDialog->SetProgress(100,0);

		if(FAILED(hr))
		{
			_pIProgressDialog->Release();
			_pIProgressDialog = NULL;
			return	false;
		}

		hr = _pIProgressDialog->StartProgressDialog(hParentWnd,NULL,PROGDLG_NORMAL,NULL);

		return	SUCCEEDED(hr) ? true : false;
	}


	//
	//	プログレスバー位置の設定
	//
	bool	SetProgress(DWORD dwCompleted,DWORD dwTotal)
	{
		HRESULT	hr;

		if(_pIProgressDialog == NULL)
			return	false;

		hr = _pIProgressDialog->SetProgress(dwCompleted,dwTotal);

		return	SUCCEEDED(hr) ? true : false;
	}


	//
	//	メッセージの表示
	//
	//nLineは1~3の範囲で指定する
	//
	bool	SetMessage(UINT nLine,LPCTSTR pszMessage)
	{
		HRESULT	hr;

		if(_pIProgressDialog == NULL)
			return	false;

		hr = _pIProgressDialog->SetLine(nLine,(CStringW)pszMessage,FALSE,NULL);

		return	SUCCEEDED(hr) ? true : false;
	}



	//
	//	処理を中止するかどうか
	//
	bool	IsAbort(void)
	{
		if(_pIProgressDialog == NULL)
			return	true;

		return	_pIProgressDialog->HasUserCancelled() ? false : true;
	}
};




bool	Test2(void)
{
	DWORD	dwProgress;
	CDnpProgressDialog	dlg;

	//プログレスダイアログの表示
	dlg.ShowProgressDialog(NULL,_T("プログレスダイアログを使用した処理"),_T("処理をキャンセル中です。"));

	//メッセージを表示
	dlg.SetMessage(1,_T("ダミー処理中です。"));
	dlg.SetMessage(3,_T("「キャンセル」ボタンを押すまで処理が続きます。"));

	dwProgress = 0;
	while(dlg.IsAbort())
	{
		//刻々変わるメッセージを表示
		CAtlString	strMessage;
		strMessage.Format(_T("処理をしています(%d)"),::GetTickCount());
		dlg.SetMessage(2,strMessage);

		//プログレスバーの進行状態設定
		//プログレスバーがいっぱいになったら元にもどす
		dlg.SetProgress(dwProgress,100);
		if(++dwProgress >= 100)
			dwProgress = 0;

		//////////////////////////////
		//何かの処理を次の1行の代わりに置く
		::Sleep(50);
	}

	dlg.Uninitialize();

	return	true;
}


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

	Test2();

	::CoUninitialize();

	return	true;
}

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

Windows Vistaの管理者権限アイコンをボタンに表示する

test74.gif
Windows Vista上で操作に管理者権限が必要なことがユーザーにひと目でわかるようにアイコンをボタンに表示する。
方法は非常に簡単で、BCM_SETSHIELDメッセージをボタンに対して送るだけでいい。その際にLPARAM=TRUEにするとアイコン表示、FALSEにするとアイコン消去となる。

この実装用にButton_SetElevationRequiredStateというマクロが定義されているのでこれを利用してもいい。


ここではWTLアプリケーションウィザードでダイアログベースのプロジェクトを作成し、その「OK」ボタンに対してアイコンを表示した。

■MainDlg.hのOnInitDialog()内に追加
		//Windows Vista管理者アイコンをボタンに設定する
		//以下の3行はどれも同じ動作をする
		Button_SetElevationRequiredState(GetDlgItem(IDOK), TRUE);
		//::SendMessage(GetDlgItem(IDOK),BCM_SETSHIELD,NULL,(LPARAM)TRUE);
		//::SendMessage(GetDlgItem(IDOK),(BCM_FIRST + 0x000C),NULL,(LPARAM)TRUE);

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

言語に応じたファイルへのパスを取得する

多言語のユーザーインターフェースを持つアプリケーションを作成するためのMUI関連APIの1つにGetFileMUIPathがある。これは言語に応じたreadmeや画像などのファイルへのパスを取得するために用意されている。
例えば「c:\test\readme.txt」というパスに対してGetFileMUIPathを実行すると、日本語UIのときは「c:\test\ja-jp\readme.txt」、英語なら「c:\test\en-us\readme.txt」、ドイツ語なら「「c:\test\de-de\readme.txt」」のように自動的に言語に応じたフォルダ内のファイルへのパスに置き換わる。ただしその言語のファイルが用意されていない場合はデフォルトの言語用のパスになる。

ここでは言語に応じたreadme.txtへのパスを取得し、それをShellExecuteによって開いている。

#include "shellapi.h"

void	Test(void)
{
	BOOL		ret;
    WCHAR		pwszMUILanguage[LOCALE_NAME_MAX_LENGTH];
	ULONG		nMUILanguageSize;
    WCHAR		pwszFileMUIPath[MAX_PATH*10];
    ULONG		nFileMUIPathSize;
    ULONGLONG	nEnumerator;
	int			nRet;

	//「はい」ボタンが押されたら言語として英語を選択する
	nRet = ::MessageBox(NULL,_T("英語にしますか?"),_T(""),MB_YESNO);
	if(nRet == IDYES)
		::SetThreadUILanguage(MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT));

	//選択した言語に応じたreadme.txtへのパスを取得する
	nMUILanguageSize = LOCALE_NAME_MAX_LENGTH;
	nFileMUIPathSize = MAX_PATH * 10;
	nEnumerator = 0;
	ret = ::GetFileMUIPath(0,L"readme.txt",pwszMUILanguage,&nMUILanguageSize,pwszFileMUIPath,&nFileMUIPathSize,&nEnumerator);

	//選択した言語に応じたreadme.txtを開く
	if(ret)
		::ShellExecute(NULL,_T("open"),pwszFileMUIPath,NULL,NULL,SW_SHOWNORMAL);
}

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

2006年12月18日

Windows Media Playerコントロールで動画を再生する

test76.gif
Windowsに標準で備わるWindows Media Playerを利用すればMPEGやAVIなどの動画ファイルを簡単に再生できる。


ここではWTLアプリケーションウイザードでダイアログベースのプロジェクトを作成し、MainDlg.hにコードを追加した。実行すると「c:\test.avi」を再生する。

■MainDlg.hの最初に追加
#include "wmp.h"

■MainDlg.hのCMainDlgのメンバ変数として追加
    CAxWindow			_wndAxWindow;
    CComPtr<IWMPPlayer>	_pIWMPPlayer;
■MainDlg.hのOnInitDialog()内に追加
		/////////////////////////////
		//Windows Media Playerコントロールの生成と表示
		//
		bool	ret;
		RECT	rcClient;
		HRESULT	hr;
		CComPtr<IAxWinHostWindow>	pIAxWinHostWindow;

		GetClientRect(&rcClient);
		rcClient.right -= 100;

		ret = false;
		_wndAxWindow.Create(m_hWnd,rcClient,NULL,WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN,WS_EX_CLIENTEDGE);
		if(_wndAxWindow.IsWindow())
			ret = true;

		if(ret)
			_wndAxWindow.QueryHost(&pIAxWinHostWindow);

		if(pIAxWinHostWindow)
			hr = pIAxWinHostWindow->CreateControl(CComBSTR(L"{6BF52A52-394A-11d3-B153-00C04F79FAA6}"),_wndAxWindow,0);
		else
			hr = E_FAIL;

		if(SUCCEEDED(hr))
			hr = _wndAxWindow.QueryControl(&_pIWMPPlayer);

		if(FAILED(hr) || _pIWMPPlayer == NULL)
			ret = false;


		/////////////////////////////
		//動画ファイルの読み込みと再生開始
		//

		if(_pIWMPPlayer)
		{
			CComPtr<IWMPControls> pIWMPControls;

			_pIWMPPlayer->close();
			_pIWMPPlayer->QueryInterface(&pIWMPControls);
			if(pIWMPControls)
			{
				pIWMPControls->stop();
				_pIWMPPlayer->put_URL(CComBSTR(L"c:\\test.avi"));
				pIWMPControls->play();
			}
		}

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

ファイルのプロパティを表示する

test77.gif
ファイルのプロパティを表示するにはShellExecuteExに対して「properties」を渡す。

#include "shellapi.h"

bool	ShowProperty(HWND hParentWnd,LPCTSTR pszFile)
{
	BOOL	ret;
	SHELLEXECUTEINFO	sInfo;

	::ZeroMemory(&sInfo,sizeof(SHELLEXECUTEINFO));
	sInfo.cbSize	= sizeof(SHELLEXECUTEINFO);
	sInfo.hwnd		= hParentWnd;
	sInfo.lpVerb	= _T("properties");
	sInfo.lpFile	= pszFile;
	sInfo.fMask		= SEE_MASK_INVOKEIDLIST;
	sInfo.nShow		= SW_SHOWNORMAL;
	ret = ::ShellExecuteEx(&sInfo);

	return	ret ? true : false;
}


void	Test(void)
{
	ShowProperty(NULL,_T("Test07.cpp"));


	//プログラムが終了すると表示したプロパティが消えるのでメッセージボックスを表示して消えないようにする
	::MessageBox(NULL,_T("ダミー"),_T(""),MB_OK);
}

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

パスの末尾に「¥」を付加する

パスの末尾に「¥」を付加する。strcat(_tcscat_s)を使ってもいいが、ここでは専用のAPI「PathAddBackslash」を使った。

この関数は与えられたパスに対して、末尾が「¥」でなければ「¥」を追加する。与えられた存在するファイルへのパスであっても「¥」が付加されるので注意。

#include "shlwapi.h"
#pragma	comment(lib,"shlwapi.lib")


bool	Test(void)
{
	TCHAR	pszPath[MAX_PATH];
	TCHAR*	pszRet;

	//テスト用のパス文字列を代入
	::_tcscpy_s(pszPath,MAX_PATH * sizeof(TCHAR),_T("c:\\windows"));

	//処理
	pszRet = ::PathAddBackslash(pszPath);
	if(pszRet == NULL)
		return	false;

	//結果表示
	::MessageBox(NULL,pszPath,_T(""),MB_OK);

	return	true;
}

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

ドラッグアンドドロップでファイルやフォルダを取得する

ウインドウへファイルやフォルダをドラッグ・アンド・ドロップできるようにするにはDragAcceptFilesを実行すればいい。

ファイルやフォルダがドロップされるとそのウインドウにWM_DROPFILESメッセージが送られる。このメッセージのWPARAMはドラッグ・アンド・ドロップを処理するためのハンドル(HDROP)になっている。これを、DragQueryFile、DragQueryFile、DragFinishに渡すことでファイルやフォルダを取得する。


ここではWTLアプリケーションウイザードでダイアログベースのプロジェクトを作成、MainDlg.h内に以下のコードを追加した。

■MainDlg.hの最初に追加
#include "atlstr.h"

■MainDlg.hのBEGIN_MSG_MAPとEND_MSG_MAPの間に追加
		//ドラッグアンドドロップ用メッセージマップ
		MESSAGE_HANDLER(WM_DROPFILES, OnDropFiles)

■MainDlg.hのCMainDlgにメンバ関数として追加
	//
	//	ドラッグアンドドロップ用メッセージハンドラ
	//
	LRESULT OnDropFiles(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
	{
		UINT	i;
		UINT	nSize;
		UINT	ret;
		HDROP	hDrop;
		TCHAR	pszBuff[MAX_PATH*10];
		CAtlString	strMessage;

		hDrop = (HDROP)wParam;
		nSize = ::DragQueryFile(hDrop,-1,NULL,0);
		for(i = 0; i < nSize; i++)
		{
			ret = ::DragQueryFile(hDrop,i,pszBuff,MAX_PATH*10);
			if(ret == -1)
				continue;

			strMessage += pszBuff;
			strMessage += _T("\n");
		}
		::DragFinish(hDrop);

		MessageBox(strMessage);

		return	0;
	}

■MainDlg.hのOnInitDialog()内に追加
		//ドラッグアンドドロップを受け入れる
		::DragAcceptFiles(m_hWnd,TRUE);

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

Windows Vistaスタイルのファイルを開く/保存するダイアログを表示する

test80.gif
Windows Vistaでは「ファイルを開く」と「ファイルを保存する」ダイアログが一新された。しかしGetOpenFileName、GetSaveFileNameを利用した場合は従来通りのスタイルで表示されてしまう。

新しいダイアログスタイルを利用したい場合はIFileDialogを利用する。ここではとりあえずこのダイアログを開くための関数を用意した。実際にプログラム内での実装に使う場合は、さらにフィルターなどの設定コードを追加する必要がある。

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


#include "shobjidl.h"

//
//	Windows Vista風のファイル読み込み/保存ダイアログ
//
//初期フォルダやフィルタ設定はしていない簡易版
//
//IFileDialogを利用。Windows Vista以降対応
//
bool	ShowOpenSaveFileDialog(HWND hParentWnd,bool bOpen,CAtlString* pstrFile)
{
	HRESULT			hr;
	IFileDialog*	pIFileDialog;

	if(pstrFile == NULL)
		return	false;

	*pstrFile = _T("");

	pIFileDialog = NULL;
	hr = ::CoCreateInstance(bOpen ? CLSID_FileOpenDialog : CLSID_FileSaveDialog,NULL,CLSCTX_INPROC_SERVER,IID_IFileDialog,(void**)&pIFileDialog);
	if(FAILED(hr) || pIFileDialog == NULL)
		return	false;

	//本当はここで初期フォルダやフィルターなどのオプションを設定する

	hr = pIFileDialog->Show(hParentWnd);

	if(SUCCEEDED(hr))
	{
		WCHAR*		pszName;
		IShellItem*	pIShellItem;

		pszName = NULL;
		pIShellItem = NULL;
		hr = pIFileDialog->GetResult(&pIShellItem);
		if(SUCCEEDED(hr))
			hr = pIShellItem->GetDisplayName(SIGDN_FILESYSPATH,&pszName);
		if(SUCCEEDED(hr))
		{
			*pstrFile = pszName;
			::CoTaskMemFree(pszName);
		}

		if(pIShellItem)
			pIShellItem->Release();
	}

	pIFileDialog->Release();

	return	SUCCEEDED(hr) ? true : false;
}


void	Test2(void)
{
	CAtlString	strFile;

	ShowOpenSaveFileDialog(NULL,true,&strFile);

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


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

	Test2();

	::CoUninitialize();
}

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

2006年12月19日

文字列をUTF8に変換する

文字列をUTF8に変換するにはいくつかの方法がある。今回はATLライブラリに備わるインライン関数「AtlUnicodeToUTF8」を利用した。

AtlUnicodeToUTF8はユニコード文字列をUTF8文字列に変換するためのものだ。そのため変換元の文字列をユニコードビルド/非ユニコードビルドで場合分けし、非ユニコードビルドの場合は一度ユニコードに変換してからUTF8に変換して使う。
ここでは使いやすいようにTCHAR文字列をUTF8文字列に変換する関数を用意した。

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

#include "atlenc.h"

//
//	文字列をUTF8に変換する
//
//UTF8文字列はCAtlStringA(char*)型として返ることに注意!
//
bool	ConvertToUTF8(LPCTSTR pszText,CAtlStringA* pstrUTF8)
{
	int		nLen;
	int		nSrc;
	char*	pszUTF8;

	if(pstrUTF8 == NULL)
		return	false;
	*pstrUTF8 = "";

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

	#ifdef	UNICODE
	{
		nSrc = (int)::_tcslen(pszText);
		nLen = AtlUnicodeToUTF8(pszText,nSrc,NULL,0);
		if(nLen == 0)
			return	false;
		nLen++;

		pszUTF8 = new char[nLen];
		if(pszUTF8 == NULL)
			return	false;

		nLen = AtlUnicodeToUTF8(pszText,nSrc,pszUTF8,nLen);
	}
	#else
	{
		CAtlStringW	ustrText;

		//変換元文字列をcharからユニコードに変換する
		ustrText = pszText;

		nSrc = ustrText.GetLength();
		nLen = AtlUnicodeToUTF8(ustrText,nSrc,NULL,0);
		if(nLen == 0)
			return	false;
		nLen++;

		pszUTF8 = new char[nLen];
		if(pszUTF8 == NULL)
			return	false;

		nLen = AtlUnicodeToUTF8(ustrText,nSrc,pszUTF8,nLen);
	}
	#endif

	pszUTF8[nLen] = NULL;
	*pstrUTF8 = pszUTF8;

	delete	pszUTF8;

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





bool	Test(void)
{
	bool		ret;
	CAtlStringA	strText;

	ret = ConvertToUTF8(_T("abcあいう"),&strText);
	if(ret == false)
		return	false;

	::MessageBox(NULL,(CAtlString)strText,_T(""),MB_OK);

	return	true;
}

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

前の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月です。

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