//+------------------------------------------------------------------- // // File: oleimpl.cxx // // Contents: This file contins the DLL entry points // LibMain // DllGetClassObject (Bindings key func) // CAdvBndCF (class factory) // CAdvBnd (actual class implementation) // // Classes: CAdvBndCF, CAdvBnd // // // History: 30-Nov-92 SarahJ Created // 31-Dec-93 ErikGav Chicago port //--------------------------------------------------------------------- // Turn off ole Cairol IUnknown #include "headers.cxx" #pragma hdrstop #include #include #include "wterm.h" #define IDM_DEBUG 0x100 static const TCHAR *szAppName = TEXT("Test OLE Server"); static const char *szFatalError = "OLESRV - Fatal Error"; void MsgBox(char *pszMsg) { MessageBoxA(NULL, pszMsg, szFatalError, MB_OK); } void HrMsgBox(char *pszMsg, HRESULT hr) { char awcBuf[512]; // Build string for output wsprintfA(awcBuf, "%s HRESULT = %lx", pszMsg, hr); // Display message box MessageBoxA(NULL, &awcBuf[0], szFatalError, MB_OK); } //+------------------------------------------------------------------- // Class: CTestServerApp // // Synopsis: Class that holds application-wide data and methods // // Methods: InitApp // CloseApp // GetEmbeddedFlag // // History: 17-Dec-92 DeanE Created //-------------------------------------------------------------------- class FAR CTestServerApp { public: // Constructor/Destructor CTestServerApp(); ~CTestServerApp(); SCODE InitApp (LPSTR lpszCmdline); SCODE CloseApp (void); BOOL GetEmbeddedFlag (void); ULONG IncEmbeddedCount(void); ULONG DecEmbeddedCount(void); private: IClassFactory *_pteClassFactory; ULONG _cEmbeddedObjs; // Count of embedded objects this server // is controlling now DWORD _dwRegId; // OLE registration ID BOOL _fRegistered; // TRUE if srv was registered w/OLE BOOL _fEmbedded; // TRUE if OLE started us at the request // of an embedded obj in a container app }; CTestServerApp tsaMain; HWND g_hMain; void ProcessCmdLine(LPSTR, BOOL *); //+-------------------------------------------------------------- // Function: CTestServerApp::CTestServerApp // // Synopsis: Constructor - initialize members // // Parameters: None // // Returns: None // // History: 17-Dec-92 DeanE Created //--------------------------------------------------------------- CTestServerApp::CTestServerApp() { _pteClassFactory = NULL; _dwRegId = 0; _fRegistered = FALSE; _fEmbedded = TRUE; _cEmbeddedObjs = 0; } //+-------------------------------------------------------------- // Function: CTestServerApp::~CTestServerApp // // Synopsis: Insure pointers are free - note this is mainly for // error-checking. // // Parameters: None // // Returns: None // // History: 17-Dec-92 DeanE Created //--------------------------------------------------------------- CTestServerApp::~CTestServerApp() { Win4Assert(_pteClassFactory == NULL && "Class factory should have been released"); } //+-------------------------------------------------------------- // Function: CTestServerApp::InitApp // // Synopsis: Initialize this instance of the app. // // Parameters: [lpszCmdline] - Command line of the application. // // Returns: S_OK if everything was initialized, or an error if not. // // History: 17-Dec-92 DeanE Created // // Notes: If this does not return, the CloseApp method should // still be called for proper cleanup. //--------------------------------------------------------------- SCODE CTestServerApp::InitApp(LPSTR lpszCmdline) { SCODE sc; // Check OLE version running // BUGBUG - NYI by OLE // Bail out if we are not running with an acceptable version of OLE // Process Command Line arguments ProcessCmdLine(lpszCmdline, &_fEmbedded); // Create the applications class factory - note that we have to free // at a later time _pteClassFactory = new CAdvBndCF(); if (NULL == _pteClassFactory) { MsgBox("Class Object Creation Failed"); return(E_ABORT); } // Register the class with OLE sc = CoRegisterClassObject( CLSID_AdvBnd, _pteClassFactory, CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &_dwRegId); if (S_OK == sc) { _fRegistered = TRUE; } else { HrMsgBox("CoRegisterClassObject FAILED", sc); } return(sc); } //+-------------------------------------------------------------- // Function: CTestServerApp::CloseApp // // Synopsis: Clean up resources this instance of the app is using. // // Parameters: None // // Returns: S_OK if everything was cleaned up, or an error if not. // // History: 17-Dec-92 DeanE Created //--------------------------------------------------------------- SCODE CTestServerApp::CloseApp() { // Revoke the class object, if registered if (TRUE == _fRegistered) { CoRevokeClassObject(_dwRegId); } // Release this apps class factory, and insure the returned count is 0 if (NULL != _pteClassFactory) { // NB: Workaround for ref count problem. #define HACK 1 #if HACK _pteClassFactory->Release(); _pteClassFactory = NULL; #else if (0 == _pteClassFactory->Release()) { _pteClassFactory = NULL; } else { Win4Assert("Release on class factory returned positive ref count"); // BUGBUG - Log error } #endif } return(S_OK); } //+-------------------------------------------------------------- // Function: CTestServerApp::GetEmbeddedFlag // // Synopsis: Returns TRUE if app was started for an embedded object, // FALSE if standalone. // // Parameters: None // // Returns: BOOL (_fEmbedded) // // History: 17-Dec-92 DeanE Created // // Notes: BUGBUG - This should be an inline method //--------------------------------------------------------------- CTestServerApp::GetEmbeddedFlag() { return(_fEmbedded); } //+-------------------------------------------------------------- // Function: CTestServerApp::IncEmbeddedCount // // Synopsis: Increments the count of embedded objects the server // has open. // // Parameters: None // // Returns: ULONG (_cEmbeddedObjs) // // History: 17-Dec-92 DeanE Created // // Notes: BUGBUG - This should be an inline method //--------------------------------------------------------------- ULONG CTestServerApp::IncEmbeddedCount() { return(++_cEmbeddedObjs); } //+-------------------------------------------------------------- // Function: CTestServerApp::DecEmbeddedCount // // Synopsis: Decrements the count of embedded objects the server // has open. If 0 are left and we were running for an // embedded object(s), shut down. // // Parameters: None // // Returns: ULONG (_cEmbeddedObjs) // // History: 17-Dec-92 DeanE Created // // Notes: BUGBUG - This should be an inline method //--------------------------------------------------------------- ULONG CTestServerApp::DecEmbeddedCount() { if ((0 == --_cEmbeddedObjs) && _fEmbedded) { // We are done so revoke our OLE stuff. We need to do this as // soon as we know that we are shutting down so that the window // for returning a bad class object is shut. CloseApp(); // Tell window to die SendMessage(g_hMain, WM_USER, 0xFFFFFFFF, 0xFFFFFFFF); } return(_cEmbeddedObjs); } //+-------------------------------------------------------------- // Function: ProcessCmdline // // Synopsis: Checks the cmd line parameters, in particular for // '/Embedding' or '-Embedding'. // // Parameters: [lpszCmdLine] - Command line buffer. // [pfEmbedded] - Flag should be set to true if we get // the '/Embedding' switch. // // Returns: void // // History: 25-Nov-92 DeanE Created // // Notes: Only two valid commandlines for this program: // (1) -Embedding when started by OLE or (2) Null // string if started from the command line. //--------------------------------------------------------------- void ProcessCmdLine(LPSTR lpszCmdline, BOOL *pfEmbedded) { if (lpszCmdline[0] == 0) { *pfEmbedded = FALSE; return; } if (strcmp(lpszCmdline, "-Embedding") == 0) { *pfEmbedded = TRUE; return; } MsgBox("Received an invalid command line!"); *pfEmbedded = FALSE; return; } void Display(TCHAR *pszFmt, ...) { va_list marker; TCHAR szBuffer[256]; va_start(marker, pszFmt); #ifdef UNICODE int iLen = vswprintf(szBuffer, pszFmt, marker); #else int iLen = vsprintf(szBuffer, pszFmt, marker); #endif va_end(marker); // Display the message on terminal window SendMessage(g_hMain, WM_PRINT_LINE, iLen, (LONG) szBuffer); } //+------------------------------------------------------------------------- // // Function: ProcessMenu // // Synopsis: Gets called when a WM_COMMAND message received. // // Arguments: [hWindow] - handle for the window // [uiMessage] - message id // [wParam] - word parameter // [lParam] - long parameter // // Returns: DefWindowProc result // // History: 06-Aug-92 Ricksa Created // //-------------------------------------------------------------------------- long ProcessMenu(HWND hWindow, UINT uiMessage, WPARAM wParam, LPARAM lParam, void *) { if ((uiMessage == WM_SYSCOMMAND) && (wParam == IDM_DEBUG)) { // Request for a debug breakpoint! DebugBreak(); } return (DefWindowProc(hWindow, uiMessage, wParam, lParam)); } //+------------------------------------------------------------------------- // // Function: ProcessChar // // Synopsis: Gets called when a WM_CHAR message received. // // Arguments: [hWindow] - handle for the window // [uiMessage] - message id // [wParam] - word parameter // [lParam] - long parameter // // Returns: DefWindowProc result // // History: 06-Aug-92 Ricksa Created // //-------------------------------------------------------------------------- long ProcessChar(HWND hWindow, UINT uiMessage, WPARAM wParam, LPARAM lParam, void *) { return (DefWindowProc(hWindow, uiMessage, wParam, lParam)); } //+------------------------------------------------------------------------- // // Function: ProcessClose // // Synopsis: Gets called when a NC_DESTROY message received. // // Arguments: [hWindow] - handle for the window // [uiMessage] - message id // [wParam] - word parameter // [lParam] - long parameter // // Returns: DefWindowProc result // // History: 06-Aug-92 Ricksa Created // //-------------------------------------------------------------------------- long ProcessClose( HWND hWindow, UINT uiMessage, WPARAM wParam, LPARAM lParam, void *pvCallBackData) { // Take default action with message return (DefWindowProc(hWindow, uiMessage, wParam, lParam)); } //+------------------------------------------------------------------- // // Function: WinMain // // Synopsis: Entry point to DLL - does little else // // Arguments: // // Returns: TRUE // // History: 21-Nov-92 SarahJ Created // //-------------------------------------------------------------------- int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, char *lpszCmdLine, int nCmdShow) { // For windows message MSG msg; BOOL bRet; HRESULT hr; // Register the window class bRet = TermRegisterClass(hInstance, NULL, (LPTSTR) szAppName, (LPTSTR) MAKEINTRESOURCE(IDI_APPLICATION)); if (!bRet) { MsgBox("TermRegisterClass FAILED"); return 1; } // Create the server window bRet = TermCreateWindow( (LPTSTR) szAppName, (LPTSTR) szAppName, NULL, ProcessMenu, ProcessChar, ProcessClose, SW_SHOWMINIMIZED, &g_hMain, NULL); if (!bRet) { MsgBox("TermCreateWindow FAILED"); return 1; } // Add debug option to system menu HMENU hmenu = GetSystemMenu(g_hMain, FALSE); AppendMenu(hmenu, MF_SEPARATOR, 0, NULL); AppendMenu(hmenu, MF_STRING | MF_ENABLED, IDM_DEBUG, TEXT("Debug")); // Look up the thread mode from the win.ini file. DWORD thread_mode; TCHAR buffer[80]; int len; len = GetProfileString( TEXT("OleSrv"), TEXT("ThreadMode"), TEXT("MultiThreaded"), buffer, sizeof(buffer) / sizeof(TCHAR)); if (lstrcmp(buffer, TEXT("ApartmentThreaded")) == 0) { thread_mode = COINIT_APARTMENTTHREADED; hr = CoInitialize(NULL); } else { #ifdef MULTI_THREADING thread_mode = COINIT_MULTITHREADED; hr = CoInitializeEx(NULL, thread_mode); #else hr = E_INVALIDARG; #endif } if (S_OK != hr) { HrMsgBox("CoInitialize FAILED", hr); return(1); } // Initialize Application if (S_OK != tsaMain.InitApp(lpszCmdLine)) { tsaMain.CloseApp(); return(1); } if (tsaMain.GetEmbeddedFlag()) { // We're running as an embedded app // Don't show the main window unless we're instructed to do so // BUGBUG - In-place editing is NYI ShowWindow(g_hMain, SW_SHOWMINIMIZED); } else { // We are not running as an embedded app - show the main window ShowWindow(g_hMain, nCmdShow); } UpdateWindow(g_hMain); // message loop while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } // If we get here, we initialized OLE so let's uninitialize it. CoUninitialize(); return (msg.wParam); /* Returns the value from PostQuitMessage */ } //+------------------------------------------------------------------- // // Class: CAdvBndCF // // Synopsis: Class Factory for CAdvBnd // // Interfaces: IUnknown - QueryInterface, AddRef, Release // IClassFactory - CreateInstance // // History: 21-Nov-92 SarahJ Created // //-------------------------------------------------------------------- //+------------------------------------------------------------------- // // Member: CAdvBndCF::CAdvBndCF() // // Synopsis: The constructor for CAdvBnd. // // Arguments: None // // History: 21-Nov-92 SarahJ Created // //-------------------------------------------------------------------- CAdvBndCF::CAdvBndCF() : _cRefs(1) { // Load the class object for the class to aggregate. HRESULT hresult = CoGetClassObject(CLSID_BasicBnd, CLSCTX_SERVER, NULL, IID_IClassFactory, (void **) &_xifac); return; } //+------------------------------------------------------------------- // // Member: CAdvBnd::~CAdvBndObj() // // Synopsis: The destructor for CAdvBnd. // // History: 21-Nov-92 SarahJ Created // //-------------------------------------------------------------------- CAdvBndCF::~CAdvBndCF() { return; } //+------------------------------------------------------------------- // // Method: CAdvBndCF::QueryInterface // // Synopsis: Only IUnknown and IClassFactory supported // //-------------------------------------------------------------------- STDMETHODIMP CAdvBndCF::QueryInterface(REFIID iid, void FAR * FAR * ppv) { if (GuidEqual(iid, IID_IUnknown) || GuidEqual(iid, IID_IClassFactory)) { *ppv = (IUnknown *) this; AddRef(); return S_OK; } else { *ppv = NULL; return E_NOINTERFACE; } } STDMETHODIMP_(ULONG) CAdvBndCF::AddRef(void) { return(++_cRefs); } STDMETHODIMP_(ULONG) CAdvBndCF::Release(void) { if (--_cRefs == 0) { delete this; return(0); } return _cRefs; } //+------------------------------------------------------------------- // // Method: CAdvBndCF::CreateInstance // // Synopsis: This is called by Binding process to create the // actual class object // //-------------------------------------------------------------------- STDMETHODIMP CAdvBndCF::CreateInstance( IUnknown FAR* pUnkOuter, REFIID iidInterface, void FAR* FAR* ppv) { Display(TEXT("CAdvBndCF::CreateInstance called\n")); if (pUnkOuter != NULL) { return E_FAIL; } CAdvBnd * lpcBB = new FAR CAdvBnd((IClassFactory *) _xifac); if (lpcBB == NULL) { return E_OUTOFMEMORY; } HRESULT hresult = lpcBB->QueryInterface(iidInterface, ppv); lpcBB->Release(); return hresult; } STDMETHODIMP CAdvBndCF::LockServer(BOOL fLock) { return E_FAIL; } //+------------------------------------------------------------------- // // Member: CAdvBnd::CAdvBnd() // // Synopsis: The constructor for CAdvBnd. I // // Arguments: None // // History: 21-Nov-92 SarahJ Created // //-------------------------------------------------------------------- CAdvBnd::CAdvBnd(IClassFactory *pcfBase) : _xiunk(), _dwRegister(0), _cRefs(1) { HRESULT hresult = pcfBase->CreateInstance((IUnknown *) this, IID_IUnknown, (void **) &_xiunk); tsaMain.IncEmbeddedCount(); return; } //+------------------------------------------------------------------- // // Member: CAdvBnd::~CAdvBndObj() // // Synopsis: The destructor for CAdvBnd. // // History: 21-Nov-92 SarahJ Created // //-------------------------------------------------------------------- CAdvBnd::~CAdvBnd() { Display(TEXT("CAdvBndCF::~CAdvBnd called\n")); if (_dwRegister != 0) { // Get the running object table IRunningObjectTable *prot; HRESULT hresult = GetRunningObjectTable(0, &prot); if (hresult != S_OK) { HrMsgBox("CAdvBnd::~CAdvBnd GetRunningObjectTable failed", hresult); } else { hresult = prot->Revoke(_dwRegister); if (hresult != S_OK) { HrMsgBox("CAdvBnd::~CAdvBnd Revoke failed", hresult); } prot->Release(); } } tsaMain.DecEmbeddedCount(); return; } //+------------------------------------------------------------------- // // Member: CAdvBnd::QueryInterface // // Returns: SUCCESS_SUCCCESS // // History: 21-Nov-92 SarahJ Created // //-------------------------------------------------------------------- STDMETHODIMP CAdvBnd::QueryInterface(REFIID iid, void ** ppunk) { Display(TEXT("CAdvBnd::QueryInterface called\n")); if (GuidEqual(iid, IID_IUnknown)) { *ppunk = (IUnknown *) this; AddRef(); return S_OK; } else if ((GuidEqual(iid, IID_IPersistFile)) || (GuidEqual(iid, IID_IPersist))) { *ppunk = (IPersistFile *) this; AddRef(); return S_OK; } return _xiunk->QueryInterface(iid, ppunk); } STDMETHODIMP_(ULONG) CAdvBnd::AddRef(void) { return ++_cRefs; } STDMETHODIMP_(ULONG) CAdvBnd::Release(void) { if (--_cRefs == 0) { delete this; return(0); } return _cRefs; } //+------------------------------------------------------------------- // // Member: CAdvBnd::Load // // Synopsis: IPeristFile interface - needed 'cause we bind with // file moniker and BindToObject insists on calling this // // History: 21-Nov-92 SarahJ Created // //-------------------------------------------------------------------- STDMETHODIMP CAdvBnd::Load(LPCWSTR lpszFileName, DWORD grfMode) { Display(TEXT("CAdvBndCF::Load called\n")); // Forward call to delegated class IPersistFile *pipfile; HRESULT hresult = _xiunk->QueryInterface(IID_IPersistFile, (void **) &pipfile); hresult = pipfile->Load(lpszFileName, grfMode); pipfile->Release(); if (FAILED(hresult)) { // Make sure delegated too class liked what it got/ // BUGBUG: Can't just forward hresults! return hresult; } // Create a file moniker IMoniker *pmk; hresult = CreateFileMoniker((LPWSTR)lpszFileName, &pmk); if (FAILED(hresult)) { HrMsgBox("CAdvBnd::Load CreateFileMoniker failed", hresult); return hresult; } // Get the running object table IRunningObjectTable *prot; hresult = GetRunningObjectTable(0, &prot); if (FAILED(hresult)) { HrMsgBox("CAdvBnd::Load GetRunningObjectTable failed", hresult); return hresult; } // Register in the running object table IUnknown *punk; QueryInterface(IID_IUnknown, (void **) &punk); hresult = prot->Register(0, punk, pmk, &_dwRegister); if (FAILED(hresult)) { HrMsgBox("CAdvBnd::Load Register failed", hresult); return hresult; } // Set filetime to known value FILETIME filetime; memset(&filetime, 'B', sizeof(filetime)); // Set time to some known value prot->NoteChangeTime(_dwRegister, &filetime); // Release uneeded objects pmk->Release(); prot->Release(); punk->Release(); return S_OK; } //+------------------------------------------------------------------- // // Member: CAdvBnd::Save // // Synopsis: IPeristFile interface - save // does little but here for commentry // // History: 21-Nov-92 SarahJ Created // //-------------------------------------------------------------------- STDMETHODIMP CAdvBnd::Save(LPCWSTR lpszFileName, BOOL fRemember) { Display(TEXT("CAdvBndCF::Save called\n")); // Forward call to delegated class IPersistFile *pipfile; HRESULT hresult = _xiunk->QueryInterface(IID_IPersistFile, (void **) &pipfile); hresult = pipfile->Save(lpszFileName, fRemember); pipfile->Release(); return hresult; } //+------------------------------------------------------------------- // // Member: CAdvBnd::SaveCpmpleted // CAdvBnd::GetCurFile // CAdvBnd::IsDirty // // Synopsis: More IPeristFile interface methods // // History: 21-Nov-92 SarahJ Created // //-------------------------------------------------------------------- STDMETHODIMP CAdvBnd::SaveCompleted(LPCWSTR lpszFileName) { Display(TEXT("CAdvBndCF::SaveCompleted called\n")); // Forward call to delegated class IPersistFile *pipfile; HRESULT hresult = _xiunk->QueryInterface(IID_IPersistFile, (void **) &pipfile); hresult = pipfile->SaveCompleted(lpszFileName); pipfile->Release(); return hresult; } STDMETHODIMP CAdvBnd::GetCurFile(LPWSTR FAR *lpszFileName) { Display(TEXT("CAdvBndCF::GetCurFile called\n")); // Forward call to delegated class IPersistFile *pipfile; HRESULT hresult = _xiunk->QueryInterface(IID_IPersistFile, (void **) &pipfile); hresult = pipfile->GetCurFile(lpszFileName); pipfile->Release(); return hresult; } STDMETHODIMP CAdvBnd::IsDirty() { Display(TEXT("CAdvBndCF::IsDirty called\n")); // Forward call to delegated class IPersistFile *pipfile; HRESULT hresult = _xiunk->QueryInterface(IID_IPersistFile, (void **) &pipfile); hresult = pipfile->IsDirty(); pipfile->Release(); return hresult; } //+------------------------------------------------------------------- // // Interface: IPersist // // Synopsis: IPersist interface methods // Need to return a valid class id here // // History: 21-Nov-92 SarahJ Created // STDMETHODIMP CAdvBnd::GetClassID(LPCLSID classid) { Display(TEXT("CAdvBndCF::GetClassID called\n")); *classid = CLSID_AdvBnd; return S_OK; }