2012-02-01 62 views
3

考慮:採用SqlServer的CE,無需安裝

  • 一個乾淨的機器,沒有的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

回答

2

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

  1. 下HKEY_CLASSES_ROOT \ CLSID中查找在Windows註冊表中的CLSID
  2. 確定DLL從InProcServer
  3. 呼叫LoadLibrary()在DLL上
  4. 調用GetProcAddress代替「DllGetClassObject」
  5. 調用DllGetClassObject得到一個IClassFactory
  6. 用途返回IClassFactory來處理你的請求CreateInstance(NULL, IID_IDBInitialize, (void**) &spIDBInitialize)

在你的情況下,你不能獲得通過第一個步驟,因爲您的DLL沒有在Windows註冊表中註冊。

但是,因爲您知道SQL Server CE DLL的位置,您可以通過讓代碼只實現3,4,5和6來解決此問題。

下面是打開使用CoCreateInstance的更換SDF一個C​​ ++控制檯應用程序:

#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小時返回代碼
  • 處理負載庫()故障

要獲取有意義的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提供
  • 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 - 管理大會
+0

+1 - 我現在要檢查它。我只希望他們的OLEDB提供者不會在裏面做另一個'CreateInstance'。 – mark 2012-02-02 11:34:43

+0

它會好的。過去我已經成功地將這種技術用於sdf文件。 – 2012-02-02 12:03:35

+0

這是令人難以置信的!這意味着SQL Server CE是最小的嵌入式數據庫! sqlceoledb40.dll只有167K,而sqlite3.lib超過2M。漁獲在哪裏? – mark 2012-02-02 12:53:32