//-------------------------------------------------------------------- // Microsoft OLE DB Sample Provider // (C) Copyright 1991 - 1999 Microsoft Corporation. All Rights Reserved. // // @doc // // @module CLASSFAC.CPP | The module contains the DLL Entry and Exit // points, plus the OLE ClassFactory class. // // // Includes ------------------------------------------------------------------ #include "headers.h" #include "classfac.h" #include "msdasc.h" //CLSID_RootBinder // Static vars --------------------------------------------------------------- static const char * s_strDllName = "SampProv"; // used with GetModuleHandle static const struct { char * strRegKey; char * strValueName; DWORD dwType; char * strValue; } s_rgRegInfo[] = { //CLSID_SampProv { "SampProv", NULL, REG_SZ, "Microsoft OLE DB Sample Provider" }, { "SampProv\\Clsid", NULL, REG_SZ, "{E8CCCB79-7C36-101B-AC3A-00AA0044773D}" }, { "CLSID\\{E8CCCB79-7C36-101B-AC3A-00AA0044773D}", NULL, REG_SZ, "SampProv" }, { "CLSID\\{E8CCCB79-7C36-101B-AC3A-00AA0044773D}", "OLEDB_SERVICES", REG_DWORD, "-1" }, { "CLSID\\{E8CCCB79-7C36-101B-AC3A-00AA0044773D}\\ProgID", NULL, REG_SZ, "SampProv" }, { "CLSID\\{E8CCCB79-7C36-101B-AC3A-00AA0044773D}\\VersionIndependentProgID",NULL, REG_SZ, "SampProv" }, { "CLSID\\{E8CCCB79-7C36-101B-AC3A-00AA0044773D}\\InprocServer32", NULL, REG_SZ, "%s" }, { "CLSID\\{E8CCCB79-7C36-101B-AC3A-00AA0044773D}\\InprocServer32", "ThreadingModel", REG_SZ, "Both" }, { "CLSID\\{E8CCCB79-7C36-101B-AC3A-00AA0044773D}\\OLE DB Provider", NULL, REG_SZ, "Microsoft OLE DB Sample Provider" }, //CLSID_SampProvConnectionPage { "SampProvConnectionPage", NULL, REG_SZ, "Microsoft OLE DB Sample Provider Connection Page" }, { "SampProvConnectionPage\\Clsid", NULL, REG_SZ, "{119C8711-905B-11d2-AF65-00C04F6F8697}" }, { "CLSID\\{119C8711-905B-11d2-AF65-00C04F6F8697}", NULL, REG_SZ, "SampProvConnectionPage" }, { "CLSID\\{119C8711-905B-11d2-AF65-00C04F6F8697}\\ProgID", NULL, REG_SZ, "SampProvConnectionPage" }, { "CLSID\\{119C8711-905B-11d2-AF65-00C04F6F8697}\\VersionIndependentProgID",NULL, REG_SZ, "SampProvConnectionPage" }, { "CLSID\\{119C8711-905B-11d2-AF65-00C04F6F8697}\\InprocServer32", NULL, REG_SZ, "%s" }, { "CLSID\\{119C8711-905B-11d2-AF65-00C04F6F8697}\\InprocServer32", "ThreadingModel", REG_SZ, "Both" }, //CLSID_SampProvAdvancedPage { "SampProvAdvancedPage", NULL, REG_SZ, "Microsoft OLE DB Sample Provider Advanced Page" }, { "SampProvAdvancedPage\\Clsid", NULL, REG_SZ, "{119C8712-905B-11d2-AF65-00C04F6F8697}" }, { "CLSID\\{119C8712-905B-11d2-AF65-00C04F6F8697}", NULL, REG_SZ, "SampProvAdvancedPage" }, { "CLSID\\{119C8712-905B-11d2-AF65-00C04F6F8697}\\ProgID", NULL, REG_SZ, "SampProvAdvancedPage" }, { "CLSID\\{119C8712-905B-11d2-AF65-00C04F6F8697}\\VersionIndependentProgID",NULL, REG_SZ, "SampProvAdvancedPage" }, { "CLSID\\{119C8712-905B-11d2-AF65-00C04F6F8697}\\InprocServer32", NULL, REG_SZ, "%s" }, { "CLSID\\{119C8712-905B-11d2-AF65-00C04F6F8697}\\InprocServer32", "ThreadingModel", REG_SZ, "Both" }, //CLSID_SampProvBinder { "SampProvBinder", NULL, REG_SZ, "Microsoft OLE DB Sample Provider Binder" }, { "SampProvBinder\\Clsid", NULL, REG_SZ, "{245E7460-B577-11D2-AF53-00C04F782926}" }, { "CLSID\\{245E7460-B577-11D2-AF53-00C04F782926}", NULL, REG_SZ, "SampProvBinder" }, { "CLSID\\{245E7460-B577-11D2-AF53-00C04F782926}\\ProgID", NULL, REG_SZ, "SampProvBinder" }, { "CLSID\\{245E7460-B577-11D2-AF53-00C04F782926}\\VersionIndependentProgID",NULL, REG_SZ, "SampProvBinder" }, { "CLSID\\{245E7460-B577-11D2-AF53-00C04F782926}\\InprocServer32", NULL, REG_SZ, "%s" }, { "CLSID\\{245E7460-B577-11D2-AF53-00C04F782926}\\InprocServer32", "ThreadingModel", REG_SZ, "Both" }, { "CLSID\\{245E7460-B577-11D2-AF53-00C04F782926}\\OLE DB Binder", NULL, REG_SZ, "Microsoft OLE DB Sample Provider Binder" }, }; // Code ---------------------------------------------------------------------- // DllMain ------------------------------------------------------------------- // // @func DLL Entry point where Instance and Thread attach/detach notifications // takes place. OLE is initialized and the IMalloc Interface pointer is obtained. // // @rdesc Boolean Flag // @flag TRUE | Successful initialization // @flag FALSE | Failure to intialize // BOOL WINAPI DllMain ( HINSTANCE hInstDLL, //@parm IN | Application Instance Handle DWORD fdwReason, //@parm IN | Indicated Process or Thread activity LPVOID lpvReserved //@parm IN | Reserved... ) { BOOL fRetVal = FALSE; SYSTEM_INFO SystemInformation; switch (fdwReason) { case DLL_PROCESS_ATTACH: // Assume successfully initialized fRetVal = TRUE; // Do one-time initialization when first process attaches if (!g_cAttachedProcesses) { g_hInstance = hInstDLL; // Get the system page size if (!g_dwPageSize) { GetSystemInfo( &SystemInformation ); // can't fail g_dwPageSize = SystemInformation.dwPageSize; } } // Do per-process initialization here... // Remember that another process successfully attached g_cAttachedProcesses++; break; case DLL_PROCESS_DETACH: // Clean up when the last process is going away if (g_cAttachedProcesses == 1) { } // Do per-process clean up here... // Remember that a process has detached g_cAttachedProcesses--; break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; } return fRetVal; } // DllGetClassObject --------------------------------------------------------- // // @func This function is exposed to OLE so that the classfactory can // be obtained. // // @rdesc HRESULT indicating status of routine // @flag S_OK | The object was retrieved successfully. // @flag CLASS_E_CLASSNOTAVAILABLE | DLL does not support class. // @flag E_OUTOFMEMORY | Out of memory. // @flag E_INVALIDARG | One or more arguments are invalid. // @flag E_UNEXPECTED | An unexpected error occurred. // @flag OTHER | Other HRESULTs returned by called functions // HRESULT CALLBACK DllGetClassObject ( REFCLSID rclsid, //@parm IN | CLSID of the object class to be loaded REFIID riid, //@parm IN | Interface on object to be instantiated LPVOID * ppvObj //@parm OUT | Pointer to interface that was instantiated ) { CClassFactory * pClassFactory; HRESULT hr; // Check for valid ppvObj pointer if (!ppvObj) return ResultFromScode( E_INVALIDARG ); // In case we fail, we need to zero output arguments *ppvObj = NULL; // We only service CLSID_SampProv if (rclsid != CLSID_SampProv && rclsid != CLSID_SampProvConnectionPage && rclsid != CLSID_SampProvAdvancedPage && rclsid != CLSID_SampProvBinder) return ResultFromScode( CLASS_E_CLASSNOTAVAILABLE ); // We only support the IUnknown and IClassFactory interfaces if (riid != IID_IUnknown && riid != IID_IClassFactory) return ResultFromScode( E_NOINTERFACE ); // Create our ClassFactory object pClassFactory = new CClassFactory(rclsid); if (pClassFactory == NULL) return ResultFromScode( E_OUTOFMEMORY ); // Get the desired interface on this object hr = pClassFactory->QueryInterface( riid, ppvObj ); if (!SUCCEEDED( hr )) SAFE_DELETE( pClassFactory ); return hr; } // DllCanUnloadNow ----------------------------------------------------------- // // @func Indicates whether the DLL is no longer in use and // can be unloaded. // // @rdesc HRESULT indicating status of routine // @flag S_OK | DLL can be unloaded now. // @flag S_FALSE | DLL cannot be unloaded now. // STDAPI DllCanUnloadNow( void ) { if (!g_cObj && !g_cLock) return ResultFromScode( S_OK ); else return ResultFromScode( S_FALSE ); } //----------------------------------------------------------------------------- // CClassFactory //----------------------------------------------------------------------------- // CClassFactory ------------------------------------------------------------- // // @mfunc Constructor for this class // // @rdesc NONE // CClassFactory::CClassFactory(REFCLSID clsid) { m_cRef = 0; m_clsid = clsid; // Increment global object count OBJECT_CONSTRUCTED(); } // ~CClassFactory ------------------------------------------------------------ // // @mfunc Destructor for this class // // @rdesc NONE // CClassFactory:: ~CClassFactory( void ) { // Decrement global object count OBJECT_DESTRUCTED(); } // QueryInterface ------------------------------------------------------------ // // @mfunc Returns a pointer to a specified interface. Callers use // QueryInterface to determine which interfaces the called object // supports. // // @rdesc HRESULT indicating the status of the method // @flag S_OK | Interface is supported and ppvObject is set. // @flag E_NOINTERFACE | Interface is not supported by the object // @flag E_INVALIDARG | One or more arguments are invalid. // STDMETHODIMP CClassFactory::QueryInterface ( REFIID riid, //@parm IN | Interface ID of the interface being queried for. LPVOID * ppvObj //@parm OUT | Pointer to interface that was instantiated ) { // Check for valid ppvObj pointer if (!ppvObj) return ResultFromScode( E_INVALIDARG ); // In case we fail, we need to zero output arguments *ppvObj = NULL; // Do we support this interface? if (riid == IID_IUnknown || riid == IID_IClassFactory) *ppvObj = (LPVOID) this; // If we're going to return an interface, AddRef it first if (*ppvObj) { ((LPUNKNOWN) *ppvObj)->AddRef(); return ResultFromScode( S_OK ); } else return ResultFromScode( E_NOINTERFACE ); } // AddRef -------------------------------------------------------------------- // // @mfunc Increments a persistence count for the object // // @rdesc Current reference count // STDMETHODIMP_( DBREFCOUNT ) CClassFactory::AddRef( void ) { return ++m_cRef; } // Release ------------------------------------------------------------------- // // @mfunc Decrements a persistence count for the object and if // persistence count is 0, the object destroys itself. // // @rdesc Current reference count // STDMETHODIMP_( DBREFCOUNT ) CClassFactory::Release( void ) { if (!--m_cRef) { delete this; return 0; } return m_cRef; } // CreateInstance ------------------------------------------------------------ // // @mfunc Creates an uninitialized instance of an object class. // Initialization is subsequently performed using another // interface-specific method // // @rdesc HRESULT indicating the status of the method // @flag S_OK | Interface is supported and ppvObject is set. // @flag E_NOINTERFACE | Interface is not supported by the object // @flag E_INVALIDARG | One or more arguments are invalid. // @flag E_OUTOFMEMORY | Memory could not be allocated // @flag OTHER | Other HRESULTs returned by called functions // STDMETHODIMP CClassFactory::CreateInstance ( LPUNKNOWN pUnkOuter, //@parm IN | Points to the controlling IUnknown interface REFIID riid, //@parm IN | Interface ID of the interface being queried for. LPVOID * ppvObj //@parm OUT | Pointer to interface that was instantiated ) { HRESULT hr = S_OK; CDataSource* pCDataSource = NULL; CPropertyPage* pCPropertyPage = NULL; CBinder * pBinder = NULL; // Check for valid ppvObj pointer if (!ppvObj) return E_INVALIDARG; // In case we fail, we need to zero output arguments *ppvObj = NULL; // If we're given a controlling IUnknown, it must ask for IUnknown. // Otherwise, the caller will end up getting a pointer to their pUnkOuter // instead of to the new object we create and will have no way of getting // back to this new object, so they won't be able to free it. Bad! if (pUnkOuter && riid != IID_IUnknown) return DB_E_NOAGGREGATION; //CLSID_SampProv if(m_clsid == CLSID_SampProv) { // Create a CDataSource object pCDataSource = new CDataSource( pUnkOuter ); } else if(m_clsid == CLSID_SampProvConnectionPage) { // Create a CDSLConnectionPage object pCPropertyPage = new CDSLConnectionPage(); } else if(m_clsid == CLSID_SampProvAdvancedPage) { // Create a CDSLAdvancedPage object pCPropertyPage = new CDSLAdvancedPage(); } else if(m_clsid == CLSID_SampProvBinder) { // Create a CBinder object pBinder = new CBinder(pUnkOuter); } else { return CLASS_E_CLASSNOTAVAILABLE; } //E_OUTOFMEMORY if(!pCDataSource && !pCPropertyPage && !pBinder) { return E_OUTOFMEMORY; } //Obtain the correct interface... if(pCDataSource) { hr = E_FAIL; if(pCDataSource->FInit()) hr = pCDataSource->QueryInterface( riid, ppvObj ); } else if(pBinder) { hr = E_OUTOFMEMORY; if(pBinder->FInit()) hr = pBinder->QueryInterface( riid, ppvObj ); } else { hr = pCPropertyPage->QueryInterface( riid, ppvObj ); } if(FAILED(hr)) { SAFE_DELETE(pCDataSource); SAFE_DELETE(pCPropertyPage); } return hr; } // LockServer ---------------------------------------------------------------- // // @mfunc Controls whether an object application is kept in memory. // Keeping the application alive in memory allows instances of this // class to be created more quickly. // // @rdesc HRESULT indicating the status of the method // @flag S_OK | Interface is supported and ppvObject is set. // STDMETHODIMP CClassFactory::LockServer ( BOOL fLock //@parm IN | TRUE or FALSE to lock or unlock ) { if (fLock) InterlockedIncrement( &g_cLock ); else InterlockedDecrement( &g_cLock ); return NOERROR; } //--------------------------------------------------------------------------- // @func Removes keys to the registry. // // @rdesc Returns NOERROR // // @comm // Special Notes: This allows us to avoid using a .reg file. // // Note that a more robust method would be to trace existing // CLSID and ProgID, and trace each from the other. This would handle the // case where either changed. Then should probably enumerate all keys under // the ProgID and CLSID, then delete them. // // Also note the problem with our exposing a different CLSID for the debug // and ndebug versions, yet the ProgID remains the same. Should we have // different ProgID's also? // //--------------------------------------------------------------------------- STDAPI DllUnregisterServer ( void ) { int i; int iNumErrors = 0; LONG stat; // Delete all table entries. Loop in reverse order, since they // are entered in a basic-to-complex order. // We cannot delete a key that has subkeys. // Ignore errors. for (i=NUMELEM( s_rgRegInfo ) - 1; i >= 0; i--) { stat = RegDeleteKey( HKEY_CLASSES_ROOT, s_rgRegInfo[i].strRegKey ); if ((stat != ERROR_SUCCESS) && (stat != ERROR_FILE_NOT_FOUND) ) iNumErrors++; } IRegisterProvider* pIRegisterProvider = NULL; //Obtain the Root Binder if(SUCCEEDED(CoCreateInstance(CLSID_RootBinder, NULL, CLSCTX_ALL, IID_IRegisterProvider, (void**)&pIRegisterProvider))) { //Unregister SampProv's URL prefix with the RootBinder //NOTE: Don't fail, since we may have never registered ourselves with the root binder pIRegisterProvider->UnregisterProvider(SAMPPROV_URL_PREFIX, 0, CLSID_SampProvBinder); pIRegisterProvider->Release(); } return ResultFromScode( iNumErrors ? E_FAIL : S_OK ); } //--------------------------------------------------------------------------- // @func Adds necessary keys to the registry. // // @rdesc Returns one of the following // @flag NOERROR | Registration succeeded // @flag E_FAIL | Something didn't work // // @comm // Special Notes: This allows us to avoid using a .reg file. // Here is what was in the SampProv.REG file of yore. // Note that now we have two CLSID's, one for DEBUG. Then each one // can point to a different .DLL. // //--------------------------------------------------------------------------- STDAPI DllRegisterServer ( void ) { HKEY hk; HMODULE hModule; DWORD dwDisposition; LONG stat; CHAR strFileName[MAX_PATH+1]; CHAR strOutBuff[300+1]; HRESULT hr = S_OK; // Get the full path name for this DLL. if (NULL == (hModule = GetModuleHandle( s_strDllName ))) return ResultFromScode( E_FAIL ); if (0 == GetModuleFileName( hModule, strFileName, sizeof( strFileName ) / sizeof( char ))) return ResultFromScode( E_FAIL ); // Make a clean start DllUnregisterServer(); // Loop through s_rgRegInfo, and put everything in it. // Every entry is based on HKEY_CLASSES_ROOT. for (ULONG i=0; i < NUMELEM( s_rgRegInfo ); i++) { // Fill in any "%s" arguments with the name of this DLL. if (s_rgRegInfo[i].dwType == REG_DWORD) *(DWORD*)strOutBuff = atol( s_rgRegInfo[i].strValue ); else StringCchPrintfA( strOutBuff, sizeof(strOutBuff), s_rgRegInfo[i].strValue, strFileName ); // Create the Key. If it exists, we open it. // Thus we can still change the value below. stat = RegCreateKeyEx( HKEY_CLASSES_ROOT, s_rgRegInfo[i].strRegKey, 0, // dwReserved NULL, // lpszClass REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, // security access mask NULL, // lpSecurityAttributes &hk, // phkResult &dwDisposition ); if (stat != ERROR_SUCCESS) return ResultFromScode( E_FAIL ); stat = RegSetValueEx( hk, // created above s_rgRegInfo[i].strValueName, // lpszValueName 0, // dwReserved s_rgRegInfo[i].dwType, // fdwType (BYTE *) strOutBuff, // value s_rgRegInfo[i].dwType == REG_SZ ? (DWORD)strlen( strOutBuff ) + 1 : // cbData, including null terminator sizeof(DWORD)); RegCloseKey( hk ); if (stat != ERROR_SUCCESS) return ResultFromScode( E_FAIL ); } IRegisterProvider* pIRegisterProvider = NULL; //Register with the RootBinder if(SUCCEEDED(CoCreateInstance(CLSID_RootBinder, NULL, CLSCTX_ALL, IID_IRegisterProvider, (void**)&pIRegisterProvider))) { //Register Sampprov's URL prefix with the RootBinder hr = pIRegisterProvider->SetURLMapping(SAMPPROV_URL_PREFIX, 0, CLSID_SampProvBinder); pIRegisterProvider->Release(); } return ResultFromScode( hr ); }