使う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の場合は必ず確認しよう。


カテゴリー「コラム」 のエントリー