« 2007年04月 | メイン | 2009年04月 »

前の10件 1  2

2009年03月 記事一覧

IEコントロールのスクリプトエラー表示を消す

IEコントロールでJavascriptなどを含むページを表示しているときにスクリプトエラーダイアログが表示されないようにするにはIOleCommandTarget::Exec()でOLECMDID_SHOWSCRIPTERRORがIEに処理されないようにすればいい。

IOleCommandTarget::Exec()を自前で処理するには、HTMLページの読み込みが終わった時にICustomDoc::SetUIHandler()を使い、IEコントロールに対してIDocHostUIHandlerを設定する。


1.Visual Studio 2008の「ファイル」メニューにある「新規」メニューから「プロジェクト」を選択する。

2.「新しいプロジェクト」の画面で「ATL/WTLアプリケーションウイザード」を選択する。ここではプロジェクト名を「HideScriptError」とした。

3.アプリケーションウイザードが開いたら、「ユーザーインターフェース機能」のタブにある「ビューウインドウの形式」で「HTML」ページを選択して「完了」ボタンを押す。

4.(以上の操作でアプリケーションウイザードにより自動的にひな形となるソースコードが自動生成される)

5.生成したソースコードのViewクラスを開き、以下のソースコードを追加する。

#pragma once

//■以下の宣言を3行追加
#define SINKID_COMTESTEVENTS 0
#include "Exdispid.h"
#include "DnpDocHostUIHandlerImpl.h"


class CHideScriptErrorView : public CWindowImpl<CHideScriptErrorView, CAxWindow>
	,public CComObjectRootEx<CComSingleThreadModel>		//■追加
	,public IDnpDocHostUIHandlerImpl	//■追加
	,public	IDispatchImpl<IDispatch>	//■追加
	,public IOleCommandTarget	//■追加
	,public IDispEventImpl<SINKID_COMTESTEVENTS, CHideScriptErrorView, &DIID_DWebBrowserEvents2>	//■追加
{
	//■メンバー変数を追加
	CComPtr<IWebBrowser2>	_pIWebBrowser2;

public:
	DECLARE_WND_SUPERCLASS(NULL, CAxWindow::GetWndClassName())

	BOOL PreTranslateMessage(MSG* pMsg)
	{
		if((pMsg->message < WM_KEYFIRST || pMsg->message > WM_KEYLAST) &&
		   (pMsg->message < WM_MOUSEFIRST || pMsg->message > WM_MOUSELAST))
			return FALSE;

		// このメッセージを翻訳する機会をHTML ページに与える
		return (BOOL)SendMessage(WM_FORWARDMSG, 0, (LPARAM)pMsg);
	}


	//■以下3行を追加
	BEGIN_SINK_MAP(CHideScriptErrorView)
		SINK_ENTRY_EX(SINKID_COMTESTEVENTS, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, OnDocumentComplete)
	END_SINK_MAP()

	//■以下5行を追加
	BEGIN_COM_MAP(CHideScriptErrorView)
		COM_INTERFACE_ENTRY(IDispatch)
		COM_INTERFACE_ENTRY(IDocHostUIHandler)
		COM_INTERFACE_ENTRY(IOleCommandTarget)
	END_COM_MAP()

	BEGIN_MSG_MAP(CHideScriptErrorView)
		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)	//■1行追加
	END_MSG_MAP()


	//■OnDocumentCompleteを追加
	HRESULT	_stdcall OnDocumentComplete(IDispatch* pDisp, VARIANT* URL)
	{
		//ドキュメントを読み込み終わった時点でUIHandlerを変更する

		CComPtr<IDispatch>	pIDispatch;
		CComPtr<ICustomDoc>	pICustomDoc;

		_pIWebBrowser2->get_Document(&pIDispatch);
		if(pIDispatch)
			pIDispatch->QueryInterface(IID_ICustomDoc,(void **)&pICustomDoc);
		if(pICustomDoc)
			pICustomDoc->SetUIHandler(static_cast<IDocHostUIHandler*>(this));

		return	S_OK;
	}



	//■IOleCommandTargetの関数追加
    STDMETHODIMP QueryStatus( const GUID* pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT* pCmdText ) 
	{
		return E_NOTIMPL; 
    }


	//■IOleCommandTargetの関数追加
    STDMETHODIMP Exec( const GUID* pguidCmdGroup, DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG* pvaIn, VARIANTARG* pvaOut)
    {
		//コマンドがスクリプトエラーを示すものなら、エラー表示を無効にする
		if(nCmdID == OLECMDID_SHOWSCRIPTERROR)
		{
			(*pvaOut).vt		= VT_BOOL;
			(*pvaOut).boolVal	= VARIANT_TRUE;
			return S_OK;
		}

		return E_NOTIMPL;
    }


	//■生成時処理用に関数を追加
	HWND Create(HWND hWndParent, _U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
			DWORD dwStyle = 0, DWORD dwExStyle = 0,
			_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
	{
		HWND	hWnd;

		hWnd = __super::Create(hWndParent,rect,szWindowName,dwStyle,dwExStyle,MenuOrID,lpCreateParam);
		if(hWnd == NULL)
			return	NULL;

		_pIWebBrowser2 = NULL;
		QueryControl(&_pIWebBrowser2);
		if(_pIWebBrowser2 == NULL)
		{
			ATLASSERT(0);
			return	hWnd;
		}

		//IEとの接続
		Advise(_pIWebBrowser2);

		return	hWnd;
	}


	//■IEからの切断処理を追加
	LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
	{
		bHandled = FALSE;

		if(_pIWebBrowser2)
			Unadvise(_pIWebBrowser2);
		_pIWebBrowser2 = NULL;

		return	0;
	}
};
6.「MainFrm.h」を開き、
	CHideScriptErrorView		m_view;
という部分を
	CComObject<CHideScriptErrorView> m_view;
に変更する。


7.最後に「DnpDocHostUIHandlerImpl.h」というファイルを作成し、その内容を以下のようにする。

#pragma	once


///
///\brief
///	IDocHostUIHandler実装補助用クラス
///
///実処理はないがS_FALSEやS_OKを返す仮想関数もある
///
class	IDnpDocHostUIHandlerImpl :
	public IDocHostUIHandler
{
	virtual HRESULT STDMETHODCALLTYPE ShowContextMenu( 
		/* [in] */ DWORD dwID,
		/* [in] */ POINT *ppt,
		/* [in] */ IUnknown *pcmdtReserved,
		/* [in] */ IDispatch *pdispReserved)
	{
		return	E_NOTIMPL;
	}

	virtual HRESULT STDMETHODCALLTYPE GetHostInfo( 
		/* [out][in] */ DOCHOSTUIINFO *pInfo)
	{
		return	S_FALSE;
	}

	virtual HRESULT STDMETHODCALLTYPE ShowUI( 
		/* [in] */ DWORD dwID,
		/* [in] */ IOleInPlaceActiveObject *pActiveObject,
		/* [in] */ IOleCommandTarget *pCommandTarget,
		/* [in] */ IOleInPlaceFrame *pFrame,
		/* [in] */ IOleInPlaceUIWindow *pDoc)
	{
		return	S_FALSE;
	}

	virtual HRESULT STDMETHODCALLTYPE HideUI( void)
	{
		return	S_FALSE;
	}

	virtual HRESULT STDMETHODCALLTYPE UpdateUI( void)
	{
		return	S_FALSE;
	}

	virtual HRESULT STDMETHODCALLTYPE EnableModeless( 
		/* [in] */ BOOL fEnable)
	{
		return	S_FALSE;
	}

	virtual HRESULT STDMETHODCALLTYPE OnDocWindowActivate( 
		/* [in] */ BOOL fActivate)
	{
		return	S_FALSE;
	}

	virtual HRESULT STDMETHODCALLTYPE OnFrameWindowActivate( 
		/* [in] */ BOOL fActivate)
	{
		return	S_FALSE;
	}

	virtual HRESULT STDMETHODCALLTYPE ResizeBorder( 
		/* [in] */ LPCRECT prcBorder,
		/* [in] */ IOleInPlaceUIWindow *pUIWindow,
		/* [in] */ BOOL fRameWindow)
	{
		return	S_FALSE;
	}

	virtual HRESULT STDMETHODCALLTYPE TranslateAccelerator( 
		/* [in] */ LPMSG lpMsg,
		/* [in] */ const GUID *pguidCmdGroup,
		/* [in] */ DWORD nCmdID)
	{
		return	E_NOTIMPL;
	}

	virtual HRESULT STDMETHODCALLTYPE GetOptionKeyPath( 
		/* [out] */ 
		__out  LPOLESTR *pchKey,
		/* [in] */ DWORD dw)
	{
		return	S_FALSE;
	}

	virtual HRESULT STDMETHODCALLTYPE GetDropTarget( 
		/* [in] */ IDropTarget *pDropTarget,
		/* [out] */ IDropTarget **ppDropTarget)
	{
		return	S_FALSE;
	}

	virtual HRESULT STDMETHODCALLTYPE GetExternal( 
		/* [out] */ IDispatch **ppDispatch)
	{
		return	E_NOTIMPL;
	}

	virtual HRESULT STDMETHODCALLTYPE TranslateUrl( 
		/* [in] */ DWORD dwTranslate,
		/* [in] */ 
		__in __nullterminated  OLECHAR *pchURLIn,
		/* [out] */ 
		__out  OLECHAR **ppchURLOut)
	{
		if(ppchURLOut)
			*ppchURLOut = NULL;
		return	S_FALSE;
	}

	virtual HRESULT STDMETHODCALLTYPE FilterDataObject( 
		/* [in] */ IDataObject *pDO,
		/* [out] */ IDataObject **ppDORet)
	{
		return	S_FALSE;
	}
};

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

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

wtl80jp_01.gif
■はじめに

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


wtl80jp_02.gif
■メリット

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

また、タブ型ビューといった最新(?)のUIを簡単に利用できます。


wtl80jp_03.gif
■日本語化内容:

 ・Windows用アプリケーションウィザード

 ・生成されるソースコード

 ・生成されるソースコードのコメント



※サンプルやWindows CE用のアプリケーションウィザードはダウンロード可能なファイルに含まれません。

※incldueファイルやreadme.html、cpl.txtは日本語化されていません。


wtl80jp_04.gif
■ダウンロード





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



(2009年3月22日現在最新版のWTLを元にしています)


2009年03月23日

WTLのタブ型ビューでタブを下側に配置する

tabview01.gif
最新のWTLではタブ型ビューがサポートされ、(MFCや.NET Frameworkなどにはまだまだ追いつけないものの)少しだけUIの幅が広がった。

新しいタブ型ビューではタブのドラッグにも対応するなど、使える機能を備えたものだ。しかし残念ながらタブを下側に配置する機能は用意されていなかった。ここではWTLのCTabView派生クラスを作ることでタブの下側表示に対応させた。

利用するときは、それまでCTabView型だった変数宣言をCDnpTabViewに変更して、タブを下に配置したいときにCDnpTabView::SwitchTabType(CDnpTabView::TAB_DOWN);を呼ぶ。逆にCDnpTabView::SwitchTabType(CDnpTabView::TAB_UP);を呼べば通常通りの上側表示に戻る。

サンプルプロジェクトでは「バージョン表示」用のメニューやボタンを操作したときにタブ位置が上側と下側に交互に変わるようにした。

(CTabViewImpl<>派生で作ればstatic_castを利用してもっとスマートに実装できたことに後から気付き後悔中。気が向いたときに作り直します)

依存環境:ATL/WTL
#pragma once

#include "atlctrlx.h"

///
///\brief
///	WTLのタブビューの下側タブ対応版
///
///\attention
///WTL 8.0での動作を前提として作られています。今後のWTLバージョンアップによっては
///使えなくなる可能性があります。
///
class	CDnpTabView	: public CTabView
{
public:


	///
	///\brief
	///	タブ配置位置指定用列挙子
	///
	enum	TAB_POSITION
	{
		TAB_UP,			//!< タブを上側に配置する
		TAB_DOWN		//!< タブを下側に配置する
	};

private:

	TAB_POSITION	_enumUpTabOrDown;		//!< 現在設定されているタブ配置位置

public:
	CDnpTabView()
	{
		_enumUpTabOrDown = TAB_UP;
	}

	BEGIN_MSG_MAP(CDnpTabView)
		MESSAGE_HANDLER(WM_CREATE, OnCreate)
		MESSAGE_HANDLER(WM_SIZE, OnSize)
		NOTIFY_HANDLER(m_nTabID, TCN_SELCHANGE, OnTabChanged)
		CHAIN_MSG_MAP(CTabView)
	ALT_MSG_MAP(1)	//タブコントロール
		MESSAGE_HANDLER(WM_WINDOWPOSCHANGING, OnWindowPosChanging)
		CHAIN_MSG_MAP_ALT(CTabView,1)
	END_MSG_MAP()




	///
	///\brief
	///	タブ配置位置の動的変更
	///
	///\param	enumType
	///	新しいタブの配置位置\n
	///	CDnpTabView::TAB_UP と CDnpTabView::TAB_DOWN のみサポート
	///
	void	SwitchTabType(TAB_POSITION enumType)
	{
		if(_enumUpTabOrDown == enumType)
			return;

		switch(_enumUpTabOrDown)
		{
		case	TAB_UP:
			m_tab.ModifyStyle(TCS_BOTTOM,0);
			break;

		case	TAB_DOWN:
			m_tab.ModifyStyle(0,TCS_BOTTOM);
			break;

		default:
			ATLASSERT(0);		//対応していない配置位置指定された
			return;
		}

		_enumUpTabOrDown = enumType;

		UpdateLayout();		//このクラスのUpdateLayout()を実行
	}



	///
	///\brief
	///	生成時処理
	///
	///\attention
	///	WTL 8.0の動作を前提としています。
	///
	LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
	{
		if(_enumUpTabOrDown == TAB_UP)
		{
			//デフォルトの動作に任せる
			bHandled = FALSE;
			return	0;
		}

		//以下のコードはWTL 8.0の CTabViewImpl::OnCreate() と同じにしている
		{
			CreateTabControl();
		}

		if(_enumUpTabOrDown == TAB_DOWN)
			m_tab.ModifyStyle(0,TCS_BOTTOM);		//タブを下タイプに変更。ComCtl32.dll Ver6では無視される

		return	0;
	}




	///
	///\brief
	///	タブ配置位置の強制変更
	///
	///	CTabViewImpl::UpdateLayout() が仮想関数でなく、直接いじることができないため、
	///	CTabViewImpl::UpdateLayout() 内で指定されたタブ配置位置を強制変更する
	///
	LRESULT OnWindowPosChanging(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
	{
		bHandled = FALSE;

		//タブが上側なら処理の必要なし
		if(_enumUpTabOrDown == TAB_UP)
			return	0;

		WINDOWPOS*	pPos = (WINDOWPOS*)lParam;
		if(pPos == NULL)
			return	0;

		if(!(pPos->flags & SWP_NOMOVE))
		{
			if(_enumUpTabOrDown == TAB_DOWN && pPos->y == 0)
			{
				//タブの位置を下側に変更
				RECT	rect;

				GetClientRect(&rect);
				pPos->y = rect.bottom - m_cyTabHeight;
			}
		}

		return	0;
	}



	///
	///\brief
	///	タブ選択時処理
	///
	///\attention
	///	WTL 8.0の動作を前提としています。
	///
	LRESULT OnTabChanged(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& bHandled)
	{
		if(_enumUpTabOrDown == TAB_UP)
		{
			//デフォルトの処理に任せる
			bHandled = FALSE;
			return	0;
		}

		//以下のコードはWTL 8.0の CTabViewImpl::OnTabChanged() と同じにしている
		{
			SetActivePage(m_tab.GetCurSel());
			OnPageActivated(m_nActivePage);
			UpdateLayout();				//このクラスのUpdateLayout()が実行される
		}

		return 0;
	}



	///
	///\brief
	///	親ウインドウサイズ変更時処理
	///
	///\attention
	///	WTL 8.0の動作を前提としています。
	///
	LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
	{
		if(_enumUpTabOrDown == TAB_UP)
		{
			//デフォルトの処理に任せる
			bHandled = FALSE;
			return	0;
		}

		//以下のコードはWTL 8.0の CTabViewImpl::OnSize() と同じにしている
		{
			UpdateLayout();		//このクラスのUpdateLayout()が実行される
		}
		return 0;
	}



	///
	///\brief
	///	ページ追加処理
	///
	///\attention
	///	WTL 8.0の動作を前提としています。
	///
	bool AddPage(HWND hWndView, LPCTSTR lpstrTitle, int nImage = -1, LPVOID pData = NULL)
	{
		//以下のコードはWTL 8.0の CTabViewImpl::OnSize() と同じにしている
		{
			//このクラスのInsertPageが実行される
			return InsertPage(GetPageCount(), hWndView, lpstrTitle, nImage, pData);
		}
	}


	///
	///\brief
	///	ページ挿入処理
	///
	bool InsertPage(int nPage, HWND hWndView, LPCTSTR lpstrTitle, int nImage = -1, LPVOID pData = NULL)
	{
		bool	ret;

		ret = __super::InsertPage(nPage,hWndView,lpstrTitle,nImage,pData);

		UpdateLayout();		//このクラスのUpdateLayout()を実行する

		return	ret;
	}

 
	///
	///\brief
	///	レイアウト設定処理
	///
	void UpdateLayout()
	{
		RECT rect;
		GetClientRect(&rect);

		if(_enumUpTabOrDown == TAB_UP)
		{
			//タブの位置をウインドウ上側に変更
			if(m_tab.IsWindow() && ((m_tab.GetStyle() & WS_VISIBLE) != 0))
				m_tab.SetWindowPos(NULL, 0, 0, rect.right - rect.left, m_cyTabHeight, SWP_NOZORDER);

			//ビューウインドウの位置を下側に変更
			if(m_nActivePage != -1)
				::SetWindowPos(GetPageHWND(m_nActivePage), NULL, 0, m_cyTabHeight, rect.right - rect.left, rect.bottom - rect.top - m_cyTabHeight, SWP_NOZORDER);
		}
		else if(_enumUpTabOrDown == TAB_DOWN)
		{
			//タブの位置をウインドウ下側に変更
			if(m_tab.IsWindow() && ((m_tab.GetStyle() & WS_VISIBLE) != 0))
				m_tab.SetWindowPos(NULL, 0, rect.bottom - m_cyTabHeight, rect.right - rect.left, m_cyTabHeight, SWP_NOZORDER);

			//ビューウインドウの位置を上側に変更
			if(m_nActivePage != -1)
				::SetWindowPos(GetPageHWND(m_nActivePage), NULL, 0, 0, rect.right - rect.left, rect.bottom - rect.top - m_cyTabHeight, SWP_NOZORDER);
		}
		else
		{
			ATLASSERT(0);	//対応していないタブ配置位置
		}
	}
};

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

2009年03月24日

WTLの警告「warning C4996...use _CRT_SECURE_NO_WARNINGS」を解決する

WTLを最新のものに入れ替えたら、それまで正常にビルドできていたソースコードで以下のような警告がでるようになった。

2>d:\_____sourcecode\_wtl\include\atlapp.h(851) : warning C4996: '_vswprintf': This function or variable may be unsafe. Consider using vswprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
2>        c:\program files\microsoft visual studio 9.0\vc\include\wchar.h(773) : '_vswprintf' の宣言を確認してください。
「atlapp.h」内の警告が出た個所を見てみると以下のようになっていた。
	inline int vsprintf_x(LPTSTR lpstrBuff, size_t cchBuff, LPCTSTR lpstrFormat, va_list args)
	{
#if _SECURE_ATL && !defined(_ATL_MIN_CRT) && !defined(_WIN32_WCE)
		return _vstprintf_s(lpstrBuff, cchBuff, lpstrFormat, args);
#else
		cchBuff;   // Avoid unused argument warning
		return _vstprintf(lpstrBuff, lpstrFormat, args);
#endif
	}

#ifによる分岐で、_SECURE_ATLが定義されていて、かつ、_ATL_MIN_CRTと_WIN32_WCEが未定義だと「_vstprintf_s」が、そうでなければ警告の出る「_vstprintf」が使われるようだ。

ここで「_WIN32_WCE」はWindows CE用の定義。通常のPC向けソースコードでは未定義がデフォルトなので問題にはならないだろう。

「_ATL_MIN_CRT」はATLの動的リンク時にランタイムライブラリの利用を極力減らすための定義。昔のプロジェクトではデフォルトで定義されていることがあったり、ビルドした実行ファイルのサイズが小さくなるというメリットがあるため敢えて定義する人もいる。そのため_ATL_MIN_CRTを利用する(利用したい)プロジェクトでは警告を解決することができない(警告を非表示にすることはできる)。

「_SECURE_ATL」は正体がよく分からないのでVisual Studioのincludeフォルダ内を検索してみた。
  D:\_____sourcecode\_WTL\include\atlapp.h(694):#if _SECURE_ATL
  D:\_____sourcecode\_WTL\include\atlapp.h(706):#if _SECURE_ATL
  D:\_____sourcecode\_WTL\include\atlapp.h(727):#if _SECURE_ATL
  D:\_____sourcecode\_WTL\include\atlapp.h(754):#if _SECURE_ATL
  D:\_____sourcecode\_WTL\include\atlapp.h(790):#if _SECURE_ATL
  D:\_____sourcecode\_WTL\include\atlapp.h(802):#if _SECURE_ATL
  D:\_____sourcecode\_WTL\include\atlapp.h(823):#if _SECURE_ATL
  D:\_____sourcecode\_WTL\include\atlapp.h(835):#if _SECURE_ATL
  D:\_____sourcecode\_WTL\include\atlapp.h(847):#if _SECURE_ATL && !defined(_ATL_MIN_CRT) && !defined(_WIN32_WCE)
  D:\_____sourcecode\_WTL\include\atlapp.h(857):#if _SECURE_ATL && !defined(_ATL_MIN_CRT) && !defined(_WIN32_WCE)
どうやらWTL内でのみ使われている定義のようだ。今回の警告が出た箇所と同じような分岐処理で「_s」タイプの関数とそうでない関数の使い分けをしているのだろう。バージョン関連の定義のように数値による分岐はなく、定義が有効かどうかだけを見ている。

以上のことから今回の警告を解決するには、_ATL_MIN_CRTの利用を諦めて、
#define	_SECURE_ATL	1
という定義をWTL関連がincludeされる前、「stdafx.h」の先頭に置く。 これで「_vstprintf_s」というより安全(とされている)関数が利用され、警告が表示されなくなる。

2009年03月31日

Internet Explorer 8をインストールするとVisual Studioが正常に動かない!

ie8_vs2008.gif







以下の問題は解決しました。
IE8環境でVisual Studioがきちんと動くようにする





IE8をVisual Studio 2008の入っている開発環境にインストールすると、いくつかのウイザードで画像のようなエラーが出てしまう。

セキュリティ関連でIE7からIE8で挙動が変更された「アプリケーションと安全でないファイルの起動」の項目が怪しいと思うのだがどうしてもエラーを解消できず。

ネット上で情報を探してみると「HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones」や
「HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Lockdown_Zones」、
「HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\ProtocolDefaults」
の辺りを変更すればなんとかなる気もするがよく分からなかった。仕方がないので今はウイザードは使わずに手動でソースコードを生成しているので非常に不便。なんとかならないだろうか。。。


バージョン情報(バージョンリソース)を取得する

version.gif
EXEファイルやDLLファイルなどに含まれているバージョンリソースから情報を取り出すにはGetFileVersionInfoSize、GetFileVersionInfo、VerQueryValueの3つを利用する。

ファイルによってはバージョン情報リソースが複数の言語分だけ用意されていたり、ひとつもなかったりすることもある。ここではGetThreadLocaleで得られるロケールのリソースから取得を試みて、ダメならファイルにあるリソースから順番に取得した。


#include "DnpFileVersion.h"

void	Test()
{
	CDnpFileVersion	ver;
	CAtlString	str;

	ver.Load(_T("c:\\windows\\system32\\acw.exe"));
	ver.GetProductVersion(str);
	ver.Unload();

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


■「DnpFileVersion.h」の内容
#pragma	once


#include "atlstr.h"
#pragma	comment(lib,"Version.lib")


///
///\brief
///		バージョン情報リソース取得クラス
///
///■使用例
/**	\code
	bool	Test()
	{
		CAtlString		strData;
		CDnpFileVersion	cInfo;

		cInfo.Load("C:\\WINDOWS\\system32\\cmd.exe");
		cInfo.GetValue("FileDescription",strData);

		cInfo.GetComments(strData);
		cInfo.GetInternalName(strData);
		cInfo.GetProductName(strData);
		cInfo.GetCompanyName(strData);
		cInfo.GetLegalCopyright(strData);
		cInfo.GetProductVersion(strData);
		cInfo.GetFileDescription(strData);
		cInfo.GetLegalTrademarks(strData);
		cInfo.GetPrivateBuild(strData);
		cInfo.GetFileVersion(strData);
		cInfo.GetOriginalFilename(strData);
		cInfo.GetSpecialBuild(strData);

		return	true;
	}
	\endcode
*///
///
class	CDnpFileVersion
{
protected:

	///
	///\brief
	///		LCIDを展開するための構造体
	///
	struct LANGANDCODEPAGE
	{
	  WORD wLanguage;
	  WORD wCodePage;
	};


	BYTE*				_pVersionInfo;			//!< 保持しているバージョンリソース
	LANGANDCODEPAGE*	_pTranslation;			//!< コードページ情報配列
	UINT				_nTranslationLen;		//!< コードページ情報配列サイズ(要素数)
	UINT				_nTranslationDefault;	//!< デフォルトで用いるコードページ情報配列へのインデックス



public:
	CDnpFileVersion()
	{
		_pVersionInfo = NULL;
		_pTranslation = NULL;
		_nTranslationLen = 0;
		_nTranslationDefault = 0;
	}

	~CDnpFileVersion()
	{
		Unload();
	}


	///
	///\brief
	///		バージョン情報のロード
	///
	///このクラス内にバージョン情報を保持する
	///
	///\param[in]	pszFile
	///	バージョン情報を取得したファイルへのパス(EXEやDLLなど)
	///
	///\retval	true	成功
	///\retval	false	失敗
	///
	bool	Load(LPCTSTR pszFile)
	{
		BOOL	ret;
		DWORD	dwSize;
		BYTE*	pData;
		BYTE*	pResult;
		UINT	nLen;

		Unload();
		dwSize = ::GetFileVersionInfoSize(pszFile,NULL);
		if(dwSize == 0)
			return	false;

		pData = new BYTE[dwSize];
		if(pData == NULL)
			return	false;

		ret = ::GetFileVersionInfo(pszFile,NULL,dwSize,pData);

		if(ret)
			ret = ::VerQueryValue(pData,_T("\\VarFileInfo\\Translation"),(void**)&pResult,&nLen); 

		if(ret == FALSE)
		{
			delete	pData;
			return	false;
		}


		//デフォルトのコードページがみつかればそれを_nTranslationDefaultに保存しておく
		//
		///\todo
		///	//■■デフォルトLCIDが見つからなかったら、ニュートラル言語などほかのを取得しておくべき
		{
			UINT	i;
			LANGANDCODEPAGE*	pLcid;
			LCID	nCurr;

			pLcid = (LANGANDCODEPAGE*)pResult;
			nCurr = ::GetThreadLocale();
			for(i = 0; i < nLen / sizeof(LANGANDCODEPAGE); i++)
			{
				if(pLcid[i].wLanguage != nCurr)
					continue;

				_nTranslationDefault = i;
			}

		}

		_pVersionInfo = pData;
		_pTranslation = (LANGANDCODEPAGE*)pResult;
		_nTranslationLen = nLen / sizeof(LANGANDCODEPAGE);

		return	true;
	}



	///
	///\brief
	///		保持している情報の破棄
	///
	void	Unload(void)
	{
		if(_pVersionInfo)
			delete	_pVersionInfo;
		_pVersionInfo = NULL;
		_pTranslation = NULL;
		_nTranslationLen = 0;
		_nTranslationDefault = 0;
	}


	///
	///\brief
	///		バージョンリソースの項目を取得する
	///
	///\attention
	///	複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
	///最初に見つかったリソースから文字列を返す
	///
	///\param[in]	pszBlockName
	///	取得したいバージョンリソースの名前
	///
	///\param[out]	strValue
	///	取得した文字列
	///
	///\retval	true	取得成功
	///\retval	false	失敗
	///
	bool	GetValue(LPCTSTR pszBlockName,CAtlString& strValue)
	{
		UINT		i;
		BOOL		ret;
		UINT		nLen;
		BYTE*		pData;
		CAtlString	strPath;

		strValue = _T("");

		if(_pVersionInfo == NULL || _pTranslation == NULL || _nTranslationLen == 0)
			return	false;

		//最初にデフォルトロケールで探しておく(_nTranslationDefault==0ならどのみちforで最初に検索されるから問題なし)
		if(_nTranslationDefault)
		{
			i = _nTranslationDefault;
			strPath.Format(_T("\\StringFileInfo\\%04x%04x\\%s"),_pTranslation[i].wLanguage,_pTranslation[i].wCodePage,pszBlockName);
			ret = ::VerQueryValue(_pVersionInfo,strPath.GetBuffer(0),(void**)&pData,&nLen);
			if(ret)
			{
				strValue = (TCHAR*)pData;
				return	true;
			}
		}

		for(i = 0; i < _nTranslationLen; i++)
		{
			strPath.Format(_T("\\StringFileInfo\\%04x%04x\\%s"),_pTranslation[i].wLanguage,_pTranslation[i].wCodePage,pszBlockName);
			ret = ::VerQueryValue(_pVersionInfo,strPath.GetBuffer(0),(void**)&pData,&nLen);
			if(ret == FALSE)
				continue;

			strValue = (TCHAR*)pData;
			return	true;
		}

		return	false;
	}


	///
	///\brief
	///		バージョン情報の「Comments」を取得する
	///
	///\attention
	///	複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
	///最初に見つかったリソースから文字列を返す
	///
	///\param[out]	strValue
	///		取得した文字列
	///
	///\retval	true	取得成功
	///\retval	false	失敗
	///
	bool	GetComments(CAtlString& strValue)
	{
		return	GetValue(_T("Comments"),strValue);
	}



	///
	///\brief
	///		バージョン情報の「InternalName」を取得する
	///
	///\attention
	///	複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
	///最初に見つかったリソースから文字列を返す
	///
	///\param[out]	strValue
	///		取得した文字列
	///
	///\retval	true	取得成功
	///\retval	false	失敗
	///
	bool	GetInternalName(CAtlString& strValue)
	{
		return	GetValue(_T("InternalName"),strValue);
	}



	///
	///\brief
	///		バージョン情報の「ProductName」を取得する
	///
	///\attention
	///	複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
	///最初に見つかったリソースから文字列を返す
	///
	///\param[out]	strValue
	///		取得した文字列
	///
	///\retval	true	取得成功
	///\retval	false	失敗
	///
	bool	GetProductName(CAtlString& strValue)
	{
		return	GetValue(_T("ProductName"),strValue);
	}



	///
	///\brief
	///		バージョン情報の「CompanyName」を取得する
	///
	///\attention
	///	複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
	///最初に見つかったリソースから文字列を返す
	///
	///\param[out]	strValue
	///		取得した文字列
	///
	///\retval	true	取得成功
	///\retval	false	失敗
	///
	bool	GetCompanyName(CAtlString& strValue)
	{
		return	GetValue(_T("CompanyName"),strValue);
	}



	///
	///\brief
	///		バージョン情報の「LegalCopyright」を取得する
	///
	///\attention
	///	複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
	///最初に見つかったリソースから文字列を返す
	///
	///\param[out]	strValue
	///		取得した文字列
	///
	///\retval	true	取得成功
	///\retval	false	失敗
	///
	bool	GetLegalCopyright(CAtlString& strValue)
	{
		return	GetValue(_T("LegalCopyright"),strValue);
	}



	///
	///\brief
	///		バージョン情報の「ProductVersion」を取得する
	///
	///\attention
	///	複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
	///最初に見つかったリソースから文字列を返す
	///
	///\param[out]	strValue
	///		取得した文字列
	///
	///\retval	true	取得成功
	///\retval	false	失敗
	///
	bool	GetProductVersion(CAtlString& strValue)
	{
		return	GetValue(_T("ProductVersion"),strValue);
	}



	///
	///\brief
	///		バージョン情報の「FileDescription」を取得する
	///
	///\attention
	///	複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
	///最初に見つかったリソースから文字列を返す
	///
	///\param[out]	strValue
	///		取得した文字列
	///
	///\retval	true	取得成功
	///\retval	false	失敗
	///
	bool	GetFileDescription(CAtlString& strValue)
	{
		return	GetValue(_T("FileDescription"),strValue);
	}



	///
	///\brief
	///		バージョン情報の「LegalTrademarks」を取得する
	///
	///\attention
	///	複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
	///最初に見つかったリソースから文字列を返す
	///
	///\param[out]	strValue
	///		取得した文字列
	///
	///\retval	true	取得成功
	///\retval	false	失敗
	///
	bool	GetLegalTrademarks(CAtlString& strValue)
	{
		return	GetValue(_T("LegalTrademarks"),strValue);
	}



	///
	///\brief
	///		バージョン情報の「PrivateBuild」を取得する
	///
	///\attention
	///	複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
	///最初に見つかったリソースから文字列を返す
	///
	///\param[out]	strValue
	///		取得した文字列
	///
	///\retval	true	取得成功
	///\retval	false	失敗
	///
	bool	GetPrivateBuild(CAtlString& strValue)
	{
		return	GetValue(_T("PrivateBuild"),strValue);
	}



	///
	///\brief
	///		バージョン情報の「FileVersion」を取得する
	///
	///\attention
	///	複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
	///最初に見つかったリソースから文字列を返す
	///
	///\param[out]	strValue
	///		取得した文字列
	///
	///\retval	true	取得成功
	///\retval	false	失敗
	///
	bool	GetFileVersion(CAtlString& strValue)
	{
		return	GetValue(_T("FileVersion"),strValue);
	}



	///
	///\brief
	///		バージョン情報の「OriginalFilename」を取得する
	///
	///\attention
	///	複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
	///最初に見つかったリソースから文字列を返す
	///
	///\param[out]	strValue
	///		取得した文字列
	///
	///\retval	true	取得成功
	///\retval	false	失敗
	///
	bool	GetOriginalFilename(CAtlString& strValue)
	{
		return	GetValue(_T("OriginalFilename"),strValue);
	}



	///
	///\brief
	///		バージョン情報の「SpecialBuild」を取得する
	///
	///\attention
	///	複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
	///最初に見つかったリソースから文字列を返す
	///
	///\param[out]	strValue
	///		取得した文字列
	///
	///\retval	true	取得成功
	///\retval	false	失敗
	///
	bool	GetSpecialBuild(CAtlString& strValue)
	{
		return	GetValue(_T("SpecialBuild"),strValue);
	}
};

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

前の10件 1  2





usefullcode@gmail.com

About 2009年03月

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

前の記事は2007年04月です。

次の記事は2009年04月です。

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