EternalWindows
バンドオブジェクト / ツールバンドサンプル

今回は、ツールバンドのサンプルコードを示します。 まず、DLLのdefファイルを示します。

LIBRARY	"mydll"

EXPORTS
	DllCanUnloadNow PRIVATE
	DllGetClassObject PRIVATE
	DllRegisterServer PRIVATE
	DllUnregisterServer PRIVATE

次に、ヘッダーファイル(sample.hと仮定)を示します。

class CToolBand : public IDeskBand, public IObjectWithSite, public IPersistStream, public IInputObject
{
public:
	STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
	STDMETHODIMP_(ULONG) AddRef();
	STDMETHODIMP_(ULONG) Release();
	
	STDMETHODIMP GetWindow(HWND *phwnd);
	STDMETHODIMP ContextSensitiveHelp(BOOL fEnterMode);
	STDMETHODIMP ShowDW(BOOL bShow);
	STDMETHODIMP CloseDW(DWORD dwReserved);
	STDMETHODIMP ResizeBorderDW(LPCRECT prcBorder, IUnknown *punkToolbarSite, BOOL fReserved);
	STDMETHODIMP GetBandInfo(DWORD dwBandID, DWORD dwViewMode, DESKBANDINFO *pdbi);
	
	STDMETHODIMP SetSite(IUnknown *pUnkSite);
	STDMETHODIMP GetSite(REFIID riid, void **ppvSite);

	STDMETHODIMP GetClassID(CLSID *pClassID);
	STDMETHODIMP IsDirty();
	STDMETHODIMP Load(IStream *pStm);
	STDMETHODIMP Save(IStream *pStm, BOOL fClearDirty);
	STDMETHODIMP GetSizeMax(ULARGE_INTEGER *pcbSize);

	STDMETHODIMP UIActivateIO(BOOL fActivate, MSG *pMsg);
	STDMETHODIMP HasFocusIO(VOID);
	STDMETHODIMP TranslateAcceleratorIO(LPMSG lpMsg);

	CToolBand();
	~CToolBand();
	BOOL IsIE();
	BOOL RegisterAndCreateWindow(HWND hwndParent);
	static LRESULT CALLBACK WindowProcStatic(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
	LRESULT WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
	void OnFocus(BOOL bFocus);
	BOOL CapturePage(LPTSTR lpszFolderPath);
	BOOL SaveFileProtect(LPWSTR lpszFolderPath, LPBYTE lpData, DWORD dwSize);
	BOOL SaveFile(LPWSTR lpszFolderPath, LPBYTE lpData, DWORD dwSize);
	LPBYTE CreateBitmapData(int nWidth, int nHeight, LPVOID lpBits, LPDWORD lpdwDataSize);
	HBITMAP CreateBackbuffer(int nWidth, int nHeight);
	void DPtoHIMETRIC(HDC hdc, LPSIZEL lpSizel);
	
private:
	LONG             m_cRef;
	HWND             m_hwnd;
	HWND             m_hwndToolbar;
	HWND             m_hwndEdit;
	HACCEL           m_haccel;
	BOOL             m_bHasFocus;
	IWebBrowser2     *m_pWebBrowser2;
	IInputObjectSite *m_pSite;
};

class CClassFactory : public IClassFactory
{
public:
	STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
	STDMETHODIMP_(ULONG) AddRef();
	STDMETHODIMP_(ULONG) Release();
	
	STDMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject);
	STDMETHODIMP LockServer(BOOL fLock);
};

次に、ソースファイルを示します。

#include <windows.h>
#include <shlwapi.h>
#include <shlobj.h>
#include <mshtml.h>
#include <commctrl.h>
#include <iepmapi.h>
#include "sample.h"

#define ID_BANDWINDOW 100
#define ID_TOOLBAR 200
#define ID_EDIT 300
#define ID_SAVE 1000

#pragma comment (lib, "comctl32.lib")
#pragma comment (lib, "shlwapi.lib")
#pragma comment (lib, "iepmapi.lib")

const CLSID CLSID_ToolBandSample = {0x9c450278, 0xe450, 0x4a94, {0x9c, 0x9b, 0x59, 0xb7, 0x8, 0x58, 0xe3, 0x8a}};
const TCHAR g_szClsid[] = TEXT("{9C450278-E450-4a94-9C9B-59B70858E38A}");

LONG      g_lLocks = 0;
HINSTANCE g_hinstDll = NULL;

void LockModule(BOOL bLock);
BOOL CreateRegistryKey(HKEY hKeyRoot, LPTSTR lpszKey, LPTSTR lpszValue, LPTSTR lpszData);


// CToolBand


CToolBand::CToolBand()
{
	m_cRef = 1;
	m_hwnd = NULL;
	m_hwndToolbar = NULL;
	m_hwndEdit = NULL;
	m_haccel = NULL;
	m_bHasFocus = FALSE;
	m_pSite = NULL;
	m_pWebBrowser2 = NULL;

	LockModule(TRUE);
}

CToolBand::~CToolBand()
{
	LockModule(FALSE);
}

STDMETHODIMP CToolBand::QueryInterface(REFIID riid, void **ppvObject)
{
	*ppvObject = NULL;

	if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IOleWindow) || IsEqualIID(riid, IID_IDockingWindow) || IsEqualIID(riid, IID_IDeskBand))
		*ppvObject = static_cast<IDeskBand *>(this);
	else if (IsEqualIID(riid, IID_IPersist) || IsEqualIID(riid, IID_IPersistStream))
		*ppvObject = static_cast<IPersistStream *>(this);
	else if (IsEqualIID(riid, IID_IObjectWithSite))
		*ppvObject = static_cast<IObjectWithSite *>(this);
	else if (IsEqualIID(riid, IID_IInputObject))
		*ppvObject = static_cast<IInputObject *>(this);
	else
		return E_NOINTERFACE;

	AddRef();

	return S_OK;
}

STDMETHODIMP_(ULONG) CToolBand::AddRef()
{
	return InterlockedIncrement(&m_cRef);
}

STDMETHODIMP_(ULONG) CToolBand::Release()
{
	if (InterlockedDecrement(&m_cRef) == 0) {
		delete this;
		return 0;
	}

	return m_cRef;
}

STDMETHODIMP CToolBand::GetWindow(HWND *phwnd)
{
	*phwnd = m_hwndToolbar;

	return S_OK;
}

STDMETHODIMP CToolBand::ContextSensitiveHelp(BOOL fEnterMode)
{
	return E_NOTIMPL;
}
	
STDMETHODIMP CToolBand::ShowDW(BOOL bShow)
{
	if (m_hwnd != NULL)
		ShowWindow(m_hwnd, bShow ? SW_SHOW : SW_HIDE);

	return S_OK;
}

STDMETHODIMP CToolBand::CloseDW(DWORD dwReserved)
{
	if (m_hwnd != NULL) {
		ShowWindow(m_hwnd, SW_HIDE);
		DestroyWindow(m_hwnd);
	}

	return S_OK;
}

STDMETHODIMP CToolBand::ResizeBorderDW(LPCRECT prcBorder, IUnknown *punkToolbarSite, BOOL fReserved)
{
	return E_NOTIMPL;
}

STDMETHODIMP CToolBand::GetBandInfo(DWORD dwBandID, DWORD dwViewMode, DESKBANDINFO *pdbi)
{
	if (pdbi == NULL)
		return E_INVALIDARG;

	if (pdbi->dwMask & DBIM_MINSIZE) {
		pdbi->ptMinSize.x = 200;
		pdbi->ptMinSize.y = 30;
	}

	if (pdbi->dwMask & DBIM_MAXSIZE)
		pdbi->ptMaxSize.y = -1;
	
	if (pdbi->dwMask & DBIM_INTEGRAL)
		pdbi->ptIntegral.y = 1;
	
	if (pdbi->dwMask & DBIM_ACTUAL) {
		pdbi->ptActual.x = 200;
		pdbi->ptActual.y = 30;
	}
	
	if (pdbi->dwMask & DBIM_TITLE)
		lstrcpyW(pdbi->wszTitle, L"");

	if (pdbi->dwMask & DBIM_MODEFLAGS)
		pdbi->dwModeFlags =  DBIMF_VARIABLEHEIGHT;

	if (pdbi->dwMask & DBIM_BKCOLOR)
		pdbi->dwMask &= ~DBIM_BKCOLOR;

	return S_OK;
}

STDMETHODIMP CToolBand::SetSite(IUnknown *pUnkSite)
{
	HRESULT hr = S_OK;
	
	if (m_pSite != NULL){
		m_pSite->Release();
		m_pSite = NULL;
	}

	if (pUnkSite != NULL) {
		HWND hwndParent;
		
		IUnknown_QueryService(pUnkSite, SID_SWebBrowserApp, IID_PPV_ARGS(&m_pWebBrowser2));
		if (!IsIE()) {
			m_pWebBrowser2->Release();
			return E_FAIL;
		}

		IUnknown_GetWindow(pUnkSite, &hwndParent);
		RegisterAndCreateWindow(hwndParent);

		hr = pUnkSite->QueryInterface(IID_PPV_ARGS(&m_pSite));
	}
	else {
		if (m_pWebBrowser2 != NULL) {
			m_pWebBrowser2->Release();
			m_pWebBrowser2 = NULL;
		}
		
		if (m_haccel != NULL) {
			DestroyAcceleratorTable(m_haccel);
			m_haccel = NULL;
		}
	}

	return hr;
}

STDMETHODIMP CToolBand::GetSite(REFIID riid, void **ppvSite)
{
	HRESULT hr;

	*ppvSite = NULL;

	if (m_pSite != NULL)
		hr = m_pSite->QueryInterface(riid, ppvSite);
	else
		hr = E_FAIL;

	return hr;
}

STDMETHODIMP CToolBand::GetClassID(CLSID *pClassID)
{
	*pClassID = CLSID_ToolBandSample;
	
	return S_OK;
}

STDMETHODIMP CToolBand::IsDirty()
{
	return E_NOTIMPL;
}

STDMETHODIMP CToolBand::Load(IStream *pStm)
{
	return S_OK;
}

STDMETHODIMP CToolBand::Save(IStream *pStm, BOOL fClearDirty)
{
	return S_OK;
}

STDMETHODIMP CToolBand::GetSizeMax(ULARGE_INTEGER *pcbSize)
{
	return E_NOTIMPL;
}

STDMETHODIMP CToolBand::UIActivateIO(BOOL fActivate, MSG *pMsg)
{
	if (fActivate)
		SetFocus(m_hwnd);

	return S_OK;
}

STDMETHODIMP CToolBand::HasFocusIO(VOID)
{
	return m_bHasFocus ? S_OK : S_FALSE;
}

STDMETHODIMP CToolBand::TranslateAcceleratorIO(LPMSG lpMsg)
{
	const int nEntries = 5;
	int       i;
	ACCEL     accel[nEntries];
	WORD      wCmd;
	WORD      wCmdArray[] = {0x41, 0x5a, 0x58, 0x43, 0x56};

	if (m_haccel == NULL) {
		for (i = 0; i < nEntries; i++) {
			accel[i].key   = wCmdArray[i]; 
			accel[i].cmd   = wCmdArray[i];
			accel[i].fVirt = FCONTROL | FVIRTKEY;
		}

		m_haccel = CreateAcceleratorTable(accel, nEntries);
	}

	if (lpMsg->message == WM_KEYDOWN) {
		if (lpMsg->wParam == VK_DELETE || lpMsg->wParam == VK_LEFT || lpMsg->wParam == VK_UP || lpMsg->wParam == VK_RIGHT || lpMsg->wParam == VK_DOWN) {
			SendMessage(lpMsg->hwnd, lpMsg->message, lpMsg->wParam, lpMsg->lParam);
			return S_OK;
		}
		else if (lpMsg->wParam == VK_BACK) {
			SendMessage(lpMsg->hwnd, WM_CHAR, lpMsg->wParam, lpMsg->lParam);
			return S_OK;
		}
		else {
			if (IsAccelerator(m_haccel, nEntries, lpMsg, &wCmd)) {
				if (wCmd == 0x41)
					SendMessage(lpMsg->hwnd, EM_SETSEL, 0, -1);
				else if (wCmd == 0x5a)
					SendMessage(lpMsg->hwnd, WM_UNDO, 0, 0);
				else if (wCmd == 0x58)
					SendMessage(lpMsg->hwnd, WM_CUT, 0, 0);
				else if (wCmd == 0x43)
					SendMessage(lpMsg->hwnd, WM_COPY, 0, 0);
				else if (wCmd == 0x56)
					SendMessage(lpMsg->hwnd, WM_PASTE, 0, 0);
				else
					;
				return S_OK;
			}
		}
	}

	return S_FALSE;
}

BOOL CToolBand::IsIE()
{
	BSTR bstr;
	BOOL bResult;

	m_pWebBrowser2->get_Name(&bstr);
	if (lstrcmpW(bstr, L"Windows Internet Explorer") == 0)
		bResult = TRUE;
	else
		bResult = FALSE;
	
	return bResult;
}

BOOL CToolBand::RegisterAndCreateWindow(HWND hwndParent)
{
	TCHAR      szClassName[] = TEXT("sample_toolband");
	WNDCLASSEX wc;
	DWORD      dwStyle;
	TBBUTTON   tbButton[] = {
		{STD_FILESAVE, ID_SAVE, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, (INT_PTR)TEXT("保存")}
	};
	int nCount = sizeof(tbButton) / sizeof(tbButton[0]);
	
	if (!GetClassInfoEx(g_hinstDll, szClassName, &wc)) {
		wc.cbSize        = sizeof(WNDCLASSEX);
		wc.style         = 0;
		wc.lpfnWndProc   = WindowProcStatic;
		wc.cbClsExtra    = 0;
		wc.cbWndExtra    = 0;
		wc.hInstance     = g_hinstDll;
		wc.hIcon         = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
		wc.hCursor       = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED);
		wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
		wc.lpszMenuName  = NULL;
		wc.lpszClassName = szClassName;
		wc.hIconSm       = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
		
		RegisterClassEx(&wc);
	}

	m_hwnd = CreateWindowEx(0, szClassName, TEXT(""), WS_CHILD | WS_TABSTOP | WS_CLIPCHILDREN, 0, 0, 0, 0, hwndParent, (HMENU)ID_BANDWINDOW, g_hinstDll, this);
	SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)this);

	m_hwndToolbar = CreateToolbarEx(m_hwnd, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | TBSTYLE_LIST | TBSTYLE_TRANSPARENT | CCS_NODIVIDER | CCS_NOPARENTALIGN, ID_TOOLBAR, 0, HINST_COMMCTRL, IDB_STD_SMALL_COLOR, tbButton, nCount, 0, 0, 0, 0, sizeof(TBBUTTON));
	dwStyle = (DWORD)SendMessage(m_hwndToolbar, TB_GETSTYLE, 0, 0) | TBSTYLE_FLAT;
	SendMessage(m_hwndToolbar, TB_SETSTYLE, 0, (LPARAM)dwStyle);

	m_hwndEdit = CreateWindowEx(0, TEXT("EDIT"), TEXT(""), WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, 60, 0, 250, 25, m_hwndToolbar, (HMENU)ID_EDIT, g_hinstDll, NULL);

	return TRUE;
}

LRESULT CALLBACK CToolBand::WindowProcStatic(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	CToolBand *p = (CToolBand *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
	
	if (p != NULL)
		return p->WindowProc(hwnd, uMsg, wParam, lParam);
	else
		return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

LRESULT CToolBand::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg) {
	
	case WM_COMMAND:
		if (LOWORD(wParam) == ID_EDIT) {
			if (HIWORD(wParam) == EN_SETFOCUS)
				OnFocus(TRUE);
			else if (HIWORD(wParam) == EN_KILLFOCUS)
				OnFocus(FALSE);
			else
				;
		}
		else if (LOWORD(wParam) == ID_SAVE) {
			TCHAR szFolderPath[MAX_PATH];

			GetWindowText(m_hwndEdit, szFolderPath, sizeof(szFolderPath) / sizeof(TCHAR));
			if (CapturePage(szFolderPath))
				MessageBox(NULL, TEXT("ファイルを作成しました。"), TEXT("OK"), MB_OK);
			else
				MessageBox(NULL, TEXT("ファイルの作成に失敗しました。"), NULL, MB_ICONWARNING);
		}
		return 0;

	case WM_SETFOCUS:
		SetFocus(m_hwndEdit);
		return 0;
	
	case WM_SIZE:
		MoveWindow(m_hwndToolbar, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
		return 0;
	
	default:
		break;

	}

	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

void CToolBand::OnFocus(BOOL bFocus)
{
	m_bHasFocus = bFocus;
	
	if (m_pSite != NULL)
		m_pSite->OnFocusChangeIS(static_cast<IInputObject *>(this), m_bHasFocus);
}

BOOL CToolBand::CapturePage(LPTSTR lpszFolderPath)
{
	IDispatch      *pDispatch;
	IHTMLDocument2 *pDocument2;
	IHTMLElement   *pElement;
	IHTMLElement2  *pElement2;
	IOleObject     *pOleObject;
	LONG           lWidth, lHeight;
	SIZEL          sizelPrev, sizel;
	RECT           rc;
	BOOL           bResult;
	HDC            hdcMem;
	HBITMAP        hbmpMem;
	HBITMAP        hbmpMemPrev;
	BITMAP         bm;
	BOOL           bProtectedMode = FALSE;
	LPBYTE         lpData;
	DWORD          dwSize;

	m_pWebBrowser2->get_Document(&pDispatch);
	pDispatch->QueryInterface(IID_PPV_ARGS(&pDocument2));
	pDocument2->get_body(&pElement);
	pElement->QueryInterface(IID_PPV_ARGS(&pElement2));
	pElement2->get_scrollWidth(&lWidth);
	pElement2->get_scrollHeight(&lHeight);
	
	hdcMem = CreateCompatibleDC(NULL);
	hbmpMem = CreateBackbuffer(lWidth, lHeight);
	hbmpMemPrev = (HBITMAP)SelectObject(hdcMem, hbmpMem);
	
	pDispatch->QueryInterface(IID_PPV_ARGS(&pOleObject));
	pOleObject->GetExtent(DVASPECT_CONTENT, &sizelPrev);
	sizel.cx = lWidth;
	sizel.cy = lHeight;
	DPtoHIMETRIC(hdcMem, &sizel);
	pOleObject->SetExtent(DVASPECT_CONTENT, &sizel);

	SetRect(&rc, 0, 0, lWidth, lHeight);
	OleDraw(pOleObject, DVASPECT_CONTENT, hdcMem, &rc);
	pOleObject->SetExtent(DVASPECT_CONTENT, &sizelPrev);

	GetObject(hbmpMem, sizeof(BITMAP), &bm);
	lpData = CreateBitmapData(lWidth, lHeight, bm.bmBits, &dwSize);

	IEIsProtectedModeProcess(&bProtectedMode);
	if (bProtectedMode)
		bResult = SaveFileProtect(lpszFolderPath, lpData, dwSize);
	else
		bResult = SaveFile(lpszFolderPath, lpData, dwSize);

	CoTaskMemFree(lpData);
	SelectObject(hdcMem, hbmpMemPrev);
	DeleteObject(hbmpMem);
	DeleteDC(hdcMem);
	pElement2->Release();
	pElement->Release();
	pOleObject->Release();
	pDocument2->Release();
	pDispatch->Release();

	return bResult;
}

BOOL CToolBand::SaveFileProtect(LPWSTR lpszFolderPath, LPBYTE lpData, DWORD dwSize)
{
	LPCWSTR lpszExt = L"Bitmap Files|*.bmp|";
	LPCWSTR lpszDefExt = L"bmp";
	WCHAR   szTempPath[MAX_PATH];
	DWORD   dwResult;
	HRESULT hr;
	HANDLE  hState, hFile;
	LPWSTR  lpszTargetPath, lpszCachePath;

	hr = IEShowSaveFileDialog(NULL, L"", lpszFolderPath, lpszExt, lpszDefExt, 1, OFN_OVERWRITEPROMPT, &lpszTargetPath, &hState);
	if (hr != S_OK)
		return FALSE;
	
	hr = IEGetWriteableFolderPath(FOLDERID_InternetCache, &lpszCachePath);
	if (hr != S_OK) {
		CoTaskMemFree(lpszTargetPath);
		IECancelSaveFile(hState);
		return FALSE;
	}

	GetTempFileNameW(lpszCachePath, TEXT("tmp"), 0, szTempPath);

	hFile = CreateFileW(szTempPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	WriteFile(hFile, lpData, dwSize, &dwResult, NULL);
	CloseHandle(hFile);
	
	IESaveFile(hState, szTempPath);

	CoTaskMemFree(lpszTargetPath);
	CoTaskMemFree(lpszCachePath);

	return TRUE;
}

BOOL CToolBand::SaveFile(LPWSTR lpszFolderPath, LPBYTE lpData, DWORD dwSize)
{
	OPENFILENAMEW ofn;
	WCHAR         szFilePath[MAX_PATH];
	DWORD         dwResult;
	HANDLE        hFile;

	szFilePath[0] = '\0';

	ZeroMemory(&ofn, sizeof(OPENFILENAME));
	ofn.lStructSize     = sizeof(OPENFILENAME);
	ofn.lpstrFilter     = L"Bitmap Files (*.bmp)\0*.bmp\0\0";
	ofn.lpstrFile       = szFilePath;
	ofn.nMaxFile        = MAX_PATH;
	ofn.lpstrInitialDir = lpszFolderPath;
	ofn.lpstrDefExt     = L"bmp";

	if (!GetSaveFileNameW(&ofn))
		return FALSE;
	
	hFile = CreateFileW(szFilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	WriteFile(hFile, lpData, dwSize, &dwResult, NULL);
	CloseHandle(hFile);

	return TRUE;
}

LPBYTE CToolBand::CreateBitmapData(int nWidth, int nHeight, LPVOID lpBits, LPDWORD lpdwDataSize)
{
	DWORD            dwSizeImage;
	DWORD            dwDataSize;
	LPBYTE           lp, lpData;
	BITMAPFILEHEADER bmfHeader;
	BITMAPINFOHEADER bmiHeader;

	dwSizeImage = nHeight * ((3 * nWidth + 3) / 4) * 4;

	dwDataSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwSizeImage;
	lpData =(LPBYTE)CoTaskMemAlloc(dwDataSize);
	lp = lpData;

	ZeroMemory(&bmfHeader, sizeof(BITMAPFILEHEADER));
	bmfHeader.bfType    = *(LPWORD)"BM";
	bmfHeader.bfSize    = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwSizeImage;
	bmfHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
	CopyMemory(lp, &bmfHeader, sizeof(BITMAPFILEHEADER));
	lp += sizeof(BITMAPFILEHEADER);
	
	ZeroMemory(&bmiHeader, sizeof(BITMAPINFOHEADER));
	bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
	bmiHeader.biWidth       = nWidth;
	bmiHeader.biHeight      = nHeight;
	bmiHeader.biPlanes      = 1;
	bmiHeader.biBitCount    = 24;
	bmiHeader.biSizeImage   = 0;
	bmiHeader.biCompression = BI_RGB;
	CopyMemory(lp, &bmiHeader, sizeof(BITMAPINFOHEADER));
	lp += sizeof(BITMAPINFOHEADER);

	CopyMemory(lp, lpBits, dwSizeImage);
	
	*lpdwDataSize = dwDataSize;

	return lpData;
}

HBITMAP CToolBand::CreateBackbuffer(int nWidth, int nHeight)
{
	LPVOID           lp;
	BITMAPINFO       bmi;
	BITMAPINFOHEADER bmiHeader;

	ZeroMemory(&bmiHeader, sizeof(BITMAPINFOHEADER));
	bmiHeader.biSize      = sizeof(BITMAPINFOHEADER);
	bmiHeader.biWidth     = nWidth;
	bmiHeader.biHeight    = nHeight;
	bmiHeader.biPlanes    = 1;
	bmiHeader.biBitCount  = 24;

	bmi.bmiHeader = bmiHeader;

	return CreateDIBSection(NULL, (LPBITMAPINFO)&bmi, DIB_RGB_COLORS, &lp, NULL, 0);
}

void CToolBand::DPtoHIMETRIC(HDC hdc, LPSIZEL lpSizel)
{
	const int HIMETRIC_INCH = 2540;

	lpSizel->cx = MulDiv(lpSizel->cx, HIMETRIC_INCH, GetDeviceCaps(hdc, LOGPIXELSX));
	lpSizel->cy = MulDiv(lpSizel->cy, HIMETRIC_INCH, GetDeviceCaps(hdc, LOGPIXELSY));
}


// CClassFactory


STDMETHODIMP CClassFactory::QueryInterface(REFIID riid, void **ppvObject)
{
	*ppvObject = NULL;

	if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory))
		*ppvObject = static_cast<IClassFactory *>(this);
	else
		return E_NOINTERFACE;

	AddRef();
	
	return S_OK;
}

STDMETHODIMP_(ULONG) CClassFactory::AddRef()
{
	LockModule(TRUE);

	return 2;
}

STDMETHODIMP_(ULONG) CClassFactory::Release()
{
	LockModule(FALSE);

	return 1;
}

STDMETHODIMP CClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject)
{
	CToolBand *p;
	HRESULT   hr;
	
	*ppvObject = NULL;

	if (pUnkOuter != NULL)
		return CLASS_E_NOAGGREGATION;

	p = new CToolBand();
	if (p == NULL)
		return E_OUTOFMEMORY;

	hr = p->QueryInterface(riid, ppvObject);
	p->Release();

	return hr;
}

STDMETHODIMP CClassFactory::LockServer(BOOL fLock)
{
	LockModule(fLock);

	return S_OK;
}


// DLL Export


STDAPI DllCanUnloadNow(void)
{
	return g_lLocks == 0 ? S_OK : S_FALSE;
}

STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
{
	static CClassFactory serverFactory;
	HRESULT hr;
	
	*ppv = NULL;

	if (IsEqualCLSID(rclsid, CLSID_ToolBandSample))
		hr = serverFactory.QueryInterface(riid, ppv);
	else
		hr = CLASS_E_CLASSNOTAVAILABLE;

	return hr;
}

STDAPI DllRegisterServer(void)
{
	TCHAR szModulePath[MAX_PATH];
	TCHAR szKey[256];

	wsprintf(szKey, TEXT("CLSID\\%s"), g_szClsid);
	if (!CreateRegistryKey(HKEY_CLASSES_ROOT, szKey, NULL, TEXT("ToolBand Sample")))
		return E_FAIL;

	GetModuleFileName(g_hinstDll, szModulePath, sizeof(szModulePath) / sizeof(TCHAR));
	wsprintf(szKey, TEXT("CLSID\\%s\\InprocServer32"), g_szClsid);
	if (!CreateRegistryKey(HKEY_CLASSES_ROOT, szKey, NULL, szModulePath))
		return E_FAIL;
	
	wsprintf(szKey, TEXT("CLSID\\%s\\InprocServer32"), g_szClsid);
	if (!CreateRegistryKey(HKEY_CLASSES_ROOT, szKey, TEXT("ThreadingModel"), TEXT("Apartment")))
		return E_FAIL;
	
	wsprintf(szKey, TEXT("SOFTWARE\\Microsoft\\Internet Explorer\\Toolbar"));
	if (!CreateRegistryKey(HKEY_LOCAL_MACHINE, szKey, (LPTSTR)g_szClsid, NULL))
		return E_FAIL;

	return S_OK;
}

STDAPI DllUnregisterServer(void)
{
	TCHAR szKey[256];

	wsprintf(szKey, TEXT("CLSID\\%s"), g_szClsid);
	SHDeleteKey(HKEY_CLASSES_ROOT, szKey);
	
	SHDeleteValue(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Internet Explorer\\Toolbar"), (LPTSTR)g_szClsid);

	return S_OK;
}

BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD dwReason, LPVOID lpReserved)
{
	switch (dwReason) {

	case DLL_PROCESS_ATTACH:
		g_hinstDll = hinstDll;
		DisableThreadLibraryCalls(hinstDll);
		return TRUE;

	}

	return TRUE;
}


// Function


void LockModule(BOOL bLock)
{
	if (bLock)
		InterlockedIncrement(&g_lLocks);
	else
		InterlockedDecrement(&g_lLocks);
}

BOOL CreateRegistryKey(HKEY hKeyRoot, LPTSTR lpszKey, LPTSTR lpszValue, LPTSTR lpszData)
{
	HKEY  hKey;
	LONG  lResult;
	DWORD dwSize;

	lResult = RegCreateKeyEx(hKeyRoot, lpszKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL);
	if (lResult != ERROR_SUCCESS)
		return FALSE;

	if (lpszData != NULL)
		dwSize = (lstrlen(lpszData) + 1) * sizeof(TCHAR);
	else
		dwSize = 0;

	RegSetValueEx(hKey, lpszValue, 0, REG_SZ, (LPBYTE)lpszData, dwSize);
	RegCloseKey(hKey);
	
	return TRUE;
}

バンドオブジェクトの実体は、COMオブジェクトを実装したDLLです。 次に示すレジストリキーにDLLを登録しておけば、 IEがバンドオブジェクトのDLLをロードするようになります。

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Toolbar

上記キーの新規エントリとして、COMオブジェクトのCLSIDを書き込みます。 IEはこのCLSIDをHKEY_CLASSES_ROOT\CLSID以下から探し出し、 関連するDLLをロードします。

作成したDLLは次の方法でレジストリに登録できます。

regsvr32 C:\sample.dll (登録の解除時は regsvr32 /u C:\sample.dll のようにする)

コマンドプロンプト上でregsvr32という文字列を入力し、その後に作成したDLLのパスを入力します。 これを実行すればDLLのDllRegisterServerが呼ばれ、DLLは登録されたことになります。 登録を終えたらIEのメニューから「ToolBand Sample」を選択することで、ツールバンドを確認することができるはずです。


戻る