|
| 1 | +/* |
| 2 | + +----------------------------------------------------------------------+ |
| 3 | + | Copyright (c) The PHP Group | |
| 4 | + +----------------------------------------------------------------------+ |
| 5 | + | This source file is subject to version 3.01 of the PHP license, | |
| 6 | + | that is bundled with this package in the file LICENSE, and is | |
| 7 | + | available through the world-wide-web at the following url: | |
| 8 | + | https://www.php.net/license/3_01.txt | |
| 9 | + | If you did not receive a copy of the PHP license and are unable to | |
| 10 | + | obtain it through the world-wide-web, please send a note to | |
| 11 | + | license@php.net so we can mail you a copy immediately. | |
| 12 | + +----------------------------------------------------------------------+ |
| 13 | + | Author: Christoph M. Becker <cmb@php.net> | |
| 14 | + | Based on: <https://thrysoee.dk/InsideCOM+/> | |
| 15 | + +----------------------------------------------------------------------+ |
| 16 | + */ |
| 17 | + |
| 18 | +#include "comtest.h" // Generated by MIDL |
| 19 | + |
| 20 | +long g_cComponents = 0; |
| 21 | +long g_cLocks = 0; |
| 22 | + |
| 23 | +class CDocument : public IDocument, IPersistStream |
| 24 | +{ |
| 25 | +public: |
| 26 | + // IUnknown |
| 27 | + STDMETHODIMP_(ULONG) AddRef(); |
| 28 | + STDMETHODIMP_(ULONG) Release(); |
| 29 | + STDMETHODIMP QueryInterface(REFIID riid, void** ppv); |
| 30 | + |
| 31 | + // IDispatch |
| 32 | + STDMETHODIMP GetTypeInfoCount(UINT* pCountTypeInfo); |
| 33 | + STDMETHODIMP GetTypeInfo(UINT iTypeInfo, LCID lcid, ITypeInfo** ppITypeInfo); |
| 34 | + STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId); |
| 35 | + STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, |
| 36 | + VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr); |
| 37 | + |
| 38 | + // IDocument |
| 39 | + STDMETHODIMP get_Content(BSTR* retvalue); |
| 40 | + STDMETHODIMP put_Content(BSTR newvalue); |
| 41 | + |
| 42 | + // IPersist |
| 43 | + STDMETHODIMP GetClassID(CLSID *pClassID); |
| 44 | + |
| 45 | + // IPersistStream |
| 46 | + STDMETHODIMP IsDirty( void); |
| 47 | + STDMETHODIMP Load(IStream *pStm); |
| 48 | + STDMETHODIMP Save(IStream *pStm, BOOL fClearDirty); |
| 49 | + STDMETHODIMP GetSizeMax(ULARGE_INTEGER *pcbSize); |
| 50 | + |
| 51 | + CDocument() : m_content(SysAllocString(L"")), m_cRef(1) { g_cComponents++; } |
| 52 | + ~CDocument() { SysFreeString(m_content); g_cComponents--; } |
| 53 | + HRESULT Init(void); |
| 54 | + |
| 55 | +private: |
| 56 | + BSTR m_content; |
| 57 | + ULONG m_cRef; |
| 58 | + ITypeInfo* m_pTypeInfo; |
| 59 | + BOOL m_dirty; |
| 60 | +}; |
| 61 | + |
| 62 | +ULONG CDocument::AddRef() |
| 63 | +{ |
| 64 | + return ++m_cRef; |
| 65 | +} |
| 66 | + |
| 67 | +ULONG CDocument::Release() |
| 68 | +{ |
| 69 | + if (--m_cRef != 0) { |
| 70 | + return m_cRef; |
| 71 | + } |
| 72 | + m_pTypeInfo->Release(); |
| 73 | + delete this; |
| 74 | + return 0; |
| 75 | +} |
| 76 | + |
| 77 | +HRESULT CDocument::QueryInterface(REFIID riid, void** ppv) |
| 78 | +{ |
| 79 | + if (riid == IID_IUnknown) { |
| 80 | + *ppv = static_cast<IDocument*>(this); |
| 81 | + } else if (riid == IID_IDocument) { |
| 82 | + *ppv = static_cast<IDocument*>(this); |
| 83 | + } else if (riid == IID_IDispatch) { |
| 84 | + *ppv = static_cast<IDispatch*>(this); |
| 85 | + } else if (riid == IID_IPersistStream) { |
| 86 | + *ppv = static_cast<IPersistStream*>(this); |
| 87 | + } else { |
| 88 | + *ppv = NULL; |
| 89 | + return E_NOINTERFACE; |
| 90 | + } |
| 91 | + AddRef(); |
| 92 | + return S_OK; |
| 93 | +} |
| 94 | + |
| 95 | +HRESULT CDocument::GetTypeInfoCount(UINT* pCountTypeInfo) |
| 96 | +{ |
| 97 | + *pCountTypeInfo = 1; |
| 98 | + return S_OK; |
| 99 | +} |
| 100 | + |
| 101 | +HRESULT CDocument::GetTypeInfo(UINT iTypeInfo, LCID lcid, ITypeInfo** ppITypeInfo) |
| 102 | +{ |
| 103 | + (void) lcid; |
| 104 | + *ppITypeInfo = NULL; |
| 105 | + if (iTypeInfo != 0) { |
| 106 | + return DISP_E_BADINDEX; |
| 107 | + } |
| 108 | + m_pTypeInfo->AddRef(); |
| 109 | + *ppITypeInfo = m_pTypeInfo; |
| 110 | + return S_OK; |
| 111 | +} |
| 112 | + |
| 113 | +HRESULT CDocument::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) |
| 114 | +{ |
| 115 | + (void) lcid; |
| 116 | + if (riid != IID_NULL) { |
| 117 | + return DISP_E_UNKNOWNINTERFACE; |
| 118 | + } |
| 119 | + return DispGetIDsOfNames(m_pTypeInfo, rgszNames, cNames, rgDispId); |
| 120 | +} |
| 121 | + |
| 122 | +HRESULT CDocument::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, |
| 123 | + VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) |
| 124 | +{ |
| 125 | + (void) lcid; |
| 126 | + if (riid != IID_NULL) { |
| 127 | + return DISP_E_UNKNOWNINTERFACE; |
| 128 | + } |
| 129 | + return DispInvoke(this, m_pTypeInfo, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); |
| 130 | +} |
| 131 | + |
| 132 | +HRESULT CDocument::get_Content(BSTR* retvalue) |
| 133 | +{ |
| 134 | + *retvalue = SysAllocString(m_content); |
| 135 | + return S_OK; |
| 136 | +} |
| 137 | + |
| 138 | +HRESULT CDocument::put_Content(BSTR newvalue) |
| 139 | +{ |
| 140 | + SysFreeString(m_content); |
| 141 | + m_content = SysAllocString(newvalue); |
| 142 | + return S_OK; |
| 143 | +} |
| 144 | + |
| 145 | +HRESULT CDocument::Init(void) |
| 146 | +{ |
| 147 | + ITypeLib* pTypeLib; |
| 148 | + if (FAILED(LoadRegTypeLib(LIBID_ComTest, 1, 0, LANG_NEUTRAL, &pTypeLib))) { |
| 149 | + return E_FAIL; |
| 150 | + } |
| 151 | + HRESULT hr = pTypeLib->GetTypeInfoOfGuid(IID_IDocument, &m_pTypeInfo); |
| 152 | + if (FAILED(hr)) { |
| 153 | + pTypeLib->Release(); |
| 154 | + return hr; |
| 155 | + } |
| 156 | + |
| 157 | + pTypeLib->Release(); |
| 158 | + return S_OK; |
| 159 | +} |
| 160 | + |
| 161 | +HRESULT CDocument::GetClassID(CLSID *pClassID) |
| 162 | +{ |
| 163 | + *pClassID = CLSID_Document; |
| 164 | + return S_OK; |
| 165 | +} |
| 166 | + |
| 167 | +HRESULT CDocument::IsDirty(void) |
| 168 | +{ |
| 169 | + return m_dirty ? S_OK : S_FALSE; |
| 170 | +} |
| 171 | + |
| 172 | +HRESULT CDocument::Load(IStream *pStm) |
| 173 | +{ |
| 174 | + ULONG read = 0; |
| 175 | + ULONG cbSize; |
| 176 | + |
| 177 | + if (FAILED(pStm->Read(&cbSize, sizeof cbSize, &read))) { |
| 178 | + return S_FALSE; |
| 179 | + } |
| 180 | + if (!SysReAllocStringLen(&m_content, NULL, cbSize)) { |
| 181 | + return S_FALSE; |
| 182 | + } |
| 183 | + if (FAILED(pStm->Read(m_content, cbSize, &read))) { |
| 184 | + // we may have garbage in m_content, but don't mind |
| 185 | + return S_FALSE; |
| 186 | + } |
| 187 | + m_dirty = FALSE; |
| 188 | + return S_OK; |
| 189 | +} |
| 190 | + |
| 191 | +HRESULT CDocument::Save(IStream *pStm, BOOL fClearDirty) |
| 192 | +{ |
| 193 | + ULONG written = 0; |
| 194 | + ULONG cbSize = SysStringByteLen(m_content); |
| 195 | + HRESULT hr; |
| 196 | + if (FAILED(hr = pStm->Write(&cbSize, sizeof cbSize, &written))) { |
| 197 | + return S_FALSE; |
| 198 | + } |
| 199 | + if (FAILED(hr = pStm->Write(m_content, cbSize, &written))) { |
| 200 | + return S_FALSE; |
| 201 | + } |
| 202 | + |
| 203 | + if (fClearDirty) { |
| 204 | + m_dirty = FALSE; |
| 205 | + } |
| 206 | + |
| 207 | + return S_OK; |
| 208 | +} |
| 209 | + |
| 210 | +HRESULT CDocument::GetSizeMax(ULARGE_INTEGER *pcbSize) |
| 211 | +{ |
| 212 | + (*pcbSize).QuadPart = sizeof(ULONG) + SysStringByteLen(m_content); |
| 213 | + return S_OK; |
| 214 | +} |
| 215 | + |
| 216 | +class CDocumentFactory : public IClassFactory |
| 217 | +{ |
| 218 | +public: |
| 219 | + // IUnknown |
| 220 | + STDMETHODIMP_(ULONG) AddRef(); |
| 221 | + STDMETHODIMP_(ULONG) Release(); |
| 222 | + STDMETHODIMP QueryInterface(REFIID riid, void** ppv); |
| 223 | + |
| 224 | + // IClassFactory |
| 225 | + STDMETHODIMP CreateInstance(IUnknown* pUnknownOuter, REFIID riid, void** ppv); |
| 226 | + STDMETHODIMP LockServer(BOOL bLock); |
| 227 | + |
| 228 | + CDocumentFactory() : m_cRef(1) { g_cLocks++; } |
| 229 | + ~CDocumentFactory() { g_cLocks--; } |
| 230 | + |
| 231 | +private: |
| 232 | + ULONG m_cRef; |
| 233 | +}; |
| 234 | + |
| 235 | +ULONG CDocumentFactory::AddRef() |
| 236 | +{ |
| 237 | + return ++m_cRef; |
| 238 | +} |
| 239 | + |
| 240 | +ULONG CDocumentFactory::Release() |
| 241 | +{ |
| 242 | + if (--m_cRef != 0) { |
| 243 | + return m_cRef; |
| 244 | + } |
| 245 | + delete this; |
| 246 | + return 0; |
| 247 | +} |
| 248 | + |
| 249 | +HRESULT CDocumentFactory::QueryInterface(REFIID riid, void** ppv) |
| 250 | +{ |
| 251 | + if (riid == IID_IUnknown) { |
| 252 | + *ppv = (IUnknown*)this; |
| 253 | + } else if (riid == IID_IClassFactory) { |
| 254 | + *ppv = (IClassFactory*)this; |
| 255 | + } else { |
| 256 | + *ppv = NULL; |
| 257 | + return E_NOINTERFACE; |
| 258 | + } |
| 259 | + AddRef(); |
| 260 | + return S_OK; |
| 261 | +} |
| 262 | + |
| 263 | +HRESULT CDocumentFactory::CreateInstance(IUnknown *pUnknownOuter, REFIID riid, void** ppv) |
| 264 | +{ |
| 265 | + if (pUnknownOuter != NULL) { |
| 266 | + return CLASS_E_NOAGGREGATION; |
| 267 | + } |
| 268 | + |
| 269 | + CDocument *pDocument = new CDocument; |
| 270 | + if (pDocument == NULL) { |
| 271 | + return E_OUTOFMEMORY; |
| 272 | + } |
| 273 | + |
| 274 | + HRESULT hr; |
| 275 | + if (FAILED(hr = pDocument->Init())) { |
| 276 | + return hr; |
| 277 | + } |
| 278 | + hr = pDocument->QueryInterface(riid, ppv); |
| 279 | + pDocument->Release(); |
| 280 | + return hr; |
| 281 | +} |
| 282 | + |
| 283 | +HRESULT CDocumentFactory::LockServer(BOOL bLock) |
| 284 | +{ |
| 285 | + if (bLock) { |
| 286 | + g_cLocks++; |
| 287 | + } else { |
| 288 | + g_cLocks --; |
| 289 | + } |
| 290 | + return S_OK; |
| 291 | +} |
| 292 | + |
| 293 | +HRESULT __stdcall DllCanUnloadNow() |
| 294 | +{ |
| 295 | + if (g_cLocks == 0) { |
| 296 | + return S_OK; |
| 297 | + } else { |
| 298 | + return S_FALSE; |
| 299 | + } |
| 300 | +} |
| 301 | + |
| 302 | +HRESULT __stdcall DllGetClassObject(REFCLSID clsid, REFIID riid, void** ppv) |
| 303 | +{ |
| 304 | + if (clsid != CLSID_Document) { |
| 305 | + return CLASS_E_CLASSNOTAVAILABLE; |
| 306 | + } |
| 307 | + |
| 308 | + CDocumentFactory* pFactory = new CDocumentFactory; |
| 309 | + if (pFactory == NULL) { |
| 310 | + return E_OUTOFMEMORY; |
| 311 | + } |
| 312 | + |
| 313 | + // riid is probably IID_IClassFactory. |
| 314 | + HRESULT hr = pFactory->QueryInterface(riid, ppv); |
| 315 | + pFactory->Release(); |
| 316 | + return hr; |
| 317 | +} |
0 commit comments