/***************************************************************************** * * Sti.c * * Copyright (C) Microsoft Corporation, 1996 - 1998 All Rights Reserved. * * Abstract: * * DLL Initialization/termination routines and global * exported functions * * Contents: * * StiCreateInstance() - exported function to create top level instance * *****************************************************************************/ #define INITGUID #include "pch.h" // // Externs found in STIRT // extern DWORD g_cRef; extern CRITICAL_SECTION g_crstDll; extern CHAR szProcessCommandLine[MAX_PATH]; #ifdef DEBUG extern int g_cCrit; #endif extern VOID RegSTIforWiaHelper(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow); extern VOID MigrateSTIAppsHelper(HWND hWnd, HINSTANCE hInst, PTSTR pszCommandLine, INT iParam); #include #define DbgFl DbgFlSti BOOL APIENTRY DmPrxyDllMain( HINSTANCE hinst, DWORD dwReason, LPVOID lpReserved ); STDAPI DmPrxyDllGetClassObject( REFCLSID rclsid, RIID riid, PPV ppvObj ); STDMETHODIMP DmPrxyDllCanUnloadNow( void ); /***************************************************************************** * * @doc INTERNAL * * @func void | DllEnterCrit | * * Take the DLL critical section. * * The DLL critical section is the lowest level critical section. * You may not attempt to acquire any other critical sections or * yield while the DLL critical section is held. * *****************************************************************************/ void EXTERNAL DllEnterCrit(void) { EnterCriticalSection(&g_crstDll); #ifdef DEBUG // Save thread ID , taking critical section first , it becomes owner if (++g_cCrit == 0) { g_thidCrit = GetCurrentThreadId(); } AssertF(g_thidCrit == GetCurrentThreadId()); #endif } /***************************************************************************** * * @doc INTERNAL * * @func void | DllLeaveCrit | * * Leave the DLL critical section. * *****************************************************************************/ void EXTERNAL DllLeaveCrit(void) { #ifdef DEBUG AssertF(g_thidCrit == GetCurrentThreadId()); AssertF(g_cCrit >= 0); if (--g_cCrit < 0) { g_thidCrit = 0; } #endif LeaveCriticalSection(&g_crstDll); } /***************************************************************************** * * @doc INTERNAL * * @func void | DllAddRef | * * Increment the reference count on the DLL. * *****************************************************************************/ void EXTERNAL DllAddRef(void) { InterlockedIncrement((LPLONG)&g_cRef); } /***************************************************************************** * * @doc INTERNAL * * @func void | DllRelease | * * Decrement the reference count on the DLL. * *****************************************************************************/ void EXTERNAL DllRelease(void) { InterlockedDecrement((LPLONG)&g_cRef); } /***************************************************************************** * * @doc INTERNAL * * @func HRESULT | DllGetClassObject | * * Create an instance for this DLL. * * @parm REFCLSID | rclsid | * * The object being requested. * * @parm RIID | riid | * * The desired interface on the object. * * @parm PPV | ppvOut | * * Output pointer. * *****************************************************************************/ #pragma BEGIN_CONST_DATA CLSIDMAP c_rgclsidmap[cclsidmap] = { { &CLSID_Sti, CStiObj_New, IDS_STIOBJ }, // { &CLSID_StiDevice, CStiDevice_New, IDS_STIDEVICE }, }; #pragma END_CONST_DATA STDAPI DllGetClassObject(REFCLSID rclsid, RIID riid, PPV ppvObj) { HRESULT hres; UINT iclsidmap; EnterProcR(DllGetClassObject, (_ "G", rclsid)); // // Bump global ref count temporarily. By doing so we minimize chances of // faulting on potential race condition when another thread just called // DllCanUnloadNow while we are inside ClassFactory. // DllAddRef(); for (iclsidmap = 0; iclsidmap < cA(c_rgclsidmap); iclsidmap++) { if (IsEqualIID(rclsid, c_rgclsidmap[iclsidmap].rclsid)) { hres = CSti_Factory_New(c_rgclsidmap[iclsidmap].pfnCreate, riid, ppvObj); goto done; } } DebugOutPtszV(DbgFlDll | DbgFlError, TEXT("%s: Wrong CLSID"),""); *ppvObj = 0; hres = CLASS_E_CLASSNOTAVAILABLE; done:; // // If unsucessful - try DM Proxy // if (!SUCCEEDED(hres)) { hres = DmPrxyDllGetClassObject(rclsid, riid, ppvObj); } ExitOleProcPpv(ppvObj); DllRelease(); return hres; } /***************************************************************************** * * @doc INTERNAL * * @func HRESULT | DllCanUnloadNow | * * Determine whether the DLL has any outstanding interfaces. * * @returns * * Returns if the DLL can unload, if * it is not safe to unload. * *****************************************************************************/ STDMETHODIMP DllCanUnloadNow(void) { HRESULT hres; // // First ask DM proxy and it says OK - check out ref count // hres = DmPrxyDllCanUnloadNow(); if (hres == S_OK) { #ifdef DEBUG DebugOutPtszV(DbgFlDll, TEXT("DllCanUnloadNow() - g_cRef = %d"), g_cRef); Common_DumpObjects(); #endif hres = g_cRef ? S_FALSE : S_OK; } return hres; } /***************************************************************************** * * @doc INTERNAL * * @func BOOL | DllEntryPoint | * * Called to notify the DLL about various things that can happen. * * We are not interested in thread attaches and detaches, * so we disable thread notifications for performance reasons. * * @parm HINSTANCE | hinst | * * The instance handle of this DLL. * * @parm DWORD | dwReason | * * Notification code. * * @parm LPVOID | lpReserved | * * Not used. * * @returns * * Returns to allow the DLL to load. * *****************************************************************************/ #pragma BEGIN_CONST_DATA #pragma END_CONST_DATA BOOL APIENTRY DllEntryPoint(HINSTANCE hinst, DWORD dwReason, LPVOID lpReserved) { //RPC_STATUS RpcStatus; DWORD dwLocalSTIServerVer = 0; UINT uiCmdLineLength; switch (dwReason) { case DLL_PROCESS_ATTACH: g_hInst = hinst; __try { // Disable thread library calls to avoid // deadlock when we spin up the worker thread DisableThreadLibraryCalls(hinst); if(!InitializeCriticalSectionAndSpinCount(&g_crstDll, MINLONG)) { // refuse to load if we can't initialize critsect return FALSE; } // Set global flags g_NoUnicodePlatform = !OSUtil_IsPlatformUnicode(); // // Save command line for use in GetLaunchInformation // uiCmdLineLength = min(lstrlenA(GetCommandLineA()),sizeof(szProcessCommandLine)-1); lstrcpyn(szProcessCommandLine,GetCommandLineA(),uiCmdLineLength); szProcessCommandLine[uiCmdLineLength] = '\0'; #ifdef DEBUG // Debugging flags InitializeDebuggingSupport(); #endif // // Initialize file logging // g_hStiFileLog = CreateStiFileLog(TEXT("STICLI"),NULL, STI_TRACE_ERROR | STI_TRACE_ADD_THREAD | STI_TRACE_ADD_PROCESS ); #if CHECK_LOCAL_SERVER // Check version of the local server RpcStatus = RpcStiApiGetVersion(NULL, 0, &dwLocalSTIServerVer); DebugOutPtszV(DbgFlDll, TEXT("STIINIT : Getting server version : RpcStatus = %d LocalServerVer=%d"), RpcStatus,dwLocalSTIServerVer); #endif } __except(EXCEPTION_EXECUTE_HANDLER) { return FALSE; } break; case DLL_PROCESS_DETACH: if (g_cRef) { DebugOutPtszV(DbgFl,"Unloaded before all objects Release()d! Crash soon!\r\n"); } // Close file logging CloseStiFileLog(g_hStiFileLog); // // Don't forget to delete our critical section. (It is safe to // do this because we definitely tried to initialize it and so // it should be in a sane state) // DeleteCriticalSection(&g_crstDll); break; } return 1; } BOOL APIENTRY DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID lpReserved) { // First call proxy dll main DmPrxyDllMain(hinst, dwReason, lpReserved); return DllEntryPoint(hinst, dwReason, lpReserved); } /***************************************************************************** * * @doc EXTERNAL * * @func HRESULT | StiCreateInstance | * * This function creates a new Sti object * which supports the COM interface. * * On success, the function returns a pointer to the new object in * *

. * * * @parm IN HINSTANCE | hinst | * * Instance handle of the application or DLL that is creating * the Sti object. * * Sti uses this value to determine whether the * application or DLL has been certified. * * @parm DWORD | dwVersion | * * Version number of the sti.h header file that was used. * This value must be . * * Sti uses this value to determine what version of * Sti the application or DLL was designed for. * * @parm OUT LPSti * | lplpSti | * Points to where to return * the pointer to the interface, if successful. * * @parm IN LPUNKNOWN | punkOuter | Pointer to controlling unknown * for OLE aggregation, or 0 if the interface is not aggregated. * Most callers will pass 0. * * Note that if aggregation is requested, the object returned * in *

will be a pointer to an * rather than an , as required * by OLE aggregation. * * @returns * * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * = : The operation completed successfully. * * = : The *

parameter is not a valid pointer. * * = : * Out of memory. * * : The application * requires a newer version of Sti. * * : The application * was written for an unsupported prerelease version * of Sti. * * @comm Calling this function with

= NULL * is equivalent to creating the object via * (&CLSID_Sti,

, * CLSCTX_INPROC_SERVER, &IID_ISti,

); * then initializing it with . * * Calling this function with

!= NULL * is equivalent to creating the object via * (&CLSID_Sti,

, * CLSCTX_INPROC_SERVER, &IID_IUnknown,

). * The aggregated object must be initialized manually. * *****************************************************************************/ STDMETHODIMP StiCreateInstanceW(HINSTANCE hinst, DWORD dwVer, PSTI *ppSti, PUNK punkOuter) { HRESULT hres; EnterProc(StiCreateInstance, (_ "xxx", hinst, dwVer, punkOuter)); hres = StiCreateHelper(hinst, dwVer, (PPV)ppSti, punkOuter,&IID_IStillImageW); ExitOleProcPpv(ppSti); return hres; } STDMETHODIMP StiCreateInstanceA(HINSTANCE hinst, DWORD dwVer, PSTIA *ppSti, PUNK punkOuter) { HRESULT hres; EnterProc(StiCreateInstance, (_ "xxx", hinst, dwVer, punkOuter)); hres = StiCreateHelper(hinst, dwVer, (PPV)ppSti, punkOuter,&IID_IStillImageA); ExitOleProcPpv(ppSti); return hres; } /***************************************************************************** * * @doc INTERNAL * * @func HRESULT | DllInitializeCOM | * * Initialize COM libraries * * @parm IN | | * * @returns * * Returns a boolean error code. * *****************************************************************************/ BOOL EXTERNAL DllInitializeCOM( void ) { DllEnterCrit(); if(!g_COMInitialized) { #ifdef USE_REAL_OLE32 if(SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE)) ) { g_COMInitialized = TRUE; } #else g_COMInitialized = TRUE; #endif } DllLeaveCrit(); return g_COMInitialized; } /***************************************************************************** * * @doc INTERNAL * * @func HRESULT | DllUnInitializeCOM | * * UnInitialize COM libraries * * @parm IN | | * * @returns * * Returns a boolean error code. * *****************************************************************************/ BOOL EXTERNAL DllUnInitializeCOM( void ) { DllEnterCrit(); #ifdef USE_REAL_OLE32 if(g_COMInitialized) { CoUninitialize(); g_COMInitialized = FALSE; } #endif DllLeaveCrit(); return TRUE; } /***************************************************************************** * * @doc INTERNAL * * @func VOID | RegSTIforWia | * * Private server entry point to register STI apps for WIA events * * @parm IN | | * * @returns * * VOID * *****************************************************************************/ VOID EXTERNAL RegSTIforWia(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) { RegSTIforWiaHelper(hwnd, hinst, lpszCmdLine, nCmdShow); } VOID WINAPI MigrateRegisteredSTIAppsForWIAEvents( HWND hWnd, HINSTANCE hInst, PTSTR pszCommandLine, INT iParam ) { MigrateSTIAppsHelper(hWnd, hInst, pszCommandLine, iParam); }