EternalWindows
OLE埋め込み / オブジェクトサンプル

OLE埋め込みのオブジェクト側のサンプルを示します。 どのコンテナに埋め込むについては、今回作成したコンテナでも構いませんし、 WordやExcelのような既存のコンテナでも構いません。 まず、object.hを示します。

struct SHAPE {
	RECT rc;
	BOOL bRectangle;
};
typedef struct SHAPE SHAPE;
typedef struct SHAPE *LPSHAPE;

class CObject : public IOleObject, public IDataObject, public IPersistStorage
{
public:
	STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
	STDMETHODIMP_(ULONG) AddRef();
	STDMETHODIMP_(ULONG) Release();

	STDMETHODIMP SetClientSite(IOleClientSite *pClientSite);
	STDMETHODIMP GetClientSite(IOleClientSite **ppClientSite);
	STDMETHODIMP SetHostNames(LPCOLESTR szContainerApp, LPCOLESTR szContainerObj);
	STDMETHODIMP Close(DWORD dwSaveOption);
	STDMETHODIMP SetMoniker(DWORD dwWhichMoniker, IMoniker *pmk);
	STDMETHODIMP GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker **ppmk);
	STDMETHODIMP InitFromData(IDataObject *pDataObject, BOOL fCreation, DWORD dwReserved);
	STDMETHODIMP GetClipboardData(DWORD dwReserved, IDataObject **ppDataObject);
	STDMETHODIMP DoVerb(LONG iVerb, LPMSG lpmsg, IOleClientSite *pActiveSite, LONG lindex, HWND hwndParent, LPCRECT lprcPosRect);
	STDMETHODIMP EnumVerbs(IEnumOLEVERB **ppEnumOleVerb);
	STDMETHODIMP Update();
	STDMETHODIMP IsUpToDate();
	STDMETHODIMP GetUserClassID(CLSID *pClsid);
	STDMETHODIMP GetUserType(DWORD dwFormOfType, LPOLESTR *pszUserType);
	STDMETHODIMP SetExtent(DWORD dwDrawAspect, SIZEL *psizel);
	STDMETHODIMP GetExtent(DWORD dwDrawAspect, SIZEL *psizel);
	STDMETHODIMP Advise(IAdviseSink *pAdvSink, DWORD *pdwConnection);
	STDMETHODIMP Unadvise(DWORD dwConnection);
	STDMETHODIMP EnumAdvise(IEnumSTATDATA **ppenumAdvise);
	STDMETHODIMP GetMiscStatus(DWORD dwAspect, DWORD *pdwStatus);
	STDMETHODIMP SetColorScheme(LOGPALETTE *pLogpal);

	STDMETHODIMP GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium);
	STDMETHODIMP GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium);
	STDMETHODIMP QueryGetData(FORMATETC *pformatetc);
	STDMETHODIMP GetCanonicalFormatEtc(FORMATETC *pformatectIn, FORMATETC *pformatetcOut);
	STDMETHODIMP SetData(FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease);
	STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc);
	STDMETHODIMP DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection);
	STDMETHODIMP DUnadvise(DWORD dwConnection);
	STDMETHODIMP EnumDAdvise(IEnumSTATDATA **ppenumAdvise);

	STDMETHODIMP GetClassID(CLSID *pClassID);
	STDMETHODIMP IsDirty();
	STDMETHODIMP InitNew(IStorage *pStg);
	STDMETHODIMP Load(IStorage *pStg);
	STDMETHODIMP Save(IStorage *pStgSave, BOOL fSameAsLoad);
	STDMETHODIMP SaveCompleted(IStorage *pStgNew);
	STDMETHODIMP HandsOffStorage();

	CObject();
	~CObject();
	int Run(HINSTANCE hinst, int nCmdShow, BOOL bEmbedding);
	LRESULT WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
	void DrawShape(HDC hdc);
	void GetSize(int *pnWidth, int *pnHeight);
	HGLOBAL GetMetaFileData(BOOL bEnhance);
	void DPtoHIMETRIC(LPSIZEL lpSizel);
	void SaveObject();
	void InitializeMenuItem(HMENU hmenu, LPTSTR lpszItemName, int nId, HMENU hmenuSub);

private:
	LONG              m_cRef;
	HWND              m_hwnd;
	HMENU             m_hmenu;
	BOOL              m_bEmbedding;
	BOOL              m_bDirty;
	BOOL              m_bDrawRectangle;
	WCHAR             m_szStreamName[256];
	SHAPE             m_shape[10];
	int               m_nShapeCount;
	int               m_nShapeMaxCount;
	IStorage          *m_pStorage;
	IStream           *m_pStream;
	IOleClientSite    *m_pClientSite;
	IOleAdviseHolder  *m_pAdviseHolder;
	IDataAdviseHolder *m_pDataAdviseHolder;
};

extern CObject *g_pObject;

const CLSID CLSID_SampleObject = {0x9d22dc48, 0x655, 0x4c36, {0x93, 0xad, 0xdf, 0xd8, 0xf0, 0x53, 0xab, 0xe0}};
const TCHAR g_szClsid[] = TEXT("{9D22DC48-0655-4c36-93AD-DFD8F053ABE0}");
const TCHAR g_szProgid[] = TEXT("Sample.OleServer");

次に、sample.cppを示します。

#include <windows.h>
#include <shlwapi.h>
#include "object.h"

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

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);
};

BOOL RegisterServer();
BOOL UnregisterServer();
BOOL CreateVerbKey();
BOOL CreateRegistryKey(HKEY hKeyRoot, LPTSTR lpszKey, LPTSTR lpszValue, LPTSTR lpszData);

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	int           nResult;
	DWORD         dwRegister = 0;
	BOOL          bEmbedding;
	CClassFactory classFactory;

	OleInitialize(NULL);
	
	g_pObject = new CObject;
	if (g_pObject == NULL) {
		OleUninitialize();
		return 0;
	}

	if ((lstrcmpA(lpszCmdLine, "-RegServer") == 0) || (lstrcmpA(lpszCmdLine, "/RegServer") == 0)) {
		if (RegisterServer())
			MessageBox(NULL, TEXT("登録に成功しました。"), TEXT("OK"), MB_OK);
		else
			MessageBox(NULL, TEXT("登録に失敗しました。"), NULL, MB_ICONWARNING);
		OleUninitialize();
		return 0;
	}
	else if ((lstrcmpA(lpszCmdLine, "-UnregServer") == 0) || (lstrcmpA(lpszCmdLine, "/UnregServer") == 0)) {
		UnregisterServer();
		MessageBox(NULL, TEXT("登録を解除しました。"), TEXT("OK"), MB_OK);
		OleUninitialize();
		return 0;
	}
	else if (lstrcmpA(lpszCmdLine, "-Embedding") == 0 || (lstrcmpA(lpszCmdLine, "/Embedding") == 0)) {
		CoRegisterClassObject(CLSID_SampleObject, static_cast<IClassFactory *>(&classFactory), CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &dwRegister);
		nCmdShow = SW_HIDE;
		bEmbedding = TRUE;
	}
	else
		bEmbedding = FALSE;

	nResult = g_pObject->Run(hinst, nCmdShow, bEmbedding);
	g_pObject->Release();

	if (bEmbedding)
		CoRevokeClassObject(dwRegister);

	OleUninitialize();

	return nResult;
}


// 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()
{
	return 2;
}

STDMETHODIMP_(ULONG) CClassFactory::Release()
{
	return 1;
}

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

	*ppvObject = NULL;

	if (pUnkOuter != NULL)
		return CLASS_E_NOAGGREGATION;

	hr = g_pObject->QueryInterface(riid, ppvObject);

	return hr;
}

STDMETHODIMP CClassFactory::LockServer(BOOL fLock)
{
	return S_OK;
}


// Function


BOOL RegisterServer()
{
	TCHAR szObjectName[] = TEXT("Sample Object");
	TCHAR szModulePath[MAX_PATH];
	TCHAR szKey[256];

	wsprintf(szKey, TEXT("CLSID\\%s"), g_szClsid);
	if (!CreateRegistryKey(HKEY_CLASSES_ROOT, szKey, NULL, szObjectName))
		return FALSE;

	GetModuleFileName(NULL, szModulePath, sizeof(szModulePath) / sizeof(TCHAR));
	wsprintf(szKey, TEXT("CLSID\\%s\\LocalServer32"), g_szClsid);
	if (!CreateRegistryKey(HKEY_CLASSES_ROOT, szKey, NULL, szModulePath))
		return FALSE;
	
	wsprintf(szKey, TEXT("CLSID\\%s\\InprocServer32"), g_szClsid);
	if (!CreateRegistryKey(HKEY_CLASSES_ROOT, szKey, NULL, TEXT("ole32.dll")))
		return FALSE;

	wsprintf(szKey, TEXT("CLSID\\%s\\ProgID"), g_szClsid);
	if (!CreateRegistryKey(HKEY_CLASSES_ROOT, szKey, NULL, (LPTSTR)g_szProgid))
		return FALSE;

	wsprintf(szKey, TEXT("%s"), g_szProgid);
	if (!CreateRegistryKey(HKEY_CLASSES_ROOT, szKey, NULL, szObjectName))
		return FALSE;

	wsprintf(szKey, TEXT("%s\\Insertable"), g_szProgid);
	if (!CreateRegistryKey(HKEY_CLASSES_ROOT, szKey, NULL, NULL))
		return FALSE;
  
	wsprintf(szKey, TEXT("%s\\CLSID"), g_szProgid);
	if (!CreateRegistryKey(HKEY_CLASSES_ROOT, szKey, NULL, (LPTSTR)g_szClsid))
		return FALSE;
	
	if (!CreateVerbKey())
		return FALSE;

	return TRUE;
}

BOOL UnregisterServer()
{
	TCHAR szKey[256];

	wsprintf(szKey, TEXT("CLSID\\%s"), g_szClsid);
	SHDeleteKey(HKEY_CLASSES_ROOT, szKey);
	
	wsprintf(szKey, TEXT("%s"), g_szProgid);
	SHDeleteKey(HKEY_CLASSES_ROOT, szKey);

	return TRUE;
}

BOOL CreateVerbKey()
{
	TCHAR szKey[256];

	wsprintf(szKey, TEXT("CLSID\\%s\\Verb"), g_szClsid);
	if (!CreateRegistryKey(HKEY_CLASSES_ROOT, szKey, NULL, NULL))
		return FALSE;

	wsprintf(szKey, TEXT("CLSID\\%s\\Verb\\0"), g_szClsid);
	if (!CreateRegistryKey(HKEY_CLASSES_ROOT, szKey, NULL, TEXT("&編集,0,2")))
		return FALSE;

	wsprintf(szKey, TEXT("CLSID\\%s\\Verb\\1"), g_szClsid);
	if (!CreateRegistryKey(HKEY_CLASSES_ROOT, szKey, NULL, TEXT("&開く,0,2")))
		return FALSE;

	return TRUE;
}

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;
}

最後に、object.cppを示します。

#include <windows.h>
#include "object.h"

#define ID_FILE 100
#define ID_EXIT 200
#define ID_UPDATE 300
#define ID_EDIT 400
#define ID_RECTANGLE 500
#define ID_ELLIPSE 600

CObject *g_pObject = NULL;

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	return g_pObject->WindowProc(hwnd, uMsg, wParam, lParam);
}


// CObject


CObject::CObject()
{
	m_cRef = 1;
	m_hwnd = NULL;
	m_hmenu = NULL;
	m_bEmbedding = FALSE;
	m_bDirty = FALSE;
	m_bDrawRectangle = TRUE;
	m_nShapeCount = 0;
	m_nShapeMaxCount = sizeof(m_shape) / sizeof(m_shape[0]);
	m_pStorage = NULL;
	m_pStream = NULL;
	m_pClientSite = NULL;
	m_pAdviseHolder = NULL;
	m_pDataAdviseHolder = NULL;
	lstrcpyW(m_szStreamName, L"stream");
}

CObject::~CObject()
{
	HandsOffStorage();
	
	if (m_pAdviseHolder != NULL)
		m_pAdviseHolder->Release();

	if (m_pDataAdviseHolder != NULL)
		m_pDataAdviseHolder->Release();
}

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

	if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IOleObject))
		*ppvObject = static_cast<IOleObject *>(this);
	else if (IsEqualIID(riid, IID_IDataObject))
		*ppvObject = static_cast<IDataObject *>(this);
	else if (IsEqualIID(riid, IID_IPersist) || IsEqualIID(riid, IID_IPersistStorage))
		*ppvObject = static_cast<IPersistStorage *>(this);
	else
		return E_NOINTERFACE;

	AddRef();
	
	return S_OK;
}

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

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

	return m_cRef;
}

STDMETHODIMP CObject::SetClientSite(IOleClientSite *pClientSite)
{
	if (m_pClientSite != NULL)
		m_pClientSite->Release();

	m_pClientSite = pClientSite;

	if (m_pClientSite != NULL)
		m_pClientSite->AddRef();

	return S_OK;
}

STDMETHODIMP CObject::GetClientSite(IOleClientSite **ppClientSite)
{
	*ppClientSite = m_pClientSite;
	m_pClientSite->AddRef();

	return S_OK;
}

STDMETHODIMP CObject::SetHostNames(LPCOLESTR szContainerApp, LPCOLESTR szContainerObj)
{
	int   i, nCount;
	HMENU hmenuPopupFile;
	WCHAR szBuf[256];

	hmenuPopupFile = GetSubMenu(m_hmenu, 0);
	nCount = GetMenuItemCount(hmenuPopupFile);

	for (i = 0; i < nCount; i++)
		RemoveMenu(hmenuPopupFile, 0, MF_BYPOSITION);

	wsprintf(szBuf, L"%sの更新", szContainerObj);
	InitializeMenuItem(hmenuPopupFile, szBuf, ID_UPDATE, NULL);
	InitializeMenuItem(hmenuPopupFile, TEXT("終了(&X)"), ID_EXIT, NULL);

	return S_OK;
}

STDMETHODIMP CObject::Close(DWORD dwSaveOption)
{
	BOOL bDontSave;

	if (dwSaveOption == OLECLOSE_NOSAVE)
		bDontSave = TRUE;
	else
		bDontSave = FALSE;
	
	PostMessage(m_hwnd, WM_CLOSE, (WPARAM)bDontSave, 0);
	
	return S_OK;
}

STDMETHODIMP CObject::SetMoniker(DWORD dwWhichMoniker, IMoniker *pmk)
{
	return E_NOTIMPL;
}

STDMETHODIMP CObject::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker **ppmk)
{
	return E_NOTIMPL;
}

STDMETHODIMP CObject::InitFromData(IDataObject *pDataObject, BOOL fCreation, DWORD dwReserved)
{
	return E_NOTIMPL;
}

STDMETHODIMP CObject::GetClipboardData(DWORD dwReserved, IDataObject **ppDataObject)
{
	return E_NOTIMPL;
}

STDMETHODIMP CObject::DoVerb(LONG iVerb, LPMSG lpmsg, IOleClientSite *pActiveSite, LONG lindex, HWND hwndParent, LPCRECT lprcPosRect)
{
	if (iVerb == OLEIVERB_OPEN || iVerb == OLEIVERB_SHOW || iVerb == OLEIVERB_PRIMARY || iVerb == 1) {
		m_pClientSite->ShowObject();
		if (lprcPosRect != NULL){
			RECT rc = *lprcPosRect;
			AdjustWindowRectEx(&rc, WS_OVERLAPPEDWINDOW, TRUE, 0);
			SetWindowPos(m_hwnd, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER);
		}
		ShowWindow(m_hwnd, SW_SHOW);
		SetForegroundWindow(m_hwnd);
		m_pClientSite->OnShowWindow(TRUE);
	}
	else if (iVerb == OLEIVERB_HIDE) {
		ShowWindow(m_hwnd, SW_HIDE);
		m_pClientSite->OnShowWindow(FALSE);
	}
	else
		return E_FAIL;

	return S_OK;
}

STDMETHODIMP CObject::EnumVerbs(IEnumOLEVERB **ppEnumOleVerb)
{
	return OLE_S_USEREG;
}

STDMETHODIMP CObject::Update()
{
	return E_NOTIMPL;
}

STDMETHODIMP CObject::IsUpToDate()
{
	return E_NOTIMPL;
}

STDMETHODIMP CObject::GetUserClassID(CLSID *pClsid)
{
	*pClsid = CLSID_SampleObject;

	return S_OK;
}

STDMETHODIMP CObject::GetUserType(DWORD dwFormOfType, LPOLESTR *pszUserType)
{
	return OLE_S_USEREG;
}

STDMETHODIMP CObject::SetExtent(DWORD dwDrawAspect, SIZEL *psizel)
{
	return E_NOTIMPL;
}

STDMETHODIMP CObject::GetExtent(DWORD dwDrawAspect, SIZEL *psizel)
{
	int nWidth, nHeight;

	GetSize(&nWidth, &nHeight);
	psizel->cx = nWidth;
	psizel->cy = nHeight;
	
	DPtoHIMETRIC(psizel);

	return S_OK;
}

STDMETHODIMP CObject::Advise(IAdviseSink *pAdvSink, DWORD *pdwConnection)
{
	if (m_pAdviseHolder == NULL)
		CreateOleAdviseHolder(&m_pAdviseHolder);

	return m_pAdviseHolder->Advise(pAdvSink, pdwConnection);
}

STDMETHODIMP CObject::Unadvise(DWORD dwConnection)
{
	if (m_pAdviseHolder != NULL)
		m_pAdviseHolder->Unadvise(dwConnection);

	return S_OK;
}

STDMETHODIMP CObject::EnumAdvise(IEnumSTATDATA **ppenumAdvise)
{
	if (m_pAdviseHolder != NULL)
		m_pAdviseHolder->EnumAdvise(ppenumAdvise);

	return S_OK;
}

STDMETHODIMP CObject::GetMiscStatus(DWORD dwAspect, DWORD *pdwStatus)
{
	*pdwStatus = 0;

	return S_OK;
}

STDMETHODIMP CObject::SetColorScheme(LOGPALETTE *pLogpal)
{
	return E_NOTIMPL;
}

STDMETHODIMP CObject::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium)
{
	if (pformatetcIn->cfFormat == CF_METAFILEPICT) {
		pmedium->tymed = TYMED_MFPICT;
		pmedium->pUnkForRelease = NULL;
		pmedium->hGlobal = GetMetaFileData(FALSE);
		
	}
	else if (pformatetcIn->cfFormat == CF_ENHMETAFILE) {
		pmedium->tymed = TYMED_ENHMF;
		pmedium->pUnkForRelease = NULL;
		pmedium->hEnhMetaFile = (HENHMETAFILE)GetMetaFileData(TRUE);
	}
	else
		return E_FAIL;
	
	return S_OK;
}

STDMETHODIMP CObject::GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium)
{
	return E_NOTIMPL;
}

STDMETHODIMP CObject::QueryGetData(FORMATETC *pformatetc)
{
	if (pformatetc->cfFormat == CF_METAFILEPICT || pformatetc->cfFormat == CF_ENHMETAFILE)
		return S_OK;

	return S_FALSE;
}

STDMETHODIMP CObject::GetCanonicalFormatEtc(FORMATETC *pformatectIn, FORMATETC *pformatetcOut)
{
	return DATA_S_SAMEFORMATETC;
}

STDMETHODIMP CObject::SetData(FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
{
	return E_NOTIMPL;
}

STDMETHODIMP CObject::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc)
{
	return E_NOTIMPL;
}

STDMETHODIMP CObject::DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
{
	if (m_pDataAdviseHolder == NULL)
		CreateDataAdviseHolder(&m_pDataAdviseHolder);

	return m_pDataAdviseHolder->Advise(static_cast<IDataObject *>(this), pformatetc, advf, pAdvSink, pdwConnection);
}

STDMETHODIMP CObject::DUnadvise(DWORD dwConnection)
{
	if (m_pDataAdviseHolder != NULL)
		m_pDataAdviseHolder->Unadvise(dwConnection);

	return S_OK;
}

STDMETHODIMP CObject::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
{
	if (m_pDataAdviseHolder != NULL)
		m_pDataAdviseHolder->EnumAdvise(ppenumAdvise);

	return S_OK;
}

STDMETHODIMP CObject::GetClassID(CLSID *pClassID)
{
	*pClassID = CLSID_SampleObject;

	return S_OK;
}

STDMETHODIMP CObject::IsDirty()
{
	if (m_bDirty)
		return S_OK;
	else
		return S_FALSE;
}

STDMETHODIMP CObject::InitNew(IStorage *pStg)
{
	if (m_pStream != NULL)
		return E_UNEXPECTED;

	pStg->CreateStream(m_szStreamName, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &m_pStream);

	m_pStorage = pStg;
	m_pStorage->AddRef();
	
	return S_OK;
}

STDMETHODIMP CObject::Load(IStorage *pStg)
{
	int     i;
	ULONG   uResult;
	IStream *pStream;

	if (SaveCompleted(pStg) != S_OK)
		return E_FAIL;

	m_pStream->Read(&m_nShapeCount, sizeof(int), &uResult);

	for (i = 0; i < m_nShapeCount; i++) {
		m_pStream->Read(&m_shape[i].rc, sizeof(RECT), &uResult);
		m_pStream->Read(&m_shape[i].bRectangle, sizeof(BOOL), &uResult);
	}
	
	m_bDirty = FALSE;

	return S_OK;
}

STDMETHODIMP CObject::Save(IStorage *pStgSave, BOOL fSameAsLoad)
{
	int           i;
	ULONG         uResult;
	IStream       *pStream;
	LARGE_INTEGER li = {0};
	
	m_pStream->Seek(li, STREAM_SEEK_SET, NULL);
	m_pStream->Write(&m_nShapeCount, sizeof(int), &uResult);

	for (i = 0; i < m_nShapeCount; i++) {
		m_pStream->Write(&m_shape[i].rc, sizeof(RECT), &uResult);
		m_pStream->Write(&m_shape[i].bRectangle, sizeof(BOOL), &uResult);
	}

	m_bDirty = FALSE;
	
	return S_OK;
}

STDMETHODIMP CObject::SaveCompleted(IStorage *pStgNew)
{
	if (pStgNew != NULL) {
		HandsOffStorage();

		pStgNew->OpenStream(m_szStreamName, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &m_pStream);
		if (m_pStream == NULL)
			return E_FAIL;

		m_pStorage = pStgNew;
		m_pStorage->AddRef();
	}

	return S_OK;
}

STDMETHODIMP CObject::HandsOffStorage()
{
	if (m_pStorage != NULL) {
		m_pStorage->Release();
		m_pStorage = NULL;
	}
	
	if (m_pStream != NULL) {
		m_pStream->Release();
		m_pStream = NULL;
	}

	return S_OK;
}

int CObject::Run(HINSTANCE hinst, int nCmdShow, BOOL bEmbedding)
{
	TCHAR      szAppName[] = TEXT("object");
	HWND       hwnd;
	MSG        msg;
	WNDCLASSEX wc;
	RECT       rc;
	int        nWidth, nHeight;

	wc.cbSize        = sizeof(WNDCLASSEX);
	wc.style         = 0;
	wc.lpfnWndProc   = ::WindowProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = hinst;
	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 = szAppName;
	wc.hIconSm       = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
	
	if (RegisterClassEx(&wc) == 0)
		return 0;

	m_bEmbedding = bEmbedding;
	if (bEmbedding) {
		SetRect(&rc, 0, 0, 230, 200);
		AdjustWindowRectEx(&rc, WS_OVERLAPPEDWINDOW, TRUE, 0);
		nWidth = rc.right - rc.left;
		nHeight = rc.bottom - rc.top;
	}
	else {
		nWidth = CW_USEDEFAULT;
		nHeight = CW_USEDEFAULT;
	}

	hwnd = CreateWindowEx(0, szAppName, szAppName, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, nWidth, nHeight, NULL, NULL, hinst, NULL);
	if (hwnd == NULL)
		return 0;

	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);

	while (GetMessage(&msg, NULL, 0, 0) > 0) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return (int)msg.wParam;
}

LRESULT CObject::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg) {

	case WM_CREATE: {
		HMENU hmenu;
		HMENU hmenuPopupFile;
		HMENU hmenuPopupEdit;

		hmenu  = CreateMenu();
		hmenuPopupFile = CreatePopupMenu();
		hmenuPopupEdit = CreatePopupMenu();

		InitializeMenuItem(hmenuPopupFile, TEXT("終了(&X)"), ID_EXIT, NULL);
		InitializeMenuItem(hmenuPopupEdit, TEXT("Rectangle"), ID_RECTANGLE, NULL);
		InitializeMenuItem(hmenuPopupEdit, TEXT("Ellipse"), ID_ELLIPSE, NULL);

		InitializeMenuItem(hmenu, TEXT("ファイル(&F)"), ID_FILE, hmenuPopupFile);
		InitializeMenuItem(hmenu, TEXT("編集(&E)"), ID_EDIT, hmenuPopupEdit);

		m_hwnd = hwnd;
		m_hmenu = hmenu;
		SetMenu(m_hwnd, m_hmenu);

		return 0;
	}
	
	case WM_PAINT: {
		HDC         hdc;
		PAINTSTRUCT ps;

		hdc = BeginPaint(hwnd, &ps);

		DrawShape(hdc);

		EndPaint(hwnd, &ps);

		return 0;
	}
	
	case WM_COMMAND: {
		int nId = LOWORD(wParam);

		if (nId == ID_RECTANGLE)
			m_bDrawRectangle = TRUE;
		else if (nId == ID_ELLIPSE)
			m_bDrawRectangle = FALSE;
		else if (nId == ID_EXIT)
			PostMessage(m_hwnd, WM_CLOSE, 0, 0);
		else if (nId == ID_UPDATE)
			SaveObject();
		else
			;

		return 0;
	}
	
	case WM_LBUTTONDOWN: {
		int  x, y;
		RECT rc;
		
		if (m_nShapeCount >= m_nShapeMaxCount) {
			MessageBox(hwnd, TEXT("最大数に達しました。"), TEXT("OK"), MB_OK);
			return 0;
		}

		x = LOWORD(lParam);
		y = HIWORD(lParam);
		
		SetRect(&rc, x, y, x + 70, y + 30);
		m_shape[m_nShapeCount].rc = rc;
		m_shape[m_nShapeCount].bRectangle = m_bDrawRectangle;
		m_nShapeCount++;
		
		InvalidateRect(hwnd, &rc, FALSE);
		
		if (m_bEmbedding && m_pDataAdviseHolder != NULL)
			m_pDataAdviseHolder->SendOnDataChange(static_cast<IDataObject *>(this), 0, DVASPECT_CONTENT);
		
		m_bDirty = TRUE;

		return 0;
	}

	case WM_EXITSIZEMOVE:
		if (m_bEmbedding && m_pDataAdviseHolder != NULL)
			m_pDataAdviseHolder->SendOnDataChange(static_cast<IDataObject *>(this), 0, DVASPECT_CONTENT);
		return 0;

	case WM_CLOSE:
		if (m_bEmbedding) {
			BOOL bDontSave = (BOOL)wParam;
			if (!bDontSave)
				SaveObject();
			m_pClientSite->OnShowWindow(FALSE);
			if (m_pAdviseHolder != NULL)
				m_pAdviseHolder->SendOnClose();
		}
		break;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;

	default:
		break;

	}

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

void CObject::DrawShape(HDC hdc)
{
	int  i;
	RECT rc;

	for (i = 0; i < m_nShapeCount; i++) {
		rc = m_shape[i].rc;
		if (m_shape[i].bRectangle)
			Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);
		else
			Ellipse(hdc, rc.left, rc.top, rc.right, rc.bottom);
	}
}

void CObject::GetSize(int *pnWidth, int *pnHeight)
{
	RECT rc;

	GetClientRect(m_hwnd, &rc);
	*pnWidth = rc.right - rc.left;
	*pnHeight = rc.bottom - rc.top;
}

HGLOBAL CObject::GetMetaFileData(BOOL bEnhance)
{
	HDC            hdc;
	HMETAFILE      hmf;
	HGLOBAL        hglobal;
	LPMETAFILEPICT lpmf;
	SIZEL          sizel;
	int            nWidth, nHeight;
	
	hdc = (HDC)CreateMetaFile(NULL);
	
	GetSize(&nWidth, &nHeight);

	SetMapMode(hdc, MM_ANISOTROPIC);
	SetWindowOrgEx(hdc, 0, 0, NULL);
	SetWindowExtEx(hdc, nWidth, nHeight, NULL);
	
	DrawShape(hdc);
	
	hmf = CloseMetaFile(hdc);

	sizel.cx = nWidth;
	sizel.cy = nHeight;
	DPtoHIMETRIC(&sizel);

	hglobal = GlobalAlloc(GPTR, sizeof(METAFILEPICT));
	lpmf = (LPMETAFILEPICT)GlobalLock(hglobal);
	lpmf->hMF = hmf;
	lpmf->mm = MM_ANISOTROPIC;
	lpmf->xExt = sizel.cx;
	lpmf->yExt = sizel.cy;
	GlobalUnlock(hglobal);

	if (bEnhance) {
		DWORD   dwSize;
		LPBYTE  lpData;
		HGLOBAL hglobalOld = hglobal;
		
		dwSize = GetMetaFileBitsEx(lpmf->hMF, 0, NULL);
		lpData = (LPBYTE)GlobalAlloc(GPTR, dwSize);
		GetMetaFileBitsEx(lpmf->hMF, dwSize, lpData);
		hglobal = (HGLOBAL)SetWinMetaFileBits(dwSize, lpData, NULL, lpmf);
		GlobalFree(lpData);
		GlobalFree(hglobalOld);
	}

	return hglobal;
}

void CObject::DPtoHIMETRIC(LPSIZEL lpSizel)
{
	HDC hdc;
	const int HIMETRIC_INCH = 2540;
	
	hdc = GetDC(NULL);
	lpSizel->cx = lpSizel->cx * HIMETRIC_INCH / GetDeviceCaps(hdc, LOGPIXELSX);
	lpSizel->cy = lpSizel->cy * HIMETRIC_INCH / GetDeviceCaps(hdc, LOGPIXELSY);
	ReleaseDC(NULL, hdc);
}

void CObject::SaveObject()
{
	if (m_bEmbedding) {
		m_pClientSite->SaveObject();
		if (m_pAdviseHolder != NULL)
			m_pAdviseHolder->SendOnSave();
	}
}

void CObject::InitializeMenuItem(HMENU hmenu, LPTSTR lpszItemName, int nId, HMENU hmenuSub)
{
	MENUITEMINFO mii;
	
	mii.cbSize = sizeof(MENUITEMINFO);
	mii.fMask  = MIIM_ID | MIIM_TYPE;
	mii.wID    = nId;

	if (lpszItemName != NULL) {
		mii.fType      = MFT_STRING;
		mii.dwTypeData = lpszItemName;
	}
	else
		mii.fType = MFT_SEPARATOR;

	if (hmenuSub != NULL) {
		mii.fMask   |= MIIM_SUBMENU;
		mii.hSubMenu = hmenuSub;
	}

	InsertMenuItem(hmenu, nId, FALSE, &mii);
}

戻る