使用SqlServer CE而无需安装

时间:2012-02-01 20:05:29

标签: c++ com

假设:

  • 一台干净的机器,没有SQL Server CE。
  • 一组* .sdf文件(Sql Server CE数据库),别介意他们是如何到达那里的
  • 相关Sql Server CE的DLL(sqlceca35.dll,sqlcecompact35.dll,sqlceer35EN.dll,sqlceme35.dll,sqlceoledb35.dll,sqlceqp35.dll,sqlcese35.dll)

问题:

  • 如何使上述DLL实现的Sql Server CE OLEDB提供程序可用。我正在寻找一种以有限帐户运行的程序化方式。

换句话说,假设我们正在谈论Sql Server CE 3.5,如何使以下代码成功:

IDBInitializePtr spDBInitialize;
HRESULT hr = spDBInitialize.CreateInstance(CLSID_SQLSERVERCE35, NULL);

请注意,该计算机是干净的,并且代码作为受限帐户运行。

修改

还有另一个问题。代码是C ++,我不能使用Ado.NET

1 个答案:

答案 0 :(得分:2)

spDBInitialize.CreateInstance()执行以下操作:

  1. 在HKEY_CLASSES_ROOT \ CLSID
  2. 下的Windows注册表中查找您的CLSID
  3. 确定InProcServer中的DLL
  4. 在DLL上调用LoadLibrary()
  5. 为“DllGetClassObject”
  6. 调用GetProcAddress
  7. 致电DllGetClassObject以获取IClassFactory
  8. 使用返回的IClassFactory来处理您的CreateInstance(NULL, IID_IDBInitialize, (void**) &spIDBInitialize)请求
  9. 在您的方案中,您无法通过第一步,因为您的DLL未在Windows注册表中注册。

    但是,因为您知道SQL Server CE DLL的位置,所以您可以通过使代码实现3,4,5和6来解决这个问题。

    这是一个C ++控制台应用程序,它使用CoCreateInstance替换打开SDF:

    #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;
    }
    

    代码段中遗漏了一些内容:

    • 当您完成图书馆(通常在程序终止之前)时调用FreeLibrary()
    • 处理错误的HRESULT hr返回码
    • 处理LoadLibrary()失败

    要获取有关SQL Server CE操作的有意义的错误消息,请参阅Microsoft MSDN文章Using OLE DB Error Objects (SQL Server Compact Edition)。我通常在这里开始使用它的缩写版本:

    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);
        }
    }
    

    仅部署整个SQL Server CE 3.5文件夹更简单,更安全,但是,如果您想要一个最小集合,我相信以下文件是您的场景的重要文件:

    • sqlceoledb35.dll - SQLCE OLEDB Provider
    • sqlceqp35.dll - SQLCE查询处理器
    • sqlcese35.dll - SQLCE存储引擎
    • sqlceer35EN.dll - SQLCE本机错误字符串和资源
    • sqlcecompact35.dll - SQLCE数据库修复工具

    作为参考,我相信你不需要的文件是:

    • sqlceca35.dll - SQLCE客户端代理(用于合并复制到SQL Server)
    • sqlceme35.dll - SQLCE托管扩展程序
    • System.Data.SqlServerCe.Entity.dll - 托管程序集