//+--------------------------------------------------------------------------
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright 1997 - 2006 Microsoft Corporation. All Rights Reserved.
//
// FILE: gdlsmpl.cpp
//
// PURPOSE: Implementation of interface for Unidrv5 UI plug-ins.
//
//--------------------------------------------------------------------------
#include "precomp.h"
#include "debug.h"
#include "devmode.h"
#include "intrface.h"
#include "gdlsmpl.h"
// This indicates to Prefast that this is a usermode driver file.
__user_driver;
//--------------------------------------------------------------------------
// Globals
//--------------------------------------------------------------------------
HINSTANCE ghInstance = NULL;
// Module's Instance handle from DLLEntry of process.
//--------------------------------------------------------------------------
// Internal Globals
//--------------------------------------------------------------------------
static long g_cComponents = 0;
// Count of active components
static long g_cServerLocks = 0;
// Count of locks
//--------------------------------------------------------------------------
// Local helper functions
//--------------------------------------------------------------------------
BOOL __stdcall
DebugPrint(
LPCWSTR pszMessage,
// Format string for the error message
...
// args specified in the format string.
)
{
va_list arglist;
// varargs list for processing the '...' parameter.
WCHAR szMsgBuf[MAX_PATH] = {0};
// Use a stack error buffer so that we don't need to
// allocate in the failure path.
HRESULT hResult;
// Result from formatting the string.
if (NULL == pszMessage)
{
return FALSE;
}
// Pass the variable parameters to wvsprintf to be formated.
va_start(arglist, pszMessage);
hResult = StringCbVPrintfW(szMsgBuf, MAX_PATH*sizeof(szMsgBuf[0]), pszMessage, arglist);
va_end(arglist);
// Dump string to debug output.
OutputDebugStringW(szMsgBuf);
return SUCCEEDED(hResult);
}
//--------------------------------------------------------------------------
// Class factory for the Plug-In object
//--------------------------------------------------------------------------
class COemCF : public IClassFactory
{
public:
// IUnknown methods
STDMETHOD(QueryInterface) (THIS_
REFIID riid,
LPVOID FAR* ppvObj
);
STDMETHOD_(ULONG,AddRef) (THIS);
__drv_at(this, __drv_freesMem(object))
STDMETHOD_(ULONG,Release) (THIS);
// IClassFactory methods
STDMETHOD(CreateInstance) (THIS_
__in_opt LPUNKNOWN pUnkOuter,
__in REFIID riid,
__deref_out LPVOID FAR* ppvObject
);
STDMETHOD(LockServer) (THIS_
BOOL bLock
);
// Class-specific methods.
COemCF(): m_cRef(1) { };
~COemCF() { };
protected:
LONG m_cRef;
};
//+---------------------------------------------------------------------------
//
// Member:
// ::DllMain
//
// Synopsis:
// Dll's main routine, called when new
// threads or processes reference the module
//
// Returns:
// TRUE. Currently has no failure paths. Return false if the module
// cannot be properly initialized.
//
// Notes:
// the caller of this routine holds a process-wide lock preventing more
// than one module from being initialized at a time. In general,
// plug-ins should do as little as possible in this routine to avoid
// stalling other threads that may need to load modules. Also, calling
// any function that would, in-turn, cause another module to be loaded
// could result in a deadlock.
//
//
//----------------------------------------------------------------------------
extern "C" BOOL
WINAPI DllMain(
HINSTANCE hInst,
WORD wReason,
LPVOID lpReserved
)
{
UNREFERENCED_PARAMETER(hInst);
UNREFERENCED_PARAMETER(lpReserved);
switch(wReason)
{
case DLL_PROCESS_ATTACH:
ghInstance = hInst;
break;
case DLL_THREAD_ATTACH:
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Member:
// ::DllCanUnloadNow
//
// Synopsis:
// Can the DLL be unloaded from memory? Answers no if any objects are
// still allocated, or if the server has been locked.
//
// To avoid leaving OEM DLL still in memory when Unidrv or Pscript
// drivers are unloaded, Unidrv and Pscript driver ignore the return
// value of DllCanUnloadNow of the OEM DLL, and always call FreeLibrary
// on the OEMDLL.
//
// If the plug-in spins off a working thread that also uses this DLL,
// the thread needs to call LoadLibrary and FreeLibraryAndExitThread,
// otherwise it may crash after Unidrv or Pscript calls FreeLibrary.
//
// Returns:
// S_OK if the DLL can be unloaded safely, otherwise S_FALSE
//
//
//----------------------------------------------------------------------------
STDAPI DllCanUnloadNow()
{
if ((g_cComponents == 0) && (g_cServerLocks == 0))
{
return S_OK;
}
else
{
return S_FALSE;
}
}
//+---------------------------------------------------------------------------
//
// Member:
// ::DllGetClassObject
//
// Synopsis:
// Retrieve the class factory object for the indicated class.
//
// Returns:
// CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, or S_OK.
//
// Notes:
//
//
//----------------------------------------------------------------------------
STDAPI
DllGetClassObject(
__in CONST CLSID& clsid,
// GUID of the class object that the caller wants a class factory for
__in CONST IID& iid,
// Interface ID to provide in ppv
__deref_out VOID** ppv
// out pointer to the interface requested.
)
{
if (ppv == NULL)
{
return E_POINTER;
}
*ppv = NULL;
//
// Can we create this component?
//
if (clsid != CLSID_OEMUI)
{
return CLASS_E_CLASSNOTAVAILABLE;
}
//
// Create class factory.
// Reference count set to 1 in Constructor
//
COemCF* pGDLSampleClassFactory = new COemCF;
if (pGDLSampleClassFactory == NULL)
{
return E_OUTOFMEMORY;
}
//
// Get requested interface.
//
HRESULT hr = pGDLSampleClassFactory->QueryInterface(iid, ppv);
pGDLSampleClassFactory->Release();
return hr;
}
//+---------------------------------------------------------------------------
//
// Member:
// COemCF::QueryInterface
//
// Synopsis:
// Standard COM IUnknown implementation.
//
//
//----------------------------------------------------------------------------
HRESULT __stdcall
COemCF::QueryInterface(
CONST IID& iid,
VOID** ppv
)
{
if ((iid == IID_IUnknown) || (iid == IID_IClassFactory))
{
*ppv = static_cast<COemCF*>(this);
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
return S_OK;
}
//+---------------------------------------------------------------------------
//
// Member:
// COemCF::AddRef
//
// Synopsis:
// Standard COM IUnknown implementatio