📄 contain.cpp
字号:
//*******************************************************************
//*******************************************************************
//*** REUSE through Containment....
//*******************************************************************
//*******************************************************************
//-------------------------------------------------------------------
// Required macros
//-------------------------------------------------------------------
#define UNICODE // UNICODE
#define _WIN32_DCOM // DCOM
//-------------------------------------------------------------------
// includes
//-------------------------------------------------------------------
#include <assert.h>
#include <stdio.h>
#include <windows.h>
#include <initguid.h>
#include "..\..\..\idl\ocr.h" // the reused intefaces
#include "..\idl\contain.h" // the interface we're implementing
//-------------------------------------------------------------------
// global event telling use wen to shutdown our application
//-------------------------------------------------------------------
HANDLE g_hExitEvent;
//-------------------------------------------------------------------
// Component Level Reference count for the lifetime managment of
// the whole component.
// These specific implementations are used for out-of-process servers
// There's a pair of functions like these that are used for
// in-process servers.
//-------------------------------------------------------------------
inline ULONG ComponentAddRef()
{
ULONG ul = CoAddRefServerProcess();
wprintf(TEXT("ComponentAddRef(%ld)\n"), ul);
return ul ;
}
inline ULONG ComponentRelease()
{
ULONG ul = CoReleaseServerProcess();
// wait 3 second to test for REGCLS_MULTIPLEUSE
// Sleep(3000);
wprintf(TEXT("ComponentRelease(%ld)\n"), ul);
if (ul==0) {
SetEvent(g_hExitEvent);
}
return ul ;
}
//*******************************************************************
//*******************************************************************
//*** UTILITY FUNCTIONS
//*******************************************************************
//*******************************************************************
void DisplayStatus(wchar_t *pwszMsg, HRESULT hr)
{
if (hr == S_OK) {
wprintf(TEXT("%s\n"), pwszMsg);
return;
}
if (HRESULT_FACILITY(hr) == FACILITY_WINDOWS) {
hr = HRESULT_CODE(hr);
}
wchar_t *pwszStatus;
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
hr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&pwszStatus,
0,
NULL );
wprintf(TEXT("%s: %s (ECode: %lx)\n"), pwszMsg, pwszStatus, hr);
LocalFree(pwszStatus);
}
//-------------------------------------------------------------------
// Given a unicode string, get the number of bytes needed to host it
//-------------------------------------------------------------------
inline long ByteLen(wchar_t *pwsz)
{
return (sizeof(wchar_t)*(wcslen(pwsz)+1));
}
//-------------------------------------------------------------------
// Automatic registration; for out-of-process server support the
// -regserver option
//-------------------------------------------------------------------
void RegisterComponent()
{
wchar_t wszKey[MAX_PATH];
wchar_t wszValue[MAX_PATH];
HKEY hKey = 0;
// HKEY_CLASSES_ROOT\CLSID\{80DA2D21-C466-11d1-83B4-006008CDD9AE}
// @="Dictionary"
wcscpy(wszKey, TEXT("CLSID\\{80DA2D21-C466-11d1-83B4-006008CDD9AE}"));
RegCreateKey(HKEY_CLASSES_ROOT, wszKey, &hKey);
wcscpy(wszValue, TEXT("Dictionary"));
RegSetValueEx(hKey, 0, 0, REG_SZ, (BYTE*)wszValue, ByteLen(wszValue));
// "AppID"="{63B53C11-C46B-11d1-83B4-006008CDD9AE}"
wcscpy(wszValue, TEXT("{63B53C11-C46B-11d1-83B4-006008CDD9AE}"));
RegSetValueEx(hKey, TEXT("AppID"), 0, REG_SZ,
(BYTE*)wszValue, ByteLen(wszValue));
RegCloseKey(hKey);
// HKEY_CLASSES_ROOT\CLSID\{80DA2D21-C466-11d1-83B4-006008CDD9AE}\LocalServer32
// @="...path...\contain.exe"
wcscpy(wszKey, TEXT("CLSID\\{80DA2D21-C466-11d1-83B4-006008CDD9AE}\\")
TEXT("LocalServer32"));
RegCreateKey(HKEY_CLASSES_ROOT, wszKey, &hKey);
GetModuleFileName(0, wszValue, MAX_PATH);
RegSetValueEx(hKey, 0, 0, REG_SZ, (BYTE*)wszValue, ByteLen(wszValue));
RegCloseKey(hKey);
// HKEY_CLASSES_ROOT\AppID\contain.exe
// "AppID"="{63B53C11-C46B-11d1-83B4-006008CDD9AE}"
wcscpy(wszKey, TEXT("AppID\\contain.exe"));
RegCreateKey(HKEY_CLASSES_ROOT, wszKey, &hKey);
wcscpy(wszValue, TEXT("{63B53C11-C46B-11d1-83B4-006008CDD9AE}"));
RegSetValueEx(hKey, TEXT("AppID"), 0, REG_SZ,
(BYTE*)wszValue, ByteLen(wszValue));
RegCloseKey(hKey);
// HKEY_CLASSES_ROOT\AppID\{63B53C11-C46B-11d1-83B4-006008CDD9AE}
// @="Dictionary"
wcscpy(wszKey, TEXT("AppID\\{63B53C11-C46B-11d1-83B4-006008CDD9AE}"));
RegCreateKey(HKEY_CLASSES_ROOT, wszKey, &hKey);
wcscpy(wszValue, TEXT("Dictionary"));
RegSetValueEx(hKey, 0, 0, REG_SZ,
(BYTE*)wszValue, ByteLen(wszValue));
RegCloseKey(hKey);
}
//-------------------------------------------------------------------
// Automatic unregistration; for out-of-process server support the
// -unregserver option
//-------------------------------------------------------------------
void UnregisterComponent()
{
long lRc = 0 ;
lRc = RegDeleteKey(HKEY_CLASSES_ROOT, TEXT("CLSID\\")
TEXT("{80DA2D21-C466-11d1-83B4-006008CDD9AE}\\")
TEXT("LocalServer32"));
DisplayStatus(TEXT("Unregistered LocalServer32"), lRc);
lRc = RegDeleteKey(HKEY_CLASSES_ROOT, TEXT("CLSID\\")
TEXT("{80DA2D21-C466-11d1-83B4-006008CDD9AE}"));
DisplayStatus(TEXT("Unregistered CLSID"), lRc);
lRc = RegDeleteKey(HKEY_CLASSES_ROOT, TEXT("AppID\\")
TEXT("{63B53C11-C46B-11d1-83B4-006008CDD9AE}"));
DisplayStatus(TEXT("Unregistered AppID"), lRc);
lRc = RegDeleteKey(HKEY_CLASSES_ROOT, TEXT("AppID\\contain.exe"));
DisplayStatus(TEXT("Unregistered contain.exe"), lRc);
}
//*******************************************************************
//*******************************************************************
//*** CONTAINMENT...
//*** Class CoDictionary - A component object that implements two
//*** interfaces: IDictionary and ISpell.
//*** We are using containment to reuse the functionality of ISpell
//*** that's been implemented by the inner object.
//*** Therefore the ISpell methods implemented in this object
//*** will forward all calls to the inner object, thus reusing
//*** already implemented functionality.
//*******************************************************************
//*******************************************************************
class CoDictionary : public IDictionary, public ISpell {
public:
// constructors/destructors
// Code to support containment
CoDictionary() : m_lRefCount(0), m_pISpell(0)
{
ComponentAddRef();
// creating the inner object
CreateInnerObject();
}
// Code to support containment
~CoDictionary()
{
// releasing the interface of the inner object
// that we've been keeping for reuse
if (m_pISpell) { m_pISpell->Release(); }
ComponentRelease();
}
// The factory will call this method to actually
// create this object
static HRESULT CreateObject(LPUNKNOWN pUnkOuter, REFIID riid,
void** ppv);
public:
// IUnknown Methods
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
STDMETHODIMP_(ULONG) AddRef(void)
{ return InterlockedIncrement(&m_lRefCount); }
STDMETHODIMP_(ULONG) Release(void)
{
long lCount = InterlockedDecrement(&m_lRefCount);
if (lCount == 0) { delete this; }
return lCount;
}
// IDictionary
STDMETHODIMP LookUp()
{ wprintf(TEXT("Lookup success...\n")); return S_OK; }
// ISpell methods
// Look... we're reusing the implementation an inner
// binary object. Basically forwarding the calls...
STDMETHODIMP Check(wchar_t *pszWord, PossibleWords *pWords)
{ return m_pISpell->Check(pszWord, pWords); }
private:
// function to create the inner object for reuse
void CreateInnerObject();
private:
LONG m_lRefCount;
// we specifically want to reuse the ISpell interface of the
// inner object -- using the containment technique.
// keeping a reference to the inner, reused object
ISpell *m_pISpell ;
};
//-------------------------------------------------------------------
// Creating the inner object for reuse...
// CoMyEngine::CreateInnerObject
//-------------------------------------------------------------------
void CoDictionary::CreateInnerObject()
{
MULTI_QI mqi[] = { {&IID_ISpell, NULL, S_OK} };
//------------------------------------------------------------
// Notice NULL as the second argument... reuse by containment!
//------------------------------------------------------------
HRESULT hr = CoCreateInstanceEx(CLSID_OcrEngine,
NULL, // Reuse by CONTAINMENT
CLSCTX_SERVER,
NULL,
sizeof(mqi)/sizeof(mqi[0]),
mqi);
if (SUCCEEDED(hr) && SUCCEEDED(mqi[0].hr)) {
m_pISpell = reinterpret_cast<ISpell *>(mqi[0].pItf);
} else {
DisplayStatus(TEXT("Failed to create inner object..."), S_OK);
assert(false);
}
}
//-------------------------------------------------------------------
// CoDictionary::CreateObject - static function to create an
// CoDictionary object
//-------------------------------------------------------------------
HRESULT CoDictionary::CreateObject(LPUNKNOWN pUnkOuter,
REFIID riid,
void** ppv)
{
*ppv = NULL;
// CoDictionary doesn't support aggregation
if (pUnkOuter != NULL) { return CLASS_E_NOAGGREGATION; }
CoDictionary * pDictionary = new CoDictionary;
if (pDictionary == NULL) { return E_OUTOFMEMORY; }
HRESULT hr = pDictionary->QueryInterface(riid, ppv);
if (FAILED(hr)) { delete pDictionary; }
return hr;
}
//-------------------------------------------------------------------
// CoDictionary::QueryInterface
//-------------------------------------------------------------------
STDMETHODIMP
CoDictionary::QueryInterface(REFIID riid, void** ppv)
{
if (ppv==NULL) { return E_INVALIDARG; }
if (riid==IID_IUnknown) {
*ppv= static_cast<IDictionary *>(this);
} else if (riid==IID_IDictionary) {
*ppv= static_cast<IDictionary *>(this);
} else if (riid==IID_ISpell) {
*ppv= static_cast<ISpell *>(this);
} else {
*ppv=NULL; return E_NOINTERFACE ;
}
reinterpret_cast<IUnknown *>(*ppv)->AddRef();
return S_OK;
}
//*******************************************************************
//*******************************************************************
//*** Class Factory: manufacturing CoDictionary objects
//*******************************************************************
//*******************************************************************
class CoDictionaryFactory : public IClassFactory
{
public:
// IUnknown Methods
STDMETHODIMP QueryInterface (REFIID riid, void** ppv);
STDMETHODIMP_(ULONG) AddRef(void)
{ return 1; }
STDMETHODIMP_(ULONG) Release(void)
{ return 1; }
// IClassFactory Methods
STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter,
REFIID riid,
void **ppv)
{
// call CoDictionary's static function to create
// a CoDictionary component object
return CoDictionary::CreateObject(pUnkOuter, riid, ppv);
}
STDMETHODIMP LockServer(BOOL fLock)
{
if (fLock) {
ComponentAddRef();
} else {
ComponentRelease();
}
return S_OK;
}
};
//-------------------------------------------------------------------
// Singleton factory instance that manufacture CoCorEngine
// component objects
//-------------------------------------------------------------------
CoDictionaryFactory g_DictionaryClassFactory;
//-------------------------------------------------------------------
// CoDictionaryFactory::QueryInterface
//-------------------------------------------------------------------
STDMETHODIMP
CoDictionaryFactory::QueryInterface(REFIID riid, void** ppv)
{
if (ppv==NULL) { return E_INVALIDARG; }
if (riid==IID_IUnknown) {
*ppv= static_cast<IClassFactory *>(this);
} else if (riid==IID_IClassFactory) {
*ppv= static_cast<IClassFactory *>(this);
} else {
*ppv=NULL; return E_NOINTERFACE ;
}
reinterpret_cast<IUnknown *>(*ppv)->AddRef();
return S_OK;
}
//*******************************************************************
//*******************************************************************
//*** Main Program
//*******************************************************************
//*******************************************************************
void main(int argc, char **argv)
{
DisplayStatus(TEXT("Server: Started"), S_OK);
g_hExitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
assert(g_hExitEvent);
// registration if required
if (argc > 1) {
if (_stricmp(argv[1], "-RegServer")==0){
RegisterComponent();
DisplayStatus(TEXT("Registered..."), S_OK);
return ;
}
if (_stricmp(argv[1], "-UnRegServer")==0){
UnregisterComponent();
DisplayStatus(TEXT("Unregistered..."), S_OK);
return ;
}
}
// Init COM
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
assert(SUCCEEDED(hr));
// Register Dictionary Class Factory with COM
DWORD dwRegister;
hr = CoRegisterClassObject(CLSID_Dictionary,
&g_DictionaryClassFactory,
CLSCTX_SERVER,
REGCLS_MULTIPLEUSE,
&dwRegister);
assert(SUCCEEDED(hr));
// we don't have to do this, but it's a good habit
g_DictionaryClassFactory.Release();
// sit and wait until CoDictionary object is used
WaitForSingleObject(g_hExitEvent, INFINITE);
// revoke the factory from public view
CoRevokeClassObject(dwRegister);
// uninitialize
CoUninitialize();
DisplayStatus(TEXT("Server shutting down in 5 seconds..."), S_OK);
Sleep(5000);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -