|
|
//+-------------------------------------------------------------------
//
// 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 <stdio.h>
#include <stdarg.h>
#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; }
|