Использование SqlServer CE без установки - PullRequest
3 голосов
/ 02 февраля 2012

Дано:

  • Чистая машина, SQL Server CE отсутствует.
  • Набор * .sdf файлов (базы данных Sql Server CE), не говоря уже о том, как они туда попали
  • Библиотеки DLL соответствующего SQL Server CE (sqlceca35.dll, sqlcecompact35.dll, sqlceer35EN.dll, sqlceme35.dll, sqlceoledb35.dll, sqlceqp35.dll, sqlcese35.dll)

Вопрос:

  • Как сделать доступным поставщик OLEDB Sql Server CE, реализованный вышеупомянутыми DLL. Я ищу программный способ сделать это при работе с ограниченной учетной записью.

Другими словами, если мы говорим о Sql Server CE 3.5, как сделать следующий код успешным:

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

Обратите внимание, что машина чистая и код работает как ограниченная учетная запись.

EDIT

Есть еще один улов. Код C ++, я не могу использовать Ado.NET

1 Ответ

2 голосов
/ 02 февраля 2012

spDBInitialize.CreateInstance() выполняет следующие действия:

  1. Поиск вашего CLSID в реестре Windows по адресу HKEY_CLASSES_ROOT \ 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, вы можете обойти это, сделав свой код просто реализующим 3, 4, 5 и 6.

Вот консольное приложение C ++, которое открывает SDF с помощью замены CoCreateInstance:

#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 Использование объектов ошибок OLE DB (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 Query Processor
  • sqlcese35.dll - SQLCE Storage Engine
  • sqlceer35EN.dll - SQLCE Собственные строки ошибок и ресурсы
  • sqlcecompact35.dll - Инструмент восстановления базы данных SQLCE

Для справки, я полагаю, вам не нужны следующие файлы:

  • sqlceca35.dll - Клиентский агент SQLCE (для репликации слиянием на SQL Server)
  • sqlceme35.dll - SQLCE Управляемые расширения
  • System.Data.SqlServerCe.Entity.dll - Управляемая сборка
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...