windows-nt/Source/XPSP1/NT/com/oleutest/server2/olesrv.cxx
2020-09-26 16:20:57 +08:00

1002 lines
23 KiB
C++

//+-------------------------------------------------------------------
//
// 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;
}