Using SqlServer CE without installation

时光怂恿深爱的人放手 提交于 2019-12-01 08:50:41

spDBInitialize.CreateInstance() does the following:

  1. Looks up your CLSID in the Windows Registry under HKEY_CLASSES_ROOT\CLSID
  2. Determines DLL from InProcServer
  3. Calls LoadLibrary() on the DLL
  4. Calls GetProcAddress for "DllGetClassObject"
  5. Calls DllGetClassObject to get an IClassFactory
  6. Uses returned IClassFactory to handle your CreateInstance(NULL, IID_IDBInitialize, (void**) &spIDBInitialize) request

In your scenario, you do cannot get pass the first step because your DLL isn't registered in the Windows Registry.

However, because you know where the SQL Server CE DLLs are you can get around this by making your code just implement 3, 4, 5 and 6.

Here's a C++ console application that opens a SDF using CoCreateInstance replacement:

#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <oleauto.h>
#include <atlbase.h>
#include "C:\Program Files (x86)\Microsoft SQL Server Compact Edition\v3.5\Include\sqlce_oledb.h"
#include "C:\Program Files (x86)\Microsoft SQL Server Compact Edition\v3.5\Include\sqlce_err.h"

//----------------------------------------------------------------------
// Creates a COM object using an HMODULE instead of the Windows Registry
//----------------------------------------------------------------------

HRESULT DllCoCreateInstance(HMODULE hModule, REFCLSID rclsid, LPUNKNOWN pUnkOuter, REFIID riid, LPVOID FAR* ppv)
{
    HRESULT hr = S_OK;

    if (hModule == NULL)
    {
        return E_INVALIDARG;
    }

    BOOL (WINAPI*DllGetClassObject)(REFCLSID, REFIID, LPVOID) = NULL;
    (FARPROC&) DllGetClassObject = GetProcAddress(hModule, "DllGetClassObject");
    if (DllGetClassObject == NULL)
    {
        return HRESULT_FROM_WIN32(GetLastError());
    }

    CComPtr<IClassFactory> spIClassFactory;
    hr = DllGetClassObject(rclsid, IID_IClassFactory, &spIClassFactory);
    if (FAILED(hr))
    {
        return hr;
    }

    return spIClassFactory->CreateInstance(pUnkOuter, riid, ppv);
}

//----------------------------------------------------------------------
// Open a close a SDF file
//----------------------------------------------------------------------

int _tmain(int argc, _TCHAR* argv[])
{
    HRESULT hr = S_OK;

    hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);

    // Need a loaded library so we can CoCreateInstance without the Windows Registry.
    HMODULE hModule = LoadLibrary(L"C:\\Program Files (x86)\\Microsoft SQL Server Compact Edition\\v3.5\\sqlceoledb35.dll");

    // Open a SQL Server CE 3.5 database without using Windows Registry.
    CComPtr<IDBInitialize> spIDBInitialize;
    //hr = spIDBInitialize.CoCreateInstance(CLSID_SQLSERVERCE_3_5);
    hr = DllCoCreateInstance(hModule, CLSID_SQLSERVERCE_3_5, NULL, IID_IDBInitialize, (void**) &spIDBInitialize);
    CComPtr<IDBProperties> spIDBProperties;
    hr = spIDBInitialize->QueryInterface(IID_IDBProperties, (void**) &spIDBProperties);
    CComVariant varDataSource(OLESTR("InsertYourSampleDatabase.SDF"));
    DBPROP prop = { DBPROP_INIT_DATASOURCE, DBPROPOPTIONS_REQUIRED, 0, DB_NULLID, varDataSource };
    DBPROPSET propSet = {&prop, 1, DBPROPSET_DBINIT};
    hr = spIDBProperties->SetProperties(1, &propSet);
    spIDBProperties = NULL;
    hr = spIDBInitialize->Initialize();

    // @@TODO: Do your regular OLEDB code with the opened database.
    //...

    // Close COM objects
    spIDBInitialize = NULL;

    CoUninitialize();
    return 0;
}

Some things that's missing from the code snippet:

  • Call FreeLibrary() when you're completely finished with the library (usually prior to program termination)
  • Handle bad HRESULT hr return codes
  • Handle LoadLibrary() failures

To get meaningful error messages for SQL Server CE operations you should consult Microsoft MSDN article Using OLE DB Error Objects (SQL Server Compact Edition). I usually start with a condense version of it here:

if (FAILED(hr))
{
    CComPtr<IErrorInfo> spIErrorInfo;
    GetErrorInfo(0, &spIErrorInfo);
    if (spIErrorInfo != NULL)
    {
        CComBSTR bstrError;
        spIErrorInfo->GetDescription(&bstrError);
        // @@TODO: Do stuff with bstrError
        wprintf("%s\r\n", (BSTR) bstrError);
    }
}

It's easier and safer to just deploy the entire SQL Server CE 3.5 folder, but, if you want a minimal set, I believe the following files are the important ones for your scenario:

  • sqlceoledb35.dll - SQLCE OLEDB Provider
  • sqlceqp35.dll - SQLCE Query Processor
  • sqlcese35.dll - SQLCE Storage Engine
  • sqlceer35EN.dll - SQLCE Native Error Strings and Resources
  • sqlcecompact35.dll - SQLCE Database Repair tool

For reference, the files I believe you don't need are:

  • sqlceca35.dll - SQLCE Client Agent (for Merge Replication to SQL Server)
  • sqlceme35.dll - SQLCE Managed Extensions
  • System.Data.SqlServerCe.Entity.dll - Managed Assembly
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!