//+------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1993. // // File: ole2.cpp // // Contents: LibMain and initialization routines // // Classes: // // Functions: LibMain // OleInitialize // OleInitializeWOW // OleInitializeEx // OleUnitialize // OleBuildVersion - !WIN32 // // // History: dd-mmm-yy Author Comment // 16-Feb-94 AlexT alias OleBuildVersion, remove OleGetMalloc // remove DisableThreadLibaryCalls // 11-Jan-94 alexgo added VDATEHEAP macros to every function // 10-Dec-93 alexgo added support for LEDebugOut // 06-Dec-93 ChrisWe remove declaration of ClipboardInitialize() // and ClipboardUninitialize(), which are declared in // clipbrd.h; include that instead // 15-Mar-94 KevinRo Added OleInitializeWOW(); // //-------------------------------------------------------------------------- #include #include #include #include #pragma SEG(ole) #include #include #include #include #include // // DECLARE_INFOLEVEL is a macro used with cairo-style debugging output. // it creates a global variable LEInfoLevel which contains bits flags // of the various debugging output that should be sent to the debugger. // // Note that info level may be set within the debugger once ole232.dll // has loaded. // // Currently LEInfoLevel defaults to DEB_WARN | DEB_ERROR // DECLARE_INFOLEVEL(LE); DECLARE_INFOLEVEL(Ref); DECLARE_INFOLEVEL(DD); DECLARE_INFOLEVEL(VDATE); NAME_SEG(Ole2Main) // these are globals HMODULE g_hmodOLE2 = NULL; HINSTANCE g_hinst = NULL; ULONG g_cOleProcessInits = 0; CLIPFORMAT g_cfObjectLink = NULL; CLIPFORMAT g_cfOwnerLink = NULL; CLIPFORMAT g_cfNative = NULL; CLIPFORMAT g_cfLink = NULL; CLIPFORMAT g_cfBinary = NULL; CLIPFORMAT g_cfFileName = NULL; CLIPFORMAT g_cfFileNameW = NULL; CLIPFORMAT g_cfNetworkName = NULL; CLIPFORMAT g_cfDataObject = NULL; CLIPFORMAT g_cfEmbeddedObject = NULL; CLIPFORMAT g_cfEmbedSource = NULL; CLIPFORMAT g_cfCustomLinkSource = NULL; CLIPFORMAT g_cfLinkSource = NULL; CLIPFORMAT g_cfLinkSrcDescriptor = NULL; CLIPFORMAT g_cfObjectDescriptor = NULL; CLIPFORMAT g_cfOleDraw = NULL; CLIPFORMAT g_cfPBrush = NULL; CLIPFORMAT g_cfMSDraw = NULL; CLIPFORMAT g_cfOlePrivateData = NULL; CLIPFORMAT g_cfScreenPicture = NULL; CLIPFORMAT g_cfOleClipboardPersistOnFlush= NULL; CLIPFORMAT g_cfMoreOlePrivateData = NULL; ATOM g_aDropTarget = NULL; ATOM g_aDropTargetMarshalHwnd = NULL; ASSERTDATA ASSERTOUTDATA // more globals extern UINT uOmPostWmCommand; extern UINT uOleMessage; extern COleStaticMutexSem g_mxsSingleThreadOle; // this dummy function is used to avoid a copy of the environment variables. // NOTE: the moniker and dde code still use the windows heap. extern "C" void _setenvp(void) { VDATEHEAP(); } //+--------------------------------------------------------------------------- // // Function: OleInitializeWOW // Synopsis: Entry point to initialize the 16-bit WOW thunk layer. // // Effects: This routine is called when OLE32 is loaded by a VDM. // It serves two functions: It lets OLE know that it is // running in a VDM, and it passes in the address to a set // of functions that are called by the thunk layer. This // allows normal 32-bit processes to avoid loading the WOW // DLL since the thunk layer references it. // // Arguments: [vlpmalloc] -- 16:16 pointer to the 16 bit allocator. // [lpthk] -- Flat pointer to the OleThunkWOW virtual // interface. This is NOT an OLE/IUnknown style // interface. // Requires: // // Returns: // // Signals: // // Modifies: // // Algorithm: // // History: 3-15-94 kevinro Created // // Notes: // //---------------------------------------------------------------------------- STDAPI OleInitializeWOW( LPMALLOC vlpmalloc, LPOLETHUNKWOW lpthk ) { OLETRACEIN((API_OleInitializeWOW, PARAMFMT("vlpmalloc= %x, lpthk= %p"), vlpmalloc, lpthk)); SetOleThunkWowPtr(lpthk); HRESULT hr; hr = OleInitializeEx( NULL, COINIT_APARTMENTTHREADED ); OLETRACEOUT((API_OleInitializeWOW, hr)); return hr; } //+------------------------------------------------------------------------- // // Function: OleInitialize // // Synopsis: Initializes OLE in single threaded mode // // Effects: // // Arguments: [pMalloc] -- the memory allocator to use // // Requires: // // Returns: HRESULT // // Signals: // // Modifies: // // Algorithm: // // History: dd-mmm-yy Author Comment // 06-Dec-93 alexgo 32bit port // // Notes: // //-------------------------------------------------------------------------- STDAPI OleInitialize(void * pMalloc) { OLETRACEIN((API_OleInitialize, PARAMFMT("pMalloc= %p"), pMalloc)); VDATEHEAP(); HRESULT hr; hr = OleInitializeEx( pMalloc, COINIT_APARTMENTTHREADED ); OLETRACEOUT((API_OleInitialize, hr)); return hr; } //+------------------------------------------------------------------------- // // Function: OleInitializeEx // // Synopsis: Initializes ole // // Effects: // // Arguments: [pMalloc] -- the task memory allocator to use // [flags] -- single or multi-threaded // // Requires: // // Returns: HRESULT // // Signals: // // Modifies: // // Algorithm: // // History: dd-mmm-yy Author Comment // 06-Dec-93 alexgo 32bit port // 24-May-94 AlexT Propagate CoInitializeEx's return code // 21-Jul-94 AlexT Allow nested OleInit/Uninit calls // 24-Aug-94 AlexT Return S_OK for first success and S_FALSE // thereafter (unless an allocator was // passed in) // 14-Aug-96 SatishT Changed the test for notification of Explorer // to only use the gfShellInitialized flag // // Notes: This routine may be called multiple times per apartment // //-------------------------------------------------------------------------- #pragma SEG(OleInitialize) STDAPI OleInitializeEx(LPVOID pMalloc, ULONG ulFlags) { OLETRACEIN((API_OleInitialize, PARAMFMT("pMalloc= %p, ulFlags= %x"), pMalloc, ulFlags)); VDATEHEAP(); HRESULT hr; #if DBG==1 HRESULT hrCoInit = S_OK; #endif DWORD cThreadOleInits; hr = CoInitializeEx(pMalloc, ulFlags); if (SUCCEEDED(hr)) { Assert (g_hmodOLE2); #if DBG==1 hrCoInit = hr; #endif COleTls tls; cThreadOleInits = ++ tls->cOleInits; do { // We only want to do the below initialization once per apartment if (cThreadOleInits > 1) { // We've already been this way before, just return Assert(SUCCEEDED(hr) && "Bad OleInitializeEx logic"); break; } // single thread registration of DDE and clipboard formats. // Only do this once per process. COleStaticLock lck(g_mxsSingleThreadOle); if (++g_cOleProcessInits != 1) { // already done the per-process initialization break; } // initialized DDE only if any server objects have // already been registered. hr = CheckInitDde(FALSE); if (FAILED(hr)) { Assert (!"DDELibMain failed()"); break; } // Only need to do the initialization once so check the global // that gets assigned last. if( !g_aDropTarget ) { // on NT3.51, clipboard formats are pre-registered for us by user32. // (This is done in file \ntuser\kernel\server.c.) // We know they are going to be sequential. This gives us a // good performance improvement (since the clipboard formats never // change. g_cfObjectLink = (CLIPFORMAT) RegisterClipboardFormat(OLESTR("ObjectLink")); g_cfOwnerLink = g_cfObjectLink + 1; Assert(g_cfOwnerLink == RegisterClipboardFormat(OLESTR("OwnerLink"))); g_cfNative = g_cfObjectLink + 2; Assert(g_cfNative == RegisterClipboardFormat(OLESTR("Native"))); g_cfBinary = g_cfObjectLink + 3; Assert(g_cfBinary == RegisterClipboardFormat(OLESTR("Binary"))); g_cfFileName = g_cfObjectLink + 4; Assert(g_cfFileName == RegisterClipboardFormat(OLESTR("FileName"))); g_cfFileNameW = g_cfObjectLink + 5; Assert(g_cfFileNameW == RegisterClipboardFormat(OLESTR("FileNameW"))); g_cfNetworkName = g_cfObjectLink + 6; Assert(g_cfNetworkName == RegisterClipboardFormat(OLESTR("NetworkName"))); g_cfDataObject = g_cfObjectLink + 7; Assert(g_cfDataObject == RegisterClipboardFormat(OLESTR("DataObject"))); g_cfEmbeddedObject = g_cfObjectLink + 8; Assert(g_cfEmbeddedObject == RegisterClipboardFormat(OLESTR("Embedded Object"))); g_cfEmbedSource = g_cfObjectLink + 9; Assert(g_cfEmbedSource == RegisterClipboardFormat(OLESTR("Embed Source"))); g_cfCustomLinkSource = g_cfObjectLink + 10; Assert(g_cfCustomLinkSource == RegisterClipboardFormat(OLESTR("Custom Link Source"))); g_cfLinkSource = g_cfObjectLink + 11; Assert(g_cfLinkSource == RegisterClipboardFormat(OLESTR("Link Source"))); g_cfObjectDescriptor = g_cfObjectLink + 12; Assert(g_cfObjectDescriptor == RegisterClipboardFormat(OLESTR("Object Descriptor"))); g_cfLinkSrcDescriptor = g_cfObjectLink + 13; Assert(g_cfLinkSrcDescriptor == RegisterClipboardFormat(OLESTR("Link Source Descriptor"))); g_cfOleDraw = g_cfObjectLink + 14; Assert(g_cfOleDraw == RegisterClipboardFormat(OLESTR("OleDraw"))); g_cfPBrush = g_cfObjectLink + 15; Assert(g_cfPBrush == RegisterClipboardFormat(OLESTR("PBrush"))); g_cfMSDraw = g_cfObjectLink + 16; Assert(g_cfMSDraw == RegisterClipboardFormat(OLESTR("MSDraw"))); g_cfOlePrivateData = g_cfObjectLink + 17; Assert(g_cfOlePrivateData == RegisterClipboardFormat(OLESTR("Ole Private Data"))); g_cfScreenPicture = g_cfObjectLink + 18; Assert(g_cfScreenPicture == RegisterClipboardFormat(OLESTR("Screen Picture"))); g_cfOleClipboardPersistOnFlush = g_cfObjectLink + 19; /* turned off till NtUser group checks in for 335613 Assert(g_cfOleClipboardPersistOnFlush == RegisterClipboardFormat(OLESTR("OleClipboardPersistOnFlush"))); */ g_cfMoreOlePrivateData = g_cfObjectLink + 20; /* turned off till NtUser group checks in for 335613 Assert(g_cfMoreOlePrivateData == RegisterClipboardFormat(OLESTR("MoreOlePrivateData"))); */ g_aDropTarget = GlobalAddAtom(OLE_DROP_TARGET_PROP); AssertSz(g_aDropTarget, "Couldn't add drop target atom\n"); g_aDropTargetMarshalHwnd = GlobalAddAtom(OLE_DROP_TARGET_MARSHALHWND); AssertSz(g_aDropTargetMarshalHwnd, "Couldn't add drop target hwnd atom\n"); } // Used in Inplace editing uOmPostWmCommand = RegisterWindowMessage(OLESTR("OM_POST_WM_COMMAND")); uOleMessage = RegisterWindowMessage(OLESTR("OLE_MESSAHE")); } while (FALSE); // end of do if (FAILED(hr)) { // clean up and break out CheckUninitDde(FALSE); tls->cOleInits--; CoUninitialize(); } else { Assert(SUCCEEDED(hr) && "Bad OleInitializeEx logic"); // If we're overriding the allocator, we return whatever // CoInitializeEx returned if (NULL != pMalloc) { Assert(hr == hrCoInit && "Bad OleInit logic"); } else if (1 == cThreadOleInits) { // First successful call to OleInitializeEx - S_OK hr = S_OK; } else { // Second or greater succesful call to OleInitializeEx - S_FALSE hr = S_FALSE; } // Notify the COM verifier about the oleinit, for tracking purposes. CoVrfNotifyOleInit(); } } OLETRACEOUT((API_OleInitialize, hr)); return hr; } //+------------------------------------------------------------------------- // // Function: OleUnitialize // // Synopsis: Unitializes OLE, releasing any grabbed resources // // Effects: // // Arguments: void // // Requires: // // Returns: void // // Signals: // // Modifies: // // Algorithm: // // History: dd-mmm-yy Author Comment // 06-Dec-93 alexgo 32bit port // 21-Jul-94 AlexT Allow nested OleInit/Uninit calls // // Notes: // //-------------------------------------------------------------------------- #pragma SEG(OleUninitialize) STDAPI_(void) OleUninitialize(void) { OLETRACEIN((API_OleUninitialize, NOPARAM)); VDATEHEAP(); COleTls tls(TRUE); if (tls.IsNULL() || 0 == tls->cOleInits) { CoVrfNotifyExtraOleUninit(); LEDebugOut((DEB_ERROR, "(0 == thread inits) Unbalanced call to OleUninitialize\n")); goto errRtn; } if (0 == -- tls->cOleInits) { // This thread has called OleUninitialize for the last time. Check if // we need to do per process uninit now. ClipboardUninitialize(); // Must be first thing CheckUninitDde(FALSE); COleStaticLock lck(g_mxsSingleThreadOle); if (--g_cOleProcessInits == 0) { DragDropProcessUninitialize(); // after this point, the uninit should not fail (because we don't // have code to redo the init). CheckUninitDde(TRUE); #if DBG==1 // check for unreleased globals UtGlobalFlushTracking(); #endif } } // Notify the COM verifier about the oleuninit, for tracking purposes. CoVrfNotifyOleUninit(); // We call CoInitialize each time we call OleInitialize, so here we // balance that call CoUninitialize(); errRtn: OLETRACEOUTEX((API_OleUninitialize, NORETURN)); return; }