//=--------------------------------------------------------------------------= // InProcServer.Cpp //=--------------------------------------------------------------------------= // Copyright 1995 Microsoft Corporation. All Rights Reserved. // // 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. //=--------------------------------------------------------------------------= // // implements all exported DLL functions for the program, as well as a few // others that will be used by same // #include "pch.h" #include "LocalSrv.H" #include "AutoObj.H" #include "ClassF.H" #include "CtrlObj.H" #include "Unknown.H" #include "ComCat.H" #ifdef DEBUG #include "debug.h" #include #endif // DEBUG // for ASSERT and FAIL // SZTHISFILE #ifdef VS_HELP #include "vshelp.h" extern IVsHelpSystem *g_pIVsHelpSystem; #endif //=--------------------------------------------------------------------------= // Private module level data // //=--------------------------------------------------------------------------= // These are used for reflection in OLE Controls. Not that big of a hit that // we mind defining them for all servers, including automation or generic // COM. // // Make this a constant. extern const char g_szReflectClassName [] = "CtlFrameWork_ReflectWindow"; BYTE g_fRegisteredReflect = FALSE; BOOL g_fDBCSEnabled = FALSE; extern HINSTANCE g_hInstResources; extern HINSTANCE g_hinstVersion; #ifdef MDAC_BUILD extern HINSTANCE g_hOleAutHandle; #else extern HANDLE g_hOleAutHandle; #endif extern const int g_ctCATIDImplemented; extern const CATID* g_rgCATIDImplemented[]; // ref count for LockServer // LONG g_cLocks; // private routines for this file. // int IndexOfOleObject(REFCLSID); HRESULT RegisterAllObjects(void); HRESULT UnregisterAllObjects(void); void CleanupGlobalObjects(void); //=--------------------------------------------------------------------------= // DllMain //=--------------------------------------------------------------------------= // yon standard LibMain. // // Parameters and Output: // - see SDK Docs on DllMain // // Notes: // BOOL WINAPI DllMain ( HANDLE hInstance, DWORD dwReason, void *pvReserved ) { // int i; switch (dwReason) { // set up some global variables, and get some OS/Version information // set up. // case DLL_PROCESS_ATTACH: { DWORD dwVer = GetVersion(); DWORD dwWinVer; // swap the two lowest bytes of dwVer so that the major and minor version // numbers are in a usable order. // for dwWinVer: high byte = major version, low byte = minor version // OS Sys_WinVersion (as of 5/2/95) // =-------------= =-------------= // Win95 0x035F (3.95) // WinNT ProgMan 0x0333 (3.51) // WinNT Win95 UI 0x0400 (4.00) // dwWinVer = (UINT)(((dwVer & 0xFF) << 8) | ((dwVer >> 8) & 0xFF)); g_fSysWinNT = FALSE; g_fSysWin95 = FALSE; g_fSysWin95Shell = FALSE; if (dwVer < 0x80000000) { g_fSysWinNT = TRUE; g_fSysWin95Shell = (dwWinVer >= 0x0334); } else { g_fSysWin95 = TRUE; g_fSysWin95Shell = TRUE; } // initialize a critical seciton for our apartment threading support // InitializeCriticalSection(&g_CriticalSection); // create an initial heap for everybody to use. // currently, we're going to let the system make things thread-safe, // which will make them a little slower, but hopefully not enough // to notice // if (!g_hHeap) g_hHeap = GetProcessHeap(); if (!g_hHeap) { FAIL("Couldn't get Process Heap. Not good!"); return FALSE; } g_hInstance = (HINSTANCE)hInstance; // this causes DllMain to NOT get called for DLL_THREAD_ATTACH and DETACH. // if you are interested in these notifications, please remove this line. // DisableThreadLibraryCalls(g_hInstance); g_fDBCSEnabled = GetSystemMetrics(SM_DBCSENABLED); // Initialize OleAut // g_hOleAutHandle = LoadLibrary("oleaut32.dll"); // give the user a chance to initialize whatever // InitializeLibrary(); #ifdef DEBUG TCHAR lpCtlName[255]; DWORD nSize = 255; DWORD fValidPath; // set all ctl debug switches // fValidPath = GetModuleFileName(g_hInstance, (LPTSTR)lpCtlName, nSize); if (fValidPath != 0) SetCtlSwitches((LPSTR)lpCtlName); // initialize a critical seciton for our heap memory leak detection // InitializeCriticalSection(&g_csHeap); g_fInitCrit = TRUE; #endif // DEBUG return TRUE; } // do a little cleaning up! // case DLL_PROCESS_DETACH: #ifdef VS_HELP ASSERT(g_pIVsHelpSystem == NULL, "IVsHelpSystem didn't get released"); #endif // clean up some stuff // DeleteCriticalSection(&g_CriticalSection); CleanupGlobalObjects(); // give the user a chance to do some cleaning up // UninitializeLibrary(); // Deinitialize OleAut, But not in Win95. // Calling FreeLibrary under Win95 for OleAut // will sometimes cause a crash (It seems that // there can be a rpoblem in which OleAut is called // from OleUnitnitialize and causes a problem with FreeLibrary. // if (g_hOleAutHandle && !g_fSysWin95) { FreeLibrary((HINSTANCE)g_hOleAutHandle); g_hOleAutHandle = NULL; } // Make sure we free up our cached resource handle for localized resources // if (g_hInstResources && g_hInstResources != g_hInstance) FreeLibrary(g_hInstResources); // Free up VERSION.DLL // if (g_hinstVersion) { FreeLibrary(g_hinstVersion); g_hinstVersion = NULL; } #ifdef DEBUG // check for memory leaks // CheckForLeaks(); // free critical section used for leak checking // DeleteCriticalSection(&g_csHeap); g_fInitCrit = FALSE; #endif // DEBUG return TRUE; } return TRUE; } //=--------------------------------------------------------------------------= // CleanupGlobalObjects //=--------------------------------------------------------------------------= // duh // // Notes: // void CleanupGlobalObjects(void) { int i = 0; while (!ISEMPTYOBJECT(i)) { if (g_ObjectInfo[i].usType == OI_CONTROL) { if (CTLWNDCLASSREGISTERED(i)) UnregisterClass(WNDCLASSNAMEOFCONTROL(i), g_hInstance); } i++; } // clean up our parking window. // if (g_hwndParking) { DestroyWindow(g_hwndParking); g_hwndParking = NULL; UnregisterClass("CtlFrameWork_Parking", g_hInstance); } // clean up after reflection, if appropriate. // if (g_fRegisteredReflect) { UnregisterClass(g_szReflectClassName, g_hInstance); g_fRegisteredReflect = FALSE; } } //=--------------------------------------------------------------------------= // DllRegisterServer //=--------------------------------------------------------------------------= // registers the Automation server // // Output: // HRESULT // // Notes: // STDAPI DllRegisterServer ( void ) { HRESULT hr; hr = RegisterAllObjects(); RETURN_ON_FAILURE(hr); // call user registration function. // return (RegisterData())? S_OK : E_FAIL; } //=--------------------------------------------------------------------------= // DllUnregisterServer //=--------------------------------------------------------------------------= // unregister's the Automation server // // Output: // HRESULT // // Notes: // STDAPI DllUnregisterServer ( void ) { HRESULT hr; hr = UnregisterAllObjects(); RETURN_ON_FAILURE(hr); // call user unregistration function // return (UnregisterData()) ? S_OK : E_FAIL; } //=--------------------------------------------------------------------------= // DllCanUnloadNow //=--------------------------------------------------------------------------= // we are being asked whether or not it's okay to unload the DLL. just check // the lock counts on remaining objects ... // // Output: // HRESULT - S_OK, can unload now, S_FALSE, can't. // // Notes: // STDAPI DllCanUnloadNow ( void ) { #ifdef VS_HELP if (g_pIVsHelpSystem) { g_pIVsHelpSystem->Release(); g_pIVsHelpSystem = NULL; } #endif // if there are any objects lying around, then we can't unload. The // controlling CUnknownObject class that people should be inheriting from // takes care of this // #ifdef MDAC_BUILD return (g_cLocks || !CanUnloadLibraryNow()) ? S_FALSE : S_OK; #else return (g_cLocks) ? S_FALSE : S_OK; #endif } //=--------------------------------------------------------------------------= // DllGetClassObject //=--------------------------------------------------------------------------= // creates a ClassFactory object, and returns it. // // Parameters: // REFCLSID - CLSID for the class object // REFIID - interface we want class object to be. // void ** - pointer to where we should ptr to new object. // // Output: // HRESULT - S_OK, CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, // E_INVALIDARG, E_UNEXPECTED // // Notes: // STDAPI DllGetClassObject ( REFCLSID rclsid, REFIID riid, void **ppvObjOut ) { HRESULT hr; void *pv; int iIndex; // arg checking // if (!ppvObjOut) return E_INVALIDARG; // first of all, make sure they're asking for something we work with. // iIndex = IndexOfOleObject(rclsid); if (iIndex == -1) #ifdef MDAC_BUILD // NOTE: LibraryGetClassObject() hook for ATL/VS98 support, added by markash return LibraryGetClassObject(rclsid, riid, ppvObjOut); #else return CLASS_E_CLASSNOTAVAILABLE; #endif // create the blank object. // pv = (void *)new CClassFactory(iIndex); if (!pv) return E_OUTOFMEMORY; // QI for whatever the user has asked for. // hr = ((IUnknown *)pv)->QueryInterface(riid, ppvObjOut); ((IUnknown *)pv)->Release(); return hr; } //=--------------------------------------------------------------------------= // IndexOfOleObject //=--------------------------------------------------------------------------= // returns the index in our global table of objects of the given CLSID. if // it's not a supported object, then we return -1 // // Parameters: // REFCLSID - [in] duh. // // Output: // int - >= 0 is index into global table, -1 means not supported // // Notes: // int IndexOfOleObject ( REFCLSID rclsid ) { int x = 0; // an object is creatable if it's CLSID is in the table of all allowable object // types. // while (!ISEMPTYOBJECT(x)) { if (OBJECTISCREATABLE(x)) { if (rclsid == CLSIDOFOBJECT(x)) return x; } x++; } return -1; } //=--------------------------------------------------------------------------= // RegisterAllObjects //=--------------------------------------------------------------------------= // registers all the objects for the given automation server. // // Parameters: // none // // Output: // HERSULT - S_OK, E_FAIL // // Notes: // HRESULT RegisterAllObjects ( void ) { ITypeLib *pTypeLib = NULL; HRESULT hr; DWORD dwPathLen; char szTmp[MAX_PATH]; char szHelpPath[MAX_PATH]; int x = 0; BOOL fHelpFile = FALSE; long lMajor = -1, lMinor = -1; UINT cbWinHelpPath = 0; OLECHAR *pwszHelpPath; BSTR bstrTypeLibName = NULL; WORD wFlags = 0; #if DEBUG BOOL fCtlFlagFound = FALSE; BOOL fCtlTypeLib = FALSE; int iCatID; BOOL fCatIDFound = FALSE; #endif // Load and register our type library. // if (g_fServerHasTypeLibrary) { TLIBATTR *ptlattr; dwPathLen = GetModuleFileName(g_hInstance, szTmp, MAX_PATH); bstrTypeLibName = BSTRFROMANSI(szTmp); hr = LoadTypeLib(bstrTypeLibName, &pTypeLib); if (FAILED(hr)) goto CleanUp; pTypeLib->GetLibAttr(&ptlattr); lMajor = ptlattr->wMajorVerNum; lMinor = ptlattr->wMinorVerNum; #if DEBUG fCtlTypeLib = ptlattr->wLibFlags & LIBFLAG_FCONTROL; #endif pTypeLib->ReleaseTLibAttr(ptlattr); } // loop through all of our creatable objects [those that have a clsid in // our global table] and register them. // while (!ISEMPTYOBJECT(x)) { if (!OBJECTISCREATABLE(x)) { x++; continue; } // Check to see if there is a help file for the object // If so, look for it in the Windows\Help directory. If a help file is // found for any object in the Windows\Help directory, then we'll register it with // the typelib. Once we find the first help file we stop looking. // if (!fHelpFile) { if (cbWinHelpPath == 0) { cbWinHelpPath = GetHelpFilePath(szHelpPath, MAX_PATH); lstrcat(szHelpPath, "\\"); cbWinHelpPath++; } ASSERT(cbWinHelpPath > 0, "Help path is zero length"); ASSERT(cbWinHelpPath + ((HELPFILEOFOBJECT(x)) ? lstrlen(HELPFILEOFOBJECT(x)) : 0) < MAX_PATH, "Help file path exceeds maxiumu path"); // Make sure we have a non-NULL pointer before calling lstrlen // and check that the helpfile exists and isn't a directory // if (HELPFILEOFOBJECT(x) && lstrlen(HELPFILEOFOBJECT(x)) > 0) { lstrcpyn(szHelpPath + cbWinHelpPath, HELPFILEOFOBJECT(x), lstrlen(HELPFILEOFOBJECT(x)) + 1); fHelpFile = ((GetFileAttributes(szHelpPath) & FILE_ATTRIBUTE_DIRECTORY) == 0); } // Once we've determined the help file exists, terminate after the filename // since all we care to register is the path. Not the path and filename. We also // don't want the terminating '\', so subtract 1 from cbWinHelpPath. // if (fHelpFile) szHelpPath[cbWinHelpPath - 1] = '\0'; else szHelpPath[cbWinHelpPath] = '\0'; } // depending on the object type, register different pieces of information // switch (g_ObjectInfo[x].usType) { // for both simple co-creatable objects and proeprty pages, do the same // thing // case OI_UNKNOWN: case OI_PROPERTYPAGE: #if DEBUG // For debug builds, verify that the cached object data matches the typeinfo attributes for that object // hr = GetTypeFlagsForGuid(pTypeLib, CLSIDOFOBJECT(x), &wFlags); if (SUCCEEDED(hr)) { if (NULL != CREATEFNOFOBJECT(x)) { ASSERT(wFlags & TYPEFLAG_FCANCREATE, "Create flag not found on creatable object"); } else { ASSERT(!(wFlags & TYPEFLAG_FCANCREATE), "Create flag found on non-creatable object"); } } #endif RegisterUnknownObject(NAMEOFOBJECT(x), LABELOFOBJECT(x), CLSIDOFOBJECT(x), ISAPARTMENTMODELTHREADED(x)); break; case OI_AUTOMATION: #if DEBUG // For debug builds, verify that the cached object data matches the typeinfo attributes for that object // hr = GetTypeFlagsForGuid(pTypeLib, CLSIDOFOBJECT(x), &wFlags); if (SUCCEEDED(hr)) { if (NULL != CREATEFNOFOBJECT(x)) { ASSERT(wFlags & TYPEFLAG_FCANCREATE, "Create flag not found on creatable object"); } else { ASSERT(!(wFlags & TYPEFLAG_FCANCREATE), "Create flag found on non-creatable object"); } } #endif RegisterAutomationObject(g_szLibName, NAMEOFOBJECT(x), LABELOFOBJECT(x), VERSIONOFOBJECT(x), lMajor, lMinor, *g_pLibid, CLSIDOFOBJECT(x), ISAPARTMENTMODELTHREADED(x)); break; case OI_CONTROL: { BOOL fControl = TRUE; // Go to the TypeInfo for the object and see if it has the control bit set // We should only add the Control and ToolboxBitmap32 registry key for objects // that have the Control bit set in their typelib. // // Note: If the TypeLib can't be found or there is an error attempting to // retrieve the control flag, we default to setting the Control bit. // Since we're attempting to register the object as a control our // default assumption will be that it is a control. // hr = GetTypeFlagsForGuid(pTypeLib, CLSIDOFOBJECT(x), &wFlags); if (SUCCEEDED(hr)) { fControl = wFlags & TYPEFLAG_FCONTROL; #if DEBUG fCtlFlagFound |= fControl; // For debug builds, verify that the cached object data matches the typeinfo attributes for that object // if (NULL != CREATEFNOFOBJECT(x)) { ASSERT(wFlags & TYPEFLAG_FCANCREATE, "Create flag not found on creatable object"); } else { ASSERT(!(wFlags & TYPEFLAG_FCANCREATE), "Create flag found on non-creatable object"); } #endif } RegisterControlObject(g_szLibName, NAMEOFOBJECT(x), LABELOFOBJECT(x), VERSIONOFOBJECT(x), VERSIONMINOROFOBJECT(x), lMajor, lMinor, *g_pLibid, CLSIDOFOBJECT(x), OLEMISCFLAGSOFCONTROL(x), BITMAPIDOFCONTROL(x), ISAPARTMENTMODELTHREADED(x), fControl); } break; } x++; } // Make sure the if a TypeLib control attribute was found, a coclass control attribute is also found; // or neither is found. You can't have one without the other. // ASSERT((fCtlTypeLib && fCtlFlagFound) || (!fCtlTypeLib && !fCtlFlagFound), "TypeLib and coclass control attributes not set consistently"); if (g_fServerHasTypeLibrary) { ASSERT(pTypeLib, "TypeLib pointer is NULL"); ASSERT(SysStringLen(bstrTypeLibName) > 0, "TypeLib name is invalid"); if (fHelpFile) pwszHelpPath = OLESTRFROMANSI(szHelpPath); // Note: we have to pass in an empty string instead of NULL if fHelpFile==FALSE, because // otherwise OLEAUT leaves the old value of the HELPDIR key there (stephwe 9/97) hr = RegisterTypeLib(pTypeLib, bstrTypeLibName, fHelpFile ? pwszHelpPath : L""); if (fHelpFile) CoTaskMemFree(pwszHelpPath); pTypeLib->Release(); if (FAILED(hr)) goto CleanUp; } #if DEBUG // Make sure there is consistency between the Control flags set in the typelib // versus the CATID_Control attribute. // for (iCatID=0; iCatID < g_ctCATIDImplemented; iCatID++) { if (IsEqualGUID((REFGUID) *g_rgCATIDImplemented[iCatID], (REFGUID) CATID_Control)) { fCatIDFound = TRUE; break; } } ASSERT((fCatIDFound && fCtlFlagFound) || (!fCatIDFound && !fCtlFlagFound), "Typelib control attribute not in sync with CATID_Control setting"); #endif hr = S_OK; CleanUp: SysFreeString(bstrTypeLibName); return hr; } //=--------------------------------------------------------------------------= // UnregisterAllObjects //=--------------------------------------------------------------------------= // un-registers all the objects for the given automation server. // // Parameters: // none // // Output: // HRESULT - S_OK // // Notes: // WARNING! You must link with the new version of OLEAUT shipping with // Visual Basic version 5.0 in order for this function to // work correctly. // HRESULT UnregisterAllObjects ( void ) { HRESULT hr; int x = 0; char szTmp[MAX_PATH]; TLIBATTR *ptlibattr = NULL; ITypeLib *pTypeLib = NULL; // loop through all of our creatable objects [those that have a clsid in // our global table] and register them. // while (!ISEMPTYOBJECT(x)) { if (!OBJECTISCREATABLE(x)) { x++; continue; } switch (g_ObjectInfo[x].usType) { case OI_UNKNOWN: case OI_PROPERTYPAGE: UnregisterUnknownObject(CLSIDOFOBJECT(x), NULL); break; case OI_CONTROL: UnregisterControlObject(g_szLibName, NAMEOFOBJECT(x), VERSIONOFOBJECT(x), CLSIDOFOBJECT(x)); break; case OI_AUTOMATION: UnregisterAutomationObject(g_szLibName, NAMEOFOBJECT(x), VERSIONOFOBJECT(x), CLSIDOFOBJECT(x)); break; } x++; } // if we've got one, unregister our type library if (g_pLibid) { GetModuleFileName(g_hInstance, szTmp, MAX_PATH); MAKE_WIDEPTR_FROMANSI(pwsz, szTmp); hr = LoadTypeLibEx(pwsz, REGKIND_NONE, &pTypeLib); if (FAILED(hr)) goto CleanUp; hr = pTypeLib->GetLibAttr(&ptlibattr); if (FAILED(hr)) goto CleanUp; // Call OLEAUT to have it unregister our type library. It will handle // the case where there is a 16-bit version of the control's typelib // registered and will only blow away the 32-bit related keys in this case. // UnRegisterTypeLib(*g_pLibid, ptlibattr->wMajorVerNum, ptlibattr->wMinorVerNum, ptlibattr->lcid, ptlibattr->syskind); } CleanUp: if (ptlibattr) pTypeLib->ReleaseTLibAttr(ptlibattr); RELEASE_OBJECT(pTypeLib); return S_OK; }