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

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

2006年12月 記事一覧

日本語版WTL 8.0のアプリケーションウィザード

test36_01.gif
■はじめに
WTLはライセンスがCPLのオープンソースプロジェクトとして公開されている。そのためおそらく勝手に日本語化したものを配布しても問題ないと思い用意しました。ライセンス的に問題があるようでしたらお知らせください。削除します。

test36_02.gif
■メリット
従来の英語版WTLではプロジェクト作成後にリソースエディタでメニューなどの言語を日本語に切り替えて、表示文字列を編集する必要がありました。しかしこの日本語版WTL 7.5ではプロジェクト生成直後から日本語リソースが利用可能です。

test36_03.gif
■日本語化内容:
 ・Windows用アプリケーションウィザード
 ・生成されるソースコード
 ・生成されるソースコードのコメント
など

※サンプルやWindows CE用のアプリケーションウィザードはダウンロード可能なファイルに含まれません。
※incldueファイルやreadme.html、cpl.txtは日本語化されていません。
※短時間で翻訳処理したため変な日本語になっている部分があります。

test36_04.gif
■ダウンロード

日本語版WTL 8.0をダウンロード

test36_05.gif
右の画像はデフォルトで生成したアプリケーション例です。
プロジェクトファイルをダウンロード


2006年12月05日

MD5ハッシュを計算する

CryptCreateHashを利用するとハッシュを計算できる。このAPIは利用できるOSに制限があるものもあるがMD5以外にもSHA-1やMD4、SHA-256、SHA-512など様々なハッシュ計算に対応している。

ここで作成した関数は簡単にするためメモリ上のデータを一括してハッシュ計算処理に回している。小さなデータであればこの関数で十分だ。しかしファイルハッシュを計算したいときなどにはこの関数は利用しない方がいい。ファイルハッシュ計算時はファイルを少しずつ読み出しCryptHashDataを何度も呼び出して計算するのがいい。

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

#include "wincrypt.h"

//
//	MD5ハッシュ計算(128ビット)
//
//対応:Windows 95 OSR2以降
//
bool	GetMD5Hash(const void* pData,DWORD dwLen,BYTE pcbHashData[16])
{
	bool		ret;
	HCRYPTPROV	hCryptProv;
	HCRYPTHASH	hHash;
	BYTE		pbHash[0x7f];
	DWORD		dwHashLen;

	::ZeroMemory(pcbHashData,16);
	if(pData == NULL || dwLen == 0)
		return	false;

	dwHashLen = 16;
	hHash = NULL;
	hCryptProv = NULL;
	ret = false;
	if(::CryptAcquireContext(&hCryptProv,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET))
	{
		if(::CryptCreateHash(hCryptProv,CALG_MD5,0,0,&hHash))
		{
			if(::CryptHashData(hHash,(BYTE*)pData,dwLen,0))
			{
				if(::CryptGetHashParam(hHash,HP_HASHVAL,pbHash,&dwHashLen,0)) 
				{
					::memcpy_s(pcbHashData,dwHashLen,pbHash,dwHashLen);
					ret = true;
				}
			}
		}
	}

	if(hHash)
		::CryptDestroyHash(hHash);
	if(hCryptProv)
		::CryptReleaseContext(hCryptProv,0);

	if(ret == false)
		::ZeroMemory(pcbHashData,dwHashLen);

	return	ret;
}





void	Test(void)
{
	bool		ret;
	int			i;
	BYTE		pcbData[16];
	CAtlString	strTmp;
	CAtlString	strMessage;


	//"abc"という文字のMD5ハッシュを計算
	ret = GetMD5Hash("abc",3,pcbData);

	if(ret == false)
	{
		::MessageBox(NULL,_T("取得に失敗しました"),_T(""),MB_OK);
		return;
	}

	for(i = 0; i < 16; i++)
	{
		strTmp.Format(_T("%x"),pcbData[i]);
		strMessage += strTmp;
	}

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

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

ファイルやIStreamのハッシュを計算する

Windows 95 OSR2以降に対応するCryptHashDataを利用すると簡単にハッシュを求めれる。ここではこのAPIを利用して、メモリ上のデータ、ファイル、IStreamのデータのハッシュを求めるクラスを作成した。簡単に利用できるのはMD2、MD4、MD5、SHA-1ハッシュだが、SHA-256などほかのハッシュもdwFlagsに指定することで計算できる。

「DnpHashEx.h」として保存
#pragma once

#include <wincrypt.h>
#include "objidl.h"


//
//Crypt関連APIを利用してハッシュを計算する
//
//Windows95OSR2以降
//
class	CDnpHashEx
{
public:


	//
	//	MD2ハッシュ計算(128ビット)
	//
	bool	GetMD2Hash(const void* pData,DWORD dwLen,BYTE pcbHashData[16])
	{
		return	GetHash(pData,dwLen,pcbHashData,16,CALG_MD2);
	}


	//
	//	MD4ハッシュ計算(128ビット)
	//
	bool	GetMD4Hash(const void* pData,DWORD dwLen,BYTE pcbHashData[16])
	{
		return	GetHash(pData,dwLen,pcbHashData,16,CALG_MD4);
	}


	//
	//	MD5ハッシュ計算(128ビット)
	//
	bool	GetMD5Hash(const void* pData,DWORD dwLen,BYTE pcbHashData[16])
	{
		return	GetHash(pData,dwLen,pcbHashData,16,CALG_MD5);
	}


	//
	//	SHA-1ハッシュ計算(160ビット)
	//
	bool	GetSHA1Hash(const void* pData,DWORD dwLen,BYTE pcbHashData[20])
	{
		return	GetHash(pData,dwLen,pcbHashData,20,CALG_SHA1);
	}




	//
	//	各種ハッシュ計算
	//
	bool	GetHash(const void* pData,DWORD dwLen,BYTE* pcbHashData,DWORD dwHashLen,DWORD dwFlags)
	{
		bool		ret;
		HCRYPTPROV	hCryptProv;
		HCRYPTHASH	hHash;
		BYTE		pbHash[0x7f];

		::ZeroMemory(pcbHashData,dwHashLen);
		if(pData == NULL || dwLen == 0 || dwHashLen == 0 || dwHashLen > 0x7f)
		{
			ATLASSERT(0);
			return	false;
		}

		hHash = NULL;
		hCryptProv = NULL;
		ret = false;
		if(::CryptAcquireContext(&hCryptProv,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET))
		{
			if(::CryptCreateHash(hCryptProv,dwFlags,0,0,&hHash))
			{
				if(::CryptHashData(hHash,(BYTE*)pData,dwLen,0))
				{
					if(::CryptGetHashParam(hHash,HP_HASHVAL,pbHash,&dwHashLen,0)) 
					{
						::memcpy_s(pcbHashData,dwHashLen,pbHash,dwHashLen);
						ret = true;
					}
				}
			}
		}

		if(hHash)
			::CryptDestroyHash(hHash);
		if(hCryptProv)
			::CryptReleaseContext(hCryptProv,0);

		if(ret == false)
			::ZeroMemory(pcbHashData,dwHashLen);

		return	ret;
	}



	//
	//	MD2ハッシュ計算(128ビット)
	//
	bool	GetMD2FileHash(LPCTSTR pszFile,BYTE pcbHashData[16])
	{
		return	GetFileHash(pszFile,pcbHashData,16,CALG_MD2);
	}


	//
	//	MD4ハッシュ計算(128ビット)
	//
	bool	GetMD4FileHash(LPCTSTR pszFile,BYTE pcbHashData[16])
	{
		return	GetFileHash(pszFile,pcbHashData,16,CALG_MD4);
	}


	//
	//	MD5ハッシュ計算(128ビット)
	//
	bool	GetMD5FileHash(LPCTSTR pszFile,BYTE pcbHashData[16])
	{
		return	GetFileHash(pszFile,pcbHashData,16,CALG_MD5);
	}


	//
	//	SHA-1ハッシュ計算(160ビット)
	//
	bool	GetSHA1FileHash(LPCTSTR pszFile,BYTE pcbHashData[20])
	{
		return	GetFileHash(pszFile,pcbHashData,20,CALG_SHA1);
	}




	//
	//	ファイルハッシュ計算
	//
	bool	GetFileHash(LPCTSTR pszFile,BYTE* pcbHashData,DWORD dwHashLen,DWORD dwFlags)
	{
		bool		ret;
		HCRYPTPROV	hCryptProv;
		HCRYPTHASH	hHash;
		BYTE		pbHash[0x7f];
		HANDLE		hFile;
		ULARGE_INTEGER	lnSize;

		::ZeroMemory(pcbHashData,dwHashLen);
		if(pszFile == 0 || dwHashLen == 0 || dwHashLen > 0x7f)
			return	false;


		hFile = ::CreateFile(pszFile,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
		if(hFile == INVALID_HANDLE_VALUE)
			return	false;


		//ファイルサイズ取得
		lnSize.LowPart = ::GetFileSize(hFile,&lnSize.HighPart);

		hHash = NULL;
		hCryptProv = NULL;
		ret = false;
		if(::CryptAcquireContext(&hCryptProv,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET))
		{
			if(::CryptCreateHash(hCryptProv,dwFlags,0,0,&hHash))
			{
				BOOL			bRet;
				ULARGE_INTEGER	lnPos;
				DWORD	dwRead;
				BYTE	pcbTmp[64000];

				bRet = FALSE;
				lnPos.QuadPart = 0;
				while(1)
				{
					//64KBずつ処理
					bRet = ::ReadFile(hFile,pcbTmp,64000,&dwRead,NULL);
					if(bRet == FALSE)
						break;

					lnPos.QuadPart += dwRead;

					//ハッシュ計算
					bRet = ::CryptHashData(hHash,pcbTmp,dwRead,0);
					if(bRet == FALSE)
						break;

					//処理バイト数とファイルサイズが一致したらbreak
					if(lnPos.QuadPart == lnSize.QuadPart)
						break;
				}

				//ハッシュ取得
				if(bRet && ::CryptGetHashParam(hHash,HP_HASHVAL,pbHash,&dwHashLen,0)) 
				{
					::memcpy_s(pcbHashData,dwHashLen,pbHash,dwHashLen);
					ret = true;
				}
			}
		}

		if(hHash)
			::CryptDestroyHash(hHash);
		if(hCryptProv)
			::CryptReleaseContext(hCryptProv,0);

		::CloseHandle(hFile);

		if(ret == false)
			::ZeroMemory(pcbHashData,dwHashLen);

		return	ret;
	}






	//
	//	MD2ハッシュ計算(128ビット)
	//
	bool	GetMD2IStreamHash(IStream* pIStream,BYTE pcbHashData[16])
	{
		return	GetIStreamHash(pIStream,pcbHashData,16,CALG_MD2);
	}


	//
	//	MD4ハッシュ計算(128ビット)
	//
	bool	GetMD4IStreamHash(IStream* pIStream,BYTE pcbHashData[16])
	{
		return	GetIStreamHash(pIStream,pcbHashData,16,CALG_MD4);
	}


	//
	//	MD5ハッシュ計算(128ビット)
	//
	bool	GetMD5IStreamHash(IStream* pIStream,BYTE pcbHashData[16])
	{
		return	GetIStreamHash(pIStream,pcbHashData,16,CALG_MD5);
	}


	//
	//	SHA-1ハッシュ計算(160ビット)
	//
	bool	GetSHA1IStreamHash(IStream* pIStream,BYTE pcbHashData[20])
	{
		return	GetIStreamHash(pIStream,pcbHashData,20,CALG_SHA1);
	}


	//
	//	IStreamからのハッシュ計算
	//
	bool	GetIStreamHash(IStream* pIStream,BYTE* pcbHashData,DWORD dwHashLen,DWORD dwFlags)
	{
		bool		ret;
		HCRYPTPROV	hCryptProv;
		HCRYPTHASH	hHash;
		BYTE		pbHash[0x7f];
		HRESULT			hr;
		LARGE_INTEGER	lnPos;
		STATSTG			sStatstg;

		::ZeroMemory(pcbHashData,dwHashLen);
		if(pIStream == 0 || dwHashLen == 0 || dwHashLen > 0x7f)
			return	false;

		//ファイル先頭へシーク
		lnPos.QuadPart = 0;
		hr = pIStream->Seek(lnPos,STREAM_SEEK_SET,NULL);
		if(FAILED(hr))
			return	false;

		//ファイルサイズ取得
		::ZeroMemory(&sStatstg,sizeof(STATSTG));
		hr = pIStream->Stat(&sStatstg,STATFLAG_DEFAULT);
		if(FAILED(hr))
			return	false;

		hHash = NULL;
		hCryptProv = NULL;
		ret = false;
		if(::CryptAcquireContext(&hCryptProv,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET))
		{
			if(::CryptCreateHash(hCryptProv,dwFlags,0,0,&hHash))
			{
				BOOL			bRet;
				ULARGE_INTEGER	lnPos;
				ULONG	nRead;
				BYTE	pcbTmp[64000];

				bRet = FALSE;
				lnPos.QuadPart = 0;
				while(1)
				{
					//64KBずつ処理
					hr = pIStream->Read(pcbTmp,64000,&nRead);
					if(FAILED(hr))
						break;

					lnPos.QuadPart += nRead;

					//ハッシュ計算
					bRet = ::CryptHashData(hHash,pcbTmp,(DWORD)nRead,0);
					if(bRet == FALSE)
						break;

					//処理バイト数とファイルサイズが一致したらbreak
					if(lnPos.QuadPart == sStatstg.cbSize.QuadPart)
						break;
				}

				//ハッシュ取得
				if(bRet && ::CryptGetHashParam(hHash,HP_HASHVAL,pbHash,&dwHashLen,0)) 
				{
					::memcpy_s(pcbHashData,dwHashLen,pbHash,dwHashLen);
					ret = true;
				}
			}
		}

		if(hHash)
			::CryptDestroyHash(hHash);
		if(hCryptProv)
			::CryptReleaseContext(hCryptProv,0);

		if(ret == false)
			::ZeroMemory(pcbHashData,dwHashLen);

		return	ret;
	}
};

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

#include "DnpHashEx.h"

//
//	テスト用関数
//
void	Test(void)
{
	bool		ret;
	int			i;
	CAtlString	strTmp;
	CAtlString	strMessage;
	BYTE		pcbData[20];
	CDnpHashEx	cHash;


	//ファイルのSHA-1ハッシュを計算
	ret = cHash.GetSHA1FileHash(_T("c:\\boot.ini"),pcbData);

	if(ret == false)
	{
		::MessageBox(NULL,_T("取得に失敗しました"),_T(""),MB_OK);
		return;
	}

	for(i = 0; i < 20; i++)
	{
		strTmp.Format(_T("%x"),pcbData[i]);
		strMessage += strTmp;
	}

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

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

Windowsプログラミングでのcharの扱い方

char配列の変数を宣言するときに文字列を入れた状態で初期化する。
////////////////////////////////
//初期文字列代入
//
char	pszSrc[] = {"abcdあいう"};
char*型の変数内の文字数を取得する。
////////////////////////////////
//文字数取得
//
size_t	nLen1 = ::strlen(pszSrc);		//変数内の文字列の文字数取得
size_t	nLen2 = ::strlen("あいうえ");	//指定した文字列の文字数取得
変数へのコピーにはstrcpyではなく、より安全なstrcpy_sを利用する。
////////////////////////////////
//文字列代入
//
char	pszText[256];
::strcpy_s(pszText,256 * sizeof(char),"あいうえABCD");	//直接代入
::strcpy_s(pszText,256 * sizeof(char),pszSrc);			//変数から代入
実際のプログラミングではchar*型ではなくCStringもしくはCStringAにしておくほうが楽。
////////////////////////////////
//char*からCStringへの変換
//
CString	strText(pszText);
CStringAというのはプロジェクトの設定に関わらず常にchar型の文字列操作クラスだ。
////////////////////////////////
//char*からCStringA(char型のCString)への変換
//
CStringA	strTextA1(pszText);			//コンストラクタを利用
CStringA	strTextA2 = pszText;		//代入
CStringWは常にWCHAR*型になる。 この操作は文字列のユニコード変換でもある。
////////////////////////////////
//char*からCStringW(WCHAR型のCString)への変換
//
CStringW	strTextW(pszText);
char*型からWCHAR*型への変換。CStringWを利用しないユニコード変換はかなり面倒。
////////////////////////////////
//char*からWCHAR*へ変換
//
char	pszChar[] = {"abcdあいう"};
WCHAR*	pszWchar;
{
	int		nLen;

	//Unicodeに必要な文字数の取得
	nLen = ::MultiByteToWideChar(CP_THREAD_ACP,0,pszChar,-1,NULL,0);
	pszWchar = new WCHAR[nLen];
	if(pszWchar)
	{
		//変換
		nLen = ::MultiByteToWideChar(CP_THREAD_ACP,0,pszChar,(int)::strlen(pszChar)+1,pszWchar,nLen);
		if(nLen == 0)
		{
			delete	pszWchar;
			pszWchar = NULL;
		}
	}
}
//
//ここでWCHAR型のpszWcharを任意の処理で利用
//
delete	pszWchar;		//処理が終わったらdelete

WindowsプログラミングでのWCHARの扱い方

WCHARでは代入などの際に " " ではなく、L" " を利用していることに注意。

変数の宣言時に文字列を指定することもできる。
////////////////////////////////
//初期文字列代入
//
WCHAR	pszSrc[] = {L"abcdあいう"};
文字数取得にstrlen(char型専用)は利用できない。wcslenを利用する。
////////////////////////////////
//文字数取得
//
size_t	nLen1 = ::wcslen(pszSrc);		//変数内の文字列の文字数取得
size_t	nLen2 = ::wcslen(L"あいうえ");	//指定した文字列の文字数取得
文字列の代入にstrlenは利用できない。wcscpyをより安全にしたwcscpy_sを利用する。
////////////////////////////////
//文字列代入
//
WCHAR	pszText[256];
::wcscpy_s(pszText,256 * sizeof(WCHAR),L"あいうえABCD");	//直接代入
::wcscpy_s(pszText,256 * sizeof(WCHAR),pszSrc);				//変数から代入
この変換時、プロジェクトの設定が非ユニコード(MBCSなど)になっているときは正常に変換できない可能性があるので注意。例えばWCHAR*型にハングル文字と日本語などが混在している場合が挙げられる。
////////////////////////////////
//WCHAR*からCStringへの変換
//
CString	strText(pszText);
この場合も変換ができないことがあるので注意。
////////////////////////////////
//WCHAR*からCStringA(char型のCString)への変換
//
CStringA	strTextA(pszText);			//コンストラクタを利用
常にWCHAR*型のCStringWへの変換時はユニコード同士の変換なので文字列が正常にコピーできないことはない。
////////////////////////////////
//WCHAR*からCStringW(WCHAR型のCString)への変換
//
CStringW	strTextW1(pszText);			//コンストラクタを利用
CStringW	strTextW2 = pszText;		//代入
CStringAへの変換と内容は同じだが実装量が増える。この場合も変換できない可能性があるので注意が必要だ。
////////////////////////////////
//WCHAR*からchar*へ変換
//
WCHAR	pszWchar[] = {L"abcdあいう"};
char*	pszChar;
{
	int		nLen;

	//charに必要な文字数の取得
	nLen = ::WideCharToMultiByte(CP_THREAD_ACP,0,pszWchar,-1,NULL,0,NULL,NULL);
	pszChar = new char[nLen];
	if(pszChar)
	{
		//変換
		nLen = ::WideCharToMultiByte(CP_THREAD_ACP,0,pszWchar,(int)::wcslen(pszWchar)+1,pszChar,nLen,NULL,NULL);
		if(nLen == 0)
		{
			delete	pszChar;
			pszChar = NULL;
		}
	}
}
//
//ここでchar*型のpszCharを任意の処理で利用
//
delete	pszChar;		//処理が終わったらdelete

WindowsプログラミングでのTCHARの扱い方

TCHARでは代入などの際に " " ではなく、_T(" ") を利用していることに注意。

変数の宣言時に文字列を指定することもできる。
////////////////////////////////
//初期文字列代入
//
TCHAR	pszSrc[] = {_T("abcdあいう")};
文字数の取得にstrlenは利用できない。_tcslenを利用する。
////////////////////////////////
//文字数取得
//
size_t	nLen1 = ::_tcslen(pszSrc);			//変数内の文字列の文字数取得
size_t	nLen2 = ::_tcslen(_T("あいうえ"));	//指定した文字列の文字数取得
文字列のコピーにstrcpyは利用できない。_tcscpyをより安全にした_tcscpy_sを利用する。
////////////////////////////////
//文字列代入
//
TCHAR	pszText[256];
::_tcscpy_s(pszText,256 * sizeof(TCHAR),_T("あいうえABCD"));	//直接代入
::_tcscpy_s(pszText,256 * sizeof(TCHAR),pszSrc);				//変数から代入
CStringはTCHARを扱うための文字列操作クラスだ。
////////////////////////////////
//TCHAR*からCStringへの変換
//
CString	strText1(pszText);
CString	strText2 = pszText;
ユニコードビルド時はTCHAR=WCHARとなる。そのときは文字列の変換に失敗する可能性がある。
////////////////////////////////
//TCHAR*からCStringA(char型のCString)への変換
//
CStringA	strTextA(pszText);			//コンストラクタを利用
この場合は文字列の変換に失敗することはない。
////////////////////////////////
//TCHAR*からCStringW(WCHAR型のCString)への変換
//
CStringW	strTextW(pszText);			//コンストラクタを利用
この場合もWCHARからcharへの変換が起きる可能性があるので注意する。
////////////////////////////////
//TCHAR*からchar*へ変換
//
//TCHARはプロジェクト設定によってはWCHAR、charのどちらかになるので
//ifdefで分岐処理する
{
	TCHAR	pszTchar[] = {_T("abcdあいう")};
	char*	pszChar;
#ifdef UNICODE
	{
		int		nLen;

		//charに必要な文字数の取得
		nLen = ::WideCharToMultiByte(CP_THREAD_ACP,0,pszTchar,-1,NULL,0,NULL,NULL);
		pszChar = new char[nLen];
		if(pszChar)
		{
			//変換
			nLen = ::WideCharToMultiByte(CP_THREAD_ACP,0,pszTchar,(int)::wcslen(pszTchar)+1,pszChar,nLen,NULL,NULL);
			if(nLen == 0)
			{
				delete	pszChar;
				pszChar = NULL;
			}
		}
	}
#else
	{
		size_t	nLen;

		nLen = ::_tcslen(pszTchar) + 1;
		pszChar = new char[nLen];
		if(pszChar)
			::strcpy_s(pszChar,nLen * sizeof(char),pszTchar);
	}
#endif
	//
	//ここでchar*型のpszCharを任意の処理で利用
	//
	delete	pszChar;		//処理が終わったらdelete
}
この場合は変換に失敗することはない。
////////////////////////////////
//TCHAR*からWCHAR*へ変換
//
//TCHARはプロジェクト設定によってはWCHAR、charのどちらかになるので
//ifdefで分岐処理する
{
	TCHAR	pszTchar[] = {_T("abcdあいう")};
	WCHAR*	pszWchar;
#ifdef UNICODE
	{
		size_t	nLen;

		nLen = ::_tcslen(pszTchar) + 1;
		pszWchar = new WCHAR[nLen];
		if(pszWchar)
			::wcscpy_s(pszWchar,nLen * sizeof(WCHAR),pszTchar);
	}
#else
	{
		int		nLen;

		//Unicodeに必要な文字数の取得
		nLen = ::MultiByteToWideChar(CP_THREAD_ACP,0,pszTchar,-1,NULL,0);
		pszWchar = new WCHAR[nLen];
		if(pszWchar)
		{
			//変換
			nLen = ::MultiByteToWideChar(CP_THREAD_ACP,0,pszTchar,(int)::strlen(pszTchar)+1,pszWchar,nLen);
			if(nLen == 0)
			{
				delete	pszWchar;
				pszWchar = NULL;
			}
		}
	}
#endif
	//
	//ここでWCHAR*型のpszWcharを任意の処理で利用
	//
	delete	pszWchar;		//処理が終わったらdelete
}

2006年12月06日

IStreamを簡単に作る

APIのCreateStreamOnHGlobalを利用すると簡単にIStreamを取得できる。COMインターフェースの中にはIStreamでデータを受け取るものがあるのでそういう場合に重宝する。

#include "objidl.h"

//
//	グローバルメモリ上に新しくIStreamを作る
//
bool	CreateOnHGlobal(IStream** ppIStream)
{
	HRESULT	hr;

	if(ppIStream == NULL)
		return	false;
	hr = ::CreateStreamOnHGlobal(NULL,TRUE,ppIStream);
	if(SUCCEEDED(hr) && *ppIStream)
		return	true;

	*ppIStream = NULL;
	return	false;
}



//
//	テスト用関数
//
void	Test(void)
{
	::CoInitialize(NULL);


	bool		ret;
	HRESULT		hr;
	IStream*	pIStream;

	//メモリ上にIStreamを確保
	pIStream = NULL;
	ret = CreateOnHGlobal(&pIStream);

	//IStreamへ10byteデータ書き込み
	hr = E_FAIL;
	if(ret)
		hr = pIStream->Write("1234567890",10,NULL);
	if(FAILED(hr))
		ret = false;

	if(ret)
		::MessageBox(NULL,_T("成功しました"),_T(""),MB_OK);
	else
		::MessageBox(NULL,_T("失敗しました"),_T(""),MB_OK);

	if(pIStream)
		pIStream->Release();

	::CoUninitialize();
}

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

WTLをインストールする

MFCは多機能で使い勝手のいいフレームワークだ。しかしちょっと手の込んだことをしようと思ったり、ほかに配布するためのEXEを生成しようというときには途端に使い勝手が悪くなる。その反面、WTLは機能はシンプルだがMFCのようにDLLに依存することもなく、小回りのきくフレームワークになっている。

私は昔は「MFCがないとWindowsプログラミングはできない!」と思っていた。しかし最近ではMFCを使うことはまずない。ほぼ全てをWTLで作成している。使えば使うほどMFCにはない良さが分かる。

wtl01.gif
WTLはVisual Studio 2005に標準では備わっていないのでダウンロードして取得する。ちなみにここでは
日本語版WTL8.0を利用することにする。

WTLをダウンロードしたらVisual Studio 2005がインストールされているフォルダをエクスプローラで開く。


wtl02.gif
そして適当な名前でフォルダを作ってそこにWTLを解凍する。ここでは「WTL」というフォルダ名にした。

wtl03.gif
解凍したWTLのAppWizフォルダにある「setup80.js」というスクリプトを実行する。これは通常のVisual Studio 2005用のもので、
Visual Studio 2005 Express Editionの場合はsetup80x.js、
Visual Studio .NET 2003はsetup71.js、
Visual Studio .NET 2002はsetup70.jsを利用する。

wtl04.gif

wtl05.gif
この状態ではまだWTLのインストールは終わっていない。次にVisual Studio 2005を起動して、「ツール」メニューから「オプション」を開く。

wtl06.gif
そしてインクルードフォルダとしてWTLを解凍したフォルダの下にあるincludeフォルダを指定する。
以上の操作でVisual Studio 2005上からWTLが利用可能になる。

一連の作業から分かるようにWTLに含まれるsetup80.jsは必要なファイルをコピーしてインストールするわけではない。そのため解凍したファイル群は削除してはならない。


WTLで文字を出力するだけのアプリケーションを作る

wtl_a_01.gif
WTLアプリケーションウィザードを利用すると簡単にWindowsアプリケーションを作成できる。

Visual Studio 2005を開き、「ファイル」メニューの「新規作成」から「プロジェクト」を選択する。そして開いたウインドウの左側から「WTL」を選び、その中の「ATL/WTL アプリケーション ウィザード」を利用する。

wtl_a_02.gif
アプリケーションウイザードでは様々なオプションを設定できるが、ここではデフォルトの設定のまま「完了」ボタンを押す。これで基本的なソースコードが自動的に生成される。

wtl_a_03.gif
プロジェクトを作成したら「ビルド」メニューから「ソリューションのビルド」を選択して実行ファイルを作る。

wtl_a_04.gif
ビルドした実行ファイルを起動するために「デバッグ」メニューから「デバッグ開始」を選択する。

wtl_a_05.gif
これが実行画面。デフォルトの状態でメニューやツールバーを備えたウインドウとなっている。


wtl_a_06.gif
せっかくなので次に画面に文字を出力してみる。画面に文字や線などを描きたい場合は左側の「ソリューションエクスプローラー」にある「○○View.h」(○○はプロジェクト名)をダブルクリックしてビューに関するソースコードを開く。
ここで「//TODO: 描画コードの追加」という部分に文字の出力命令を追加すればいい。

wtl_a_07.gif
文字を表示する命令を追加する。ここではTextOut命令を利用した。

dc.TestOut(10,10,_T("文字を出力する"));


wtl_a_08.gif
ソースコードを変更したら「ビルド」メニューから「ソリューションのビルド」を選択して再びビルドする。

wtl_a_09.gif
そして「デバッグ」メニューの「デバッグ開始」を選択して実行ファイルを起動する。

wtl_a_10.gif
これで作成したアプリケーションのウインドウに文字が出力された。

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

バイト配列をひっくり返す(intel配列とモトローラ配列)

ごくたまにだが、Mac系とIntel系でのメモリ上の格納方式の違いを意識しなければいけないことがある。例えばデジカメ画像に含まれるExifデータやVirtual PCのVirtual HDDファイルを読むときなどが挙げられる。
そのようなときに使うと便利なのがこのようなマクロ。
0x12345678という配列であれば0x78563412のようにひっくり返してくれる。もちろんDWORDだけでなく、int、shortやLONGLONGなどほかの型でも使える。

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


#define	SWAP_BYTE_ALIGNMENT(data)	\
{									\
	int		i;						\
	int		nSize;					\
	int		nLoop;					\
	BYTE*	pData;					\
	BYTE	cbTmp;					\
									\
	pData = (BYTE*)&data;			\
	nSize = sizeof(data);			\
	nLoop = nSize / 2;				\
	for(i = 0; i < nLoop; i++)		\
	{								\
		cbTmp = *(pData + i);		\
		*(pData + i) = *(pData + nSize - i - 1);	\
		*(pData + nSize - i - 1) = cbTmp;			\
	}								\
}



void	Test(void)
{
	CAtlString	strMessage;
	DWORD		dwData;

	dwData = 0x12345678;
	SWAP_BYTE_ALIGNMENT(dwData)

	strMessage.Format(_T("%08x"),dwData);

	::MessageBox(NULL,strMessage,_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月です。

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