EternalWindows
Silverlight / ホストサンプル

今回はSilverlightをホストするプログラムを示します。 1つ注意点として、Silverlightをホストするために使用するIXcpControlHostなどの定義は、 既定でWindows SDKに含まれていません。 このため、当初は次のURLからIDLファイルをダウンロードし、これをコンパイルすることでヘッダーファイルを生成することになると考えていました。

http://msdn.microsoft.com/ja-jp/library/cc296246(VS.95).aspx

実際に上記のURLからxcpctrl.idlをダウンロードしてコンパイルすれば分かりますが、 controlids.hが存在しないことによってコンパイルが失敗することになります。 この問題を解決する方法が分からなかったため、 今回は次のURLからダウンロードできるサンプルプログラムを利用しています。

http://code.msdn.microsoft.com/silverlightalthost/Release/ProjectReleases.aspx?ReleaseId=2968

サンプルプログラムにはCLSIDやIIDを定義したGuids.hと、IXcpControlHostなどを定義したXcp.hが存在しているため、 これを使用するようにしています。 まず、Guids.hを示します。

// Guids.h
//

#ifndef __GUIDS_H_
#define __GUIDS_H_

DEFINE_GUID(CLSID_XcpControl,
    0xDFEAF541,0xF3E1,0x4c24,0xAC,0xAC,0x99,0xC3,0x07,0x15,0x08,0x4A);

DEFINE_GUID(IID_IXcpControl,
    0x1FB839CC,0x116C,0x4C9B,0xAE,0x8E,0x3D,0xBB,0x64,0x96,0xE3,0x26);

DEFINE_GUID(IID_IXcpControlHost,
    0x1B36028E,0xB491,0x4bb2,0x85,0x84,0x8A,0x9E,0x0A,0x67,0x7D,0x6E);

DEFINE_GUID(IID_IXcpControlHost2,
    0xfb3ed7c4,0x5797,0x4b44,0x86,0x95,0x0c,0x51,0x2e,0xa2,0x7d,0x8f);

DEFINE_GUID(IID_IXcpControlDownloadCallback,
    0x2E340632,0x5D5A,0x427b,0xAC,0x31,0x30,0x3F,0x6E,0x32,0xB9,0xE8);

#endif // __GUIDS_H_

次に、xcp.hを示します。

// Xcp.h
//

#ifndef __XCP_H_
#define __XCP_H_
#include "Guids.h"

interface IXcpControl : public IDispatch {

    STDMETHOD(get_Source)(BSTR* pbstrSource) = 0;
    STDMETHOD(put_Source)(BSTR bstrSource) = 0;
};

interface IXcpControlDownloadCallback : public IUnknown {

    STDMETHOD(OnUrlDownloaded)(HRESULT hr, IStream* pStream) = 0;
};

interface IXcpControlHost : public IUnknown {

    STDMETHOD(GetHostOptions)(DWORD* pdwOptions) = 0;

    STDMETHOD(NotifyLoaded)() = 0;

    STDMETHOD(NotifyError)(BSTR bstrError, BSTR bstrSource, long nLine, long nColumn) = 0;

    STDMETHOD(InvokeHandler)(BSTR bstrName, VARIANT varParam1, VARIANT varParam2, VARIANT* pvarResult) = 0;

    STDMETHOD(GetBaseUrl)(BSTR* pbstrUrl) = 0;

    STDMETHOD(GetNamedSource)(BSTR bstrSourceName, BSTR* pbstrSource) = 0;

    STDMETHOD(DownloadUrl)(BSTR bstrUrl, IXcpControlDownloadCallback* pCallback, IStream** ppStream) = 0;

};

interface IXcpControlHost2 : public IXcpControlHost {

    STDMETHOD(GetCustomAppDomain)(IUnknown **ppCLRHost) = 0;
    STDMETHOD(GetControlVersion)(UINT *puMajorVersion, UINT *puMinorVersion) = 0;

};

#endif // __XCP_H_

最後にソースファイルを示します。

#include <windows.h>
#include <olectl.h>
#include <shlwapi.h>
#include <initguid.h>
#include "Xcp.h"

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

class CXcpControlHost : public IOleClientSite, public IOleInPlaceSite, public IDispatch, public IServiceProvider, public IXcpControlHost2
{
public:
	STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
	STDMETHODIMP_(ULONG) AddRef();
	STDMETHODIMP_(ULONG) Release();
	
	STDMETHODIMP SaveObject();
	STDMETHODIMP GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker **ppmk);
	STDMETHODIMP GetContainer(IOleContainer **ppContainer);
	STDMETHODIMP ShowObject();
	STDMETHODIMP OnShowWindow(BOOL fShow);
	STDMETHODIMP RequestNewObjectLayout();
	
	STDMETHODIMP GetWindow(HWND *phwnd);
	STDMETHODIMP ContextSensitiveHelp(BOOL fEnterMode);
	STDMETHODIMP CanInPlaceActivate();
	STDMETHODIMP OnInPlaceActivate();
	STDMETHODIMP OnUIActivate();
	STDMETHODIMP GetWindowContext(IOleInPlaceFrame **ppFrame, IOleInPlaceUIWindow **ppDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo);
	STDMETHODIMP Scroll(SIZE scrollExtant);
	STDMETHODIMP OnUIDeactivate(BOOL fUndoable);
	STDMETHODIMP OnInPlaceDeactivate();
	STDMETHODIMP DiscardUndoState();
	STDMETHODIMP DeactivateAndUndo();
	STDMETHODIMP OnPosRectChange(LPCRECT lprcPosRect);

	STDMETHODIMP GetTypeInfoCount(UINT *pctinfo);
	STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo);
	STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId);
	STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr);

	STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, void **ppv);

	STDMETHODIMP GetHostOptions(DWORD* pdwOptions);
	STDMETHODIMP NotifyLoaded();
	STDMETHODIMP NotifyError(BSTR bstrError, BSTR bstrSource, long nLine, long nColumn);
	STDMETHODIMP InvokeHandler(BSTR bstrName, VARIANT varParam1, VARIANT varParam2, VARIANT* pvarResult);
	STDMETHODIMP GetBaseUrl(BSTR* pbstrUrl);
	STDMETHODIMP GetNamedSource(BSTR bstrSourceName, BSTR* pbstrSource);
	STDMETHODIMP DownloadUrl(BSTR bstrUrl, IXcpControlDownloadCallback* pCallback, IStream** ppStream);
	STDMETHODIMP GetCustomAppDomain(IUnknown** ppAppDomain);
	STDMETHODIMP GetControlVersion(UINT *puMajorVersion, UINT *puMinorVersion);

	CXcpControlHost();
	~CXcpControlHost();
	int Run(HINSTANCE hinst, int nCmdShow);
	LRESULT WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
	BOOL Create();
	BOOL InitNew();
	HRESULT Invoke(IDispatch *pDispatch, LPOLESTR lpszName, WORD wFlags, VARIANT *pVarArray, int nArgs, VARIANT *pVarResult);

private:
	LONG       m_cRef;
	HWND       m_hwnd;
	IOleObject *m_pOleObject;
};

class CPropertyBag : public IPropertyBag
{
public:
	STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
	STDMETHODIMP_(ULONG) AddRef();
	STDMETHODIMP_(ULONG) Release();
	
	STDMETHODIMP Read(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog);
	STDMETHODIMP Write(LPCOLESTR pszPropName, VARIANT *pVar);

	CPropertyBag();

private:
	LONG m_cRef;
};

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

CXcpControlHost *g_pXcpControlHost = NULL;

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	int nResult = 0;

	OleInitialize(NULL);
	
	g_pXcpControlHost = new CXcpControlHost;
	if (g_pXcpControlHost != NULL) {
		nResult = g_pXcpControlHost->Run(hinst, nCmdShow);
		g_pXcpControlHost->Release();
	}

	OleUninitialize();

	return nResult;
}

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


// CXcpControlHost


CXcpControlHost::CXcpControlHost()
{
	m_cRef = 1;
	m_hwnd = NULL;
	m_pOleObject = NULL;
}

CXcpControlHost::~CXcpControlHost()
{
}

STDMETHODIMP CXcpControlHost::QueryInterface(REFIID riid, void **ppvObject)
{
	*ppvObject = NULL;
	
	if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IOleClientSite))
		*ppvObject = static_cast<IOleClientSite *>(this);
	else if (IsEqualIID(riid, IID_IOleWindow) || IsEqualIID(riid, IID_IOleInPlaceSite))
		*ppvObject = static_cast<IOleInPlaceSite *>(this);
	else if (IsEqualIID(riid, IID_IDispatch))
		*ppvObject = static_cast<IDispatch *>(this);
	else if (IsEqualIID(riid, IID_IServiceProvider))
		*ppvObject = static_cast<IServiceProvider *>(this);
	else if (IsEqualIID(riid, IID_IXcpControlHost) || IsEqualIID(riid, IID_IXcpControlHost2))
		*ppvObject = static_cast<IXcpControlHost2 *>(this);
	else
		return E_NOINTERFACE;

	AddRef();
	
	return S_OK;
}

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

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

	return m_cRef;
}

STDMETHODIMP CXcpControlHost::SaveObject()
{
	return E_NOTIMPL;
}

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

STDMETHODIMP CXcpControlHost::GetContainer(IOleContainer **ppContainer)
{
	*ppContainer = NULL;

	return E_NOINTERFACE;
}

STDMETHODIMP CXcpControlHost::ShowObject()
{
	return S_OK;
}

STDMETHODIMP CXcpControlHost::OnShowWindow(BOOL fShow)
{
	return S_OK;
}

STDMETHODIMP CXcpControlHost::RequestNewObjectLayout()
{
	return E_NOTIMPL;
}

STDMETHODIMP CXcpControlHost::GetWindow(HWND *phwnd)
{
	*phwnd = m_hwnd;

	return S_OK;
}

STDMETHODIMP CXcpControlHost::ContextSensitiveHelp(BOOL fEnterMode)
{
	return E_NOTIMPL;
}

STDMETHODIMP CXcpControlHost::CanInPlaceActivate()
{
	return S_OK;
}

STDMETHODIMP CXcpControlHost::OnInPlaceActivate()
{
	return S_OK;
}

STDMETHODIMP CXcpControlHost::OnUIActivate()
{
	return S_OK;
}

STDMETHODIMP CXcpControlHost::GetWindowContext(IOleInPlaceFrame **ppFrame, IOleInPlaceUIWindow **ppDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo)
{
	*ppFrame = NULL;
	*ppDoc = NULL;
	
	GetClientRect(m_hwnd, lprcPosRect);
	GetClientRect(m_hwnd, lprcClipRect);

	return S_OK;
}

STDMETHODIMP CXcpControlHost::Scroll(SIZE scrollExtant)
{
	return E_NOTIMPL;
}

STDMETHODIMP CXcpControlHost::OnUIDeactivate(BOOL fUndoable)
{
	return E_NOTIMPL;
}

STDMETHODIMP CXcpControlHost::OnInPlaceDeactivate()
{
	return E_NOTIMPL;
}

STDMETHODIMP CXcpControlHost::DiscardUndoState()
{
	return E_NOTIMPL;
}

STDMETHODIMP CXcpControlHost::DeactivateAndUndo()
{
	return E_NOTIMPL;
}

STDMETHODIMP CXcpControlHost::OnPosRectChange(LPCRECT lprcPosRect)
{
	return S_OK;
}

STDMETHODIMP CXcpControlHost::GetTypeInfoCount(UINT *pctinfo)
{
	*pctinfo = 0;
	
	return S_OK;
}

STDMETHODIMP CXcpControlHost::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
{
	return E_NOTIMPL;
}

STDMETHODIMP CXcpControlHost::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
{
	return E_NOTIMPL;
}

STDMETHODIMP CXcpControlHost::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
	if (dispIdMember == DISPID_AMBIENT_USERMODE) {
		pVarResult->vt = VT_BOOL;
		pVarResult->boolVal = VARIANT_FALSE;
	}
	else
		return DISP_E_MEMBERNOTFOUND;

	return S_OK;
}

STDMETHODIMP CXcpControlHost::QueryService(REFGUID guidService, REFIID riid, void **ppv)
{
	return QueryInterface(riid, ppv); 
}

STDMETHODIMP CXcpControlHost::GetHostOptions(DWORD* pdwOptions)
{
	*pdwOptions = 0;

	return S_OK;
}

STDMETHODIMP CXcpControlHost::NotifyLoaded()
{
	return S_OK;
}

STDMETHODIMP CXcpControlHost::NotifyError(BSTR bstrError, BSTR bstrSource, long nLine, long nColumn)
{
	return S_OK;
}

STDMETHODIMP CXcpControlHost::InvokeHandler(BSTR bstrName, VARIANT varParam1, VARIANT varParam2, VARIANT* pvarResult)
{
	IDispatch *pMouseButtonEventArgs = varParam1.pdispVal;
	IDispatch *pRectangle = varParam2.pdispVal;
	IDispatch *pSolidColorBrush;
	BOOL      bPressCtrl;
	VARIANT   var, varResult;

	if (lstrcmpW(bstrName, L"RectangleClicked") == 0) {
		VariantInit(&varResult);
		Invoke(pMouseButtonEventArgs, L"Ctrl", DISPATCH_PROPERTYGET, NULL, 0, &varResult);
		bPressCtrl = varResult.boolVal;

		VariantInit(&varResult);
		Invoke(pRectangle, L"Fill", DISPATCH_PROPERTYGET, NULL, 0, &varResult);
		pSolidColorBrush = varResult.pdispVal;

		var.vt = VT_I4;
		var.lVal = bPressCtrl ? 0xff0000ff : 0xff00ff00;
		Invoke(pSolidColorBrush, L"color", DISPATCH_PROPERTYPUT, &var, 1, &varResult);
		pSolidColorBrush->Release();
	}

	return S_OK;
}

STDMETHODIMP CXcpControlHost::GetBaseUrl(BSTR* pbstrUrl)
{
	int   nLen;
	WCHAR szCurrentDirectory[MAX_PATH];

	GetCurrentDirectoryW(MAX_PATH, szCurrentDirectory);

	nLen = lstrlenW(szCurrentDirectory);
	szCurrentDirectory[nLen] = '\\';
	szCurrentDirectory[nLen + 1] = '\0';
	
	*pbstrUrl = SysAllocString(szCurrentDirectory);

	return S_OK;
}

STDMETHODIMP CXcpControlHost::GetNamedSource(BSTR bstrSourceName, BSTR* pbstrSource)
{
	return E_NOTIMPL;
}

STDMETHODIMP CXcpControlHost::DownloadUrl(BSTR bstrUrl, IXcpControlDownloadCallback* pCallback, IStream** ppStream)
{
	if (lstrcmpW(PathFindFileName(bstrUrl), L"sample.xaml") == 0) {
		ULONG         uWritten;
		LARGE_INTEGER li;
		WCHAR         szXAML[] = 
			L"<Canvas "
				L"xmlns=\"http://schemas.microsoft.com/client/2007\" "
				L"xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\">"
				L"<Rectangle Width=\"200\" Height=\"200\" Fill=\"Red\" MouseLeftButtonDown=\"RectangleClicked\"/>"
			L"</Canvas>";
		
		CreateStreamOnHGlobal(NULL, TRUE, ppStream);
		(*ppStream)->Write((char *)szXAML, lstrlenW(szXAML) * sizeof(WCHAR), &uWritten);
		
		li.HighPart = 0;
		li.LowPart = 0;
		(*ppStream)->Seek(li, STREAM_SEEK_SET, NULL);

		return S_OK;
	}

	return S_FALSE;
}

STDMETHODIMP CXcpControlHost::GetCustomAppDomain(IUnknown** ppAppDomain)
{
	return E_NOTIMPL;
}

STDMETHODIMP CXcpControlHost::GetControlVersion(UINT *puMajorVersion, UINT *puMinorVersion)
{
	*puMajorVersion = 3;
	*puMinorVersion = 0;

	return S_OK;
}

int CXcpControlHost::Run(HINSTANCE hinst, int nCmdShow)
{
	TCHAR      szAppName[] = TEXT("sample");
	HWND       hwnd;
	MSG        msg;
	WNDCLASSEX wc;

	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;

	hwnd = CreateWindowEx(0, szAppName, szAppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 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 CXcpControlHost::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg) {

	case WM_CREATE:
		m_hwnd = hwnd;
		if (!Create())
			return -1;
		return 0;

	case WM_DESTROY:
		if (m_pOleObject != NULL) {
			RECT rc;
			SetRectEmpty(&rc);
			m_pOleObject->DoVerb(OLEIVERB_HIDE, NULL, NULL, 0, m_hwnd, &rc);
			m_pOleObject->Close(OLECLOSE_NOSAVE);
			m_pOleObject->SetClientSite(NULL);
			m_pOleObject->Release();
		}
		PostQuitMessage(0);
		return 0;

	default:
		break;

	}

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

BOOL CXcpControlHost::Create()
{
	RECT              rc;
	HRESULT           hr;
	IOleInPlaceObject *pOleInPlaceObject;

	hr = CoCreateInstance(CLSID_XcpControl, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_pOleObject));
	if (FAILED(hr))
		return FALSE;

	m_pOleObject->SetClientSite(static_cast<IOleClientSite *>(this));
	InitNew();

	SetRectEmpty(&rc);
	hr = m_pOleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, static_cast<IOleClientSite *>(this), 0, m_hwnd, &rc);
	if (FAILED(hr))
		return FALSE;

	m_pOleObject->QueryInterface(IID_PPV_ARGS(&pOleInPlaceObject));
	SetRect(&rc, 100, 100, 400, 400);
	pOleInPlaceObject->SetObjectRects(&rc, &rc);
	pOleInPlaceObject->Release();

	return TRUE;
}

BOOL CXcpControlHost::InitNew()
{
	IPersistPropertyBag *pPersistPropertyBag;
	IPropertyBag        *pPropertyBag = new CPropertyBag;
	
	m_pOleObject->QueryInterface(IID_PPV_ARGS(&pPersistPropertyBag));
	pPersistPropertyBag->Load(pPropertyBag, NULL);
	pPersistPropertyBag->Release();

	return TRUE;
}

HRESULT CXcpControlHost::Invoke(IDispatch *pDispatch, LPOLESTR lpszName, WORD wFlags, VARIANT *pVarArray, int nArgs, VARIANT *pVarResult)
{
	DISPPARAMS dispParams;
	DISPID     dispid;
	DISPID     dispidName = DISPID_PROPERTYPUT;
	HRESULT    hr;
	
	hr = pDispatch->GetIDsOfNames(IID_NULL, &lpszName, 1, LOCALE_USER_DEFAULT, &dispid);
	if (FAILED(hr))
		return hr;
	
	dispParams.cArgs = nArgs;
	dispParams.rgvarg = pVarArray;
	if (wFlags & DISPATCH_PROPERTYPUT) {
		dispParams.cNamedArgs = 1;
		dispParams.rgdispidNamedArgs = &dispidName;
	}
	else {
		dispParams.cNamedArgs = 0;
		dispParams.rgdispidNamedArgs = NULL;
	}

	hr = pDispatch->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, wFlags, &dispParams, pVarResult, NULL, NULL);

	return hr;
}


// CPropertyBag


CPropertyBag::CPropertyBag()
{
	m_cRef = 1;
}

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

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

	AddRef();
	
	return S_OK;
}

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

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

	return m_cRef;
}

STDMETHODIMP CPropertyBag::Read(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog)
{
	VARIANT var;
	BSTR bstr;

	if (lstrcmpW(pszPropName, L"Source") == 0) {
		pVar->vt = VT_BSTR;
		pVar->bstrVal = SysAllocString(L"sample.xaml");
	}
	else if (lstrcmpW(pszPropName, L"Background") == 0) {
		pVar->vt = VT_BSTR;
		pVar->bstrVal = SysAllocString(L"gray");
	}
	else if (lstrcmpW(pszPropName, L"Windowless") == 0) {
		pVar->vt = VT_BOOL;
		pVar->boolVal = VARIANT_FALSE;
	}
	else
		return E_FAIL;

	return S_OK;
}

STDMETHODIMP CPropertyBag::Write(LPCOLESTR pszPropName, VARIANT *pVar)
{
	return E_NOTIMPL;
}

戻る