running .net application from c++ - c++

I have a byte array of a .NET application inside c++ code.
I want to execute this .NET application without writing those bytes on the disk. ICLRRuntimeHost::ExecuteInDefaultAppDomain expects a path to the assembly so it's out of the equation here. I'm looking for a possible way (or hack) to pass the binary directly to the clr.
So what i can do ?

//todo error checks/cleanup
HRESULT hr;
ICLRMetaHost *pMetaHost = NULL;
ICLRRuntimeInfo *pRuntimeInfo = NULL;
ICorRuntimeHost *pCorRuntimeHost = NULL;
IUnknownPtr spAppDomainThunk = NULL;
_AppDomainPtr spDefaultAppDomain = NULL;
bstr_t bstrAssemblyName(L"");
_AssemblyPtr spAssembly = NULL;
bstr_t bstrClassName(L"");
_TypePtr spType = NULL;
variant_t vtEmpty;
bstr_t bstrStaticMethodName(L"Main");
variant_t vtLengthRet;
hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost));
const wchar_t* pszVersion = L"v2.0.50727";
hr = pMetaHost->GetRuntime(pszVersion, IID_PPV_ARGS(&pRuntimeInfo));
BOOL fLoadable;
hr = pRuntimeInfo->IsLoadable(&fLoadable);
if (!fLoadable) { wprintf(L".NET runtime %s cannot be loaded\n", pszVersion); return; }
hr = pRuntimeInfo->GetInterface(CLSID_CorRuntimeHost, IID_PPV_ARGS(&pCorRuntimeHost));
hr = pCorRuntimeHost->Start();
hr = pCorRuntimeHost->GetDefaultDomain(&spAppDomainThunk);
hr = spAppDomainThunk->QueryInterface(IID_PPV_ARGS(&spDefaultAppDomain));
SAFEARRAYBOUND bounds[1];
bounds[0].cElements = array_len;
bounds[0].lLbound = 0;
SAFEARRAY* arr = SafeArrayCreate(VT_UI1, 1, bounds);
SafeArrayLock(arr);
memcpy(arr->pvData, bytearray, array_len);
SafeArrayUnlock(arr);
hr = spDefaultAppDomain->Load_3(arr, &spAssembly);
hr = spAssembly->GetType_2(bstrClassName, &spType);
hr = spType->InvokeMember_3(bstrStaticMethodName, static_cast<BindingFlags>(BindingFlags_InvokeMethod | BindingFlags_Static | BindingFlags_Public), NULL, vtEmpty, nullptr, &vtLengthRet);
SafeArrayDestroy(arr);

Related

Stream Buffer crashes in qdv.dll Win7

I have this code for streaming to/from a stream buffer. I've left all error checking out to make the code easier to read and see what I'm doing.
ICaptureGraphBuilder2* pCaptureGraphBuilder = nullptr;
IGraphBuilder* pGraphCapture = nullptr;
IMediaControl* pControlCapture = nullptr;
IGraphBuilder* pGraphStream = nullptr;
IMediaControl* pControlStream = nullptr;
IBaseFilter* pFilterVideoIn = nullptr;
IBaseFilter* pFilterDVEncode = nullptr;
IBaseFilter* pFilterBufferCapture = nullptr;
IBaseFilter* pFilterBufferStream = nullptr;
// streams
IStreamBufferSink2* pBufferCapture = nullptr;
IStreamBufferSource* pBufferStream = nullptr;
// This sets up the streaming capture
HRESULT hr = CoCreateInstance(CLSID_CaptureGraphBuilder2,nullptr,CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&pCaptureGraphBuilder));
hr = CoCreateInstance(CLSID_FilterGraph,nullptr,CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&pGraphCapture));
hr = pCaptureGraphBuilder->SetFiltergraph(pGraphCapture);
hr = pGraphCapture->QueryInterface(IID_IMediaControl,(VOID**)&pControlCapture);
hr = EnumClassForFilterName(CLSID_VideoInputDeviceCategory,TEXT_CAPTUREDEVICE,&pFilterVideoIn); // This functions creates an instance of the capture device
hr = pGraphCapture->AddFilter(pFilterVideoIn,L"VideoIn");
hr = CoCreateInstance(CLSID_DVVideoEnc,nullptr,CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&pFilterDVEncode));
hr = pGraphCapture->AddFilter(pFilterDVEncode,L"DVEncoder");
hr = CoCreateInstance(CLSID_StreamBufferSink,nullptr,CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&pBufferCapture));
hr = pBufferCapture->QueryInterface(IID_PPV_ARGS(&pFilterBufferCapture));
hr = pGraphCapture->AddFilter(pFilterBufferCapture,L"BufferSink");
hr = pCaptureGraphBuilder->RenderStream(&PIN_CATEGORY_CAPTURE,&MEDIATYPE_Video,pFilterVideoIn,pFilterDVEncode,pFilterBufferCapture);
hr = pBufferCapture->LockProfile(L"C:\\save.tmp");
// now work on the stream in
hr = CoCreateInstance(CLSID_FilterGraph,nullptr,CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&pGraphStream));
hr = pGraphStream->QueryInterface(IID_IMediaControl,(VOID**)&pControlStream);
hr = CoCreateInstance(CLSID_StreamBufferSource,nullptr,CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&pBufferStream));
hr = pBufferStream->QueryInterface(IID_PPV_ARGS(&pFilterBufferStream));
hr = pGraphStream->AddFilter(pFilterBufferStream,L"StreamBufferSource");
hr = pBufferStream->SetStreamSink(pBufferCapture);
IEnumPins* pEnumPins = nullptr;
IPin* pPin = nullptr;
hr = pFilterBufferStream->EnumPins(&pEnumPins);
while(pEnumPins->Next(1,&pPin,nullptr) == S_OK){
hr = pGraphStream->Render(pPin);
pPin->Release();
}
// Which filters are really in the graph
// capture graph
OutputDebugString(L"-----------------------\n");
OutputDebugString(L"StreamIn Graph Filters\n");
OutputDebugString(L"\n");
IEnumFilters* pFilterEnum = nullptr;
IBaseFilter* pFilter = nullptr;
WCHAR name[256] = {0};
hr = pGraphCapture->EnumFilters(&pFilterEnum);
while(pFilterEnum->Next(1,&pFilter,nullptr) == S_OK){
FILTER_INFO fi={0};
pFilter->QueryFilterInfo(&fi);
StringCchPrintf(name,255,L"%s\n",fi.achName);
OutputDebugString(name);
fi.pGraph->Release();
pFilter->Release();
}
OutputDebugString(L"-----------------------\n");
// stream graph
OutputDebugString(L"-----------------------\n");
OutputDebugString(L"StreamSource Graph Filters\n");
OutputDebugString(L"\n");
pFilterEnum = nullptr;
pFilter = nullptr;
hr = pGraphStream->EnumFilters(&pFilterEnum);
while(pFilterEnum->Next(1,&pFilter,nullptr) == S_OK){
FILTER_INFO fi={0};
pFilter->QueryFilterInfo(&fi);
WCHAR name[256]={0};
StringCchPrintf(name,256,L"%s\n",fi.achName);
OutputDebugString(name);
fi.pGraph->Release();
pFilter->Release();
}
OutputDebugString(L"-----------------------\n");
hr = pControlCapture->Run();
hr = pControlStream->Run();
[SNIP]
and it crashes as soon as the 2nd graph starts to run with
First-chance exception at 0x000007fef3ce42e0 (qdv.dll) in StreamBuffer.exe: 0xC0000005: Access violation reading location 0x00000000000001c5.
Unhandled exception at 0x000007fef3ce42e0 (qdv.dll) in StreamBuffer.exe: 0xC0000005: Access violation reading location 0x00000000000001c5.
Which is telling me that something is not happy inside qdv.dll. So I downloaded the debug symbols to help diagnose whats really happening.
In the call stack I get
qdv.dll!CDVVideoCodec::Receive() + 0x220 bytes
qdv.dll!CTransformInputPin::Receive() + 0x4c bytes
qdv.dll!CBaseInputPin::ReceiveMultiple() + 0x49 bytes
sbe.dll!COutputQueue::ThreadProc() + 0xca bytes
sbe.dll!COutputQueue::InitialThreadProc() + 0x1c bytes
kernel32.dll!BaseThreadInitThunk() + 0xd bytes
ntdll.dll!RtlUserThreadStart() + 0x21 bytes
This tells me that perhaps I haven't supplied enough information in one of the graphs for DVEncoder. I've tried various settings for the codec but nothing works and I get the same crash in the same place with the same error.
All help is appreciated.

IIS Client Certificate Mapping Authentication

I am trying to programmatically add onetoone client certificate authentication to the applicationhost.config file.
After referring to these two documents(thread1, thread2), I am sure that it is possible to implement it with different languages. And for some kind of reason I have to develop it with C++. While translating the code sample in thread1,
Below is the code snippet FYI.
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <ahadmin.h>
#include <crtdbg.h>
#include <string>
using namespace std;
void PrintPropertiesOfElement(IAppHostElement *pElement)
{
HRESULT hr = S_OK;
IAppHostPropertyCollection *pProperties = NULL;
IAppHostProperty *pProperty = NULL;
hr = pElement->get_Properties(&pProperties);
DWORD properties_count = 0;
hr = pProperties->get_Count(&properties_count);
VARIANT vtIndex;
vtIndex.vt = VT_INT;
for(DWORD i=0; i<properties_count; ++i)
{
vtIndex.intVal = i;
hr = pProperties->get_Item(vtIndex, &pProperty);
BSTR strName;
BSTR strValue;
hr = pProperty->get_Name(&strName);
hr = pProperty->get_StringValue(&strValue);
_tprintf(_T("name : %s, value: %s\n"), strName, strValue);
}
}
void PrintElementsOfCollection(IAppHostChildElementCollection *pCollection)
{
HRESULT hr = S_OK;
IAppHostElement *pElement = NULL;
DWORD elements_count = 0;
hr = pCollection->get_Count(&elements_count);
VARIANT vtIndex;
vtIndex.vt = VT_INT;
for(DWORD i=0; i<elements_count; ++i)
{
vtIndex.intVal = i;
hr = pCollection->get_Item(vtIndex, &pElement);
BSTR strName;
hr = pElement->get_Name(&strName);
_tprintf(_T("element : %s\n"), strName);
}
}
void PrintElementsOfCollection(IAppHostElementCollection *pCollection)
{
HRESULT hr = S_OK;
IAppHostElement *pElement = NULL;
DWORD elements_count = 0;
hr = pCollection->get_Count(&elements_count);
VARIANT vtIndex;
vtIndex.vt = VT_INT;
for(DWORD i=0; i<elements_count; ++i)
{
vtIndex.intVal = i;
hr = pCollection->get_Item(vtIndex, &pElement);
BSTR strName;
hr = pElement->get_Name(&strName);
_tprintf(_T("element : %s\n"), strName);
//PrintPropertiesOfElement(pElement);
}
}
struct UserCertification
{
VARIANT username;
VARIANT password;
VARIANT certification;
public:
UserCertification(wstring name, wstring pwd, wstring cert)
{
username.vt = VT_BSTR;
username.bstrVal = SysAllocString(name.c_str());
password.vt = VT_BSTR;
password.bstrVal = SysAllocString(pwd.c_str());
certification.vt = VT_BSTR;
certification.bstrVal = SysAllocString(cert.c_str());
}
};
HRESULT SetHostElementProperty(IAppHostElement *pElement, UserCertification *pUserCert)
{
HRESULT hr = S_OK;
IAppHostProperty *pProperty = NULL;
BSTR name = SysAllocString(L"userName");
BSTR password = SysAllocString(L"password");
BSTR certification = SysAllocString(L"certificate");
//name
hr = pElement->GetPropertyByName(name, &pProperty);
pProperty->put_Value(pUserCert->username);
//password
hr = pElement->GetPropertyByName(password, &pProperty);
pProperty->put_Value(pUserCert->password);
//certification
hr = pElement->GetPropertyByName(certification, &pProperty);
pProperty->put_Value(pUserCert->certification);
return hr;
}
UserCertification* GenerateUserCertification()
{
wstring username = L"jinqiu.tao#emacle.com";
wstring password = L"123456";
wstring certificate = L"xxxxxxxx";
return new UserCertification(username, password, certificate);
}
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hr = S_OK;
IAppHostWritableAdminManager * pWMgr = NULL;
IAppHostConfigManager * pCfgMgr = NULL;
IAppHostConfigFile * pCfgFile = NULL;
IAppHostConfigLocationCollection * pLocations = NULL;
IAppHostElement *pAdminSection = NULL;
IAppHostElementCollection *pElementCollection = NULL;
IAppHostChildElementCollection *pChildElements = NULL;
IAppHostElement *pElement = NULL;
IAppHostElement *pNewElement = NULL;
BSTR bstrConfigCommitPath = SysAllocString(L"MACHINE/WEBROOT/APPHOST/Default Web Site");
BSTR bstrSectionName = SysAllocString(L"system.webServer/security/authentication/iisClientCertificateMappingAuthentication");
BSTR bstrOneToOne = SysAllocString(L"oneToOneMappings");
BSTR bstrElementName = SysAllocString(L"add");
// Initialize
hr = CoInitializeEx( NULL, COINIT_MULTITHREADED );
// Create
hr = CoCreateInstance( __uuidof( AppHostWritableAdminManager ), NULL,
CLSCTX_INPROC_SERVER,
__uuidof( IAppHostWritableAdminManager ), (void**) &pWMgr );
pWMgr -> put_CommitPath ( bstrConfigCommitPath );
hr = pWMgr->GetAdminSection(bstrSectionName, bstrConfigCommitPath, &pAdminSection);
hr = pAdminSection->get_ChildElements(&pChildElements);
PrintElementsOfCollection(pChildElements);
hr = pAdminSection->GetElementByName(bstrOneToOne, &pElement);
hr = pElement->get_Collection(&pElementCollection);
//PrintElementsOfCollection(pElementCollection);
hr = pElementCollection->CreateNewElement(bstrElementName, &pNewElement);
//PrintPropertiesOfElement(pNewElement);
hr = SetHostElementProperty(pNewElement, GenerateUserCertification());
//got and error saying that another process is accesssing the data
hr = pElementCollection->AddElement(pNewElement); //got an error code 0x80070021 here |||||||||||||||||
PrintElementsOfCollection(pElementCollection);
// Commit the changes to the configuration system
pWMgr->CommitChanges ( );
return 0;
}
As you see, I can create a new element, but not able to add it to the element collection.
What I want to do is just add a record to the onetoonemappings part.
<location path="Default Web Site">
<system.webServer>
<security>
<access sslFlags="None" />
<authentication>
<anonymousAuthentication enabled="true" />
<iisClientCertificateMappingAuthentication enabled="true" oneToOneCertificateMappingsEnabled="true">
<oneToOneMappings>
<add userName="yonggui.yu#emacle.com" password="[enc:AesProvider:4QEVwn3c530VH5sdwCl+Sm8G2eJesNEs4SaL6U5LrXg=:enc]" certificate="MIIFOjCCBCKgAwIBAgIKOAV" />
<add userName="yuyonggui#tbp.com" password="[enc:AesProvider:iBqmPwvbefiuiUZ03AyPD/0AxzD0HIb4SlJXKQGr9Ug=:enc]" certificate="MIIEjzCCA3egAwIBAgIKGgSFpwAAAA" />
<add userName="yonggui.yu#emacle.com" password="[enc:AesProvider:DogNZMKGrLa9ih2IO9PiMNUz9Ucggu9icKD7o8+U8dQ=:enc]" certificate="MIIFZzCCBE+gAwIBAgIHGAOD3e2==" />
</oneToOneMappings>
</iisClientCertificateMappingAuthentication>
</authentication>
</security>
</system.webServer>
I hope that I have made it clear enough. If you guys need any kind of additional information, please do not hesitate to inform me.
Looking forward for your help.
Best Regards,
Jordan

How to distinguish between items returned by EnumObjects of IShellFolder

I am trying to get the computers in my workgroup using Shell
HRESULT hr = S_OK;
ULONG celtFetched;
LPITEMIDLIST pidlItems = NULL;
LPITEMIDLIST netItemIdLst = NULL;
IShellFolder* pFolder = NULL;
IEnumIDList* pEnumIds = NULL;
IShellFolder* pDesktopFolder = NULL;
LPITEMIDLIST full_pid;
hr = SHGetMalloc(&pMalloc);
hr = SHGetDesktopFolder(&pDesktopFolder);
hr = SHGetSpecialFolderLocation(NULL, CSIDL_COMPUTERSNEARME, &netItemIdLst);
hr = pDesktopFolder->BindToObject(netItemIdLst, NULL,
IID_IShellFolder, (void **)&pFolder);
if(SUCCEEDED(hr))
{
hr = pFolder->EnumObjects(NULL, SHCONTF_NONFOLDERS, &pEnumIds);
if(SUCCEEDED(hr))
{
STRRET strDisplayName;
while((hr = pEnumIds->Next(1, &pidlItems, &celtFetched)) == S_OK && celtFetched > 0)
{
hr = pFolder->GetDisplayNameOf(pidlItems, SHGDN_NORMAL, &strDisplayName);
if(SUCCEEDED(hr))
{
wprintf(L"%s\n", strDisplayName.pOleStr);
}
}
}
}
But this returns the Computers, Media Devices, and Streaming Devices (is that it name?).
Like say, a computer is called OSOFEM on my workgroup... STRRET::pOleStr returns strings OSOFEM (which is the computer), OSOFEM (I think streaming device), and OSOFEM:example#email.com: (which is the Windows Media Player).
My question is how can I distinguish which is the Computer? Of course, there names can't be used because two exactly the same name will always be returned...

Create VM in virtual box with VB SDK

I need to create a VM in virtual box using the API in the VB SDK. I was able to create the machine but creating controller and adding device for the VM is troubling me a lot. Could you please help me out? I have given the code which i am using
CoInitialize(NULL);
IMachine *machine = NULL;
IVirtualBox *virtualBox = NULL;
BSTR guid = NULL;
HRESULT hr;
/* Instantiate the VirtualBox root object. */
hr = CoCreateInstance(CLSID_VirtualBox, /* the VirtualBox base object */
NULL, /* no aggregation */
CLSCTX_LOCAL_SERVER, /* the object lives in a server process on this machine */
IID_IVirtualBox, /* IID of the interface */
(void**)&virtualBox);
BSTR strMachineName = ::SysAllocString(L"SampleMachine");
IGuestOSType* os = NULL;
BSTR type = ::SysAllocString(L"unknown");
hr = virtualBox->GetGuestOSType(type, &os);
os->get_Id(&guid);
os->Release();
BSTR null = ::SysAllocString(L"00000000-0000-0000-0000-000000000000");
hr = virtualBox->CreateMachine(NULL, strMachineName, guid, null, TRUE, &machine);
::SysFreeString(null);
if (SUCCEEDED(hr))
{
IMedium* medium = NULL;
ISession *session = NULL;
IConsole *console = NULL;
IProgress *progress = NULL;
BSTR sessiontype = SysAllocString(L"gui");
BSTR bstrPath = SysAllocString(L"I:\\VHD\\Local_disk_(C).vhd");
hr = machine->SaveSettings();
hr = virtualBox->RegisterMachine(machine);
machine->Release();
hr = virtualBox->FindMachine(strMachineName, &machine);
hr = virtualBox->OpenMedium(bstrPath, DeviceType_HardDisk, AccessMode_ReadWrite,
TRUE, &medium);
/* Create the session object. */
hr = CoCreateInstance(CLSID_Session, /* the VirtualBox base object */
NULL, /* no aggregation */
CLSCTX_INPROC_SERVER, /* the object lives in a server process on this machine */
IID_ISession, /* IID of the interface */
(void**)&session);
hr = machine->LockMachine(session, LockType_Write);
IStorageController* cont = NULL;
BSTR loc = ::SysAllocString(L"BusLogic");
hr = machine->AddStorageController(loc, StorageBus_SCSI, &cont);
hr = machine->AttachDevice(loc, 0, 0, DeviceType_HardDisk, medium);
/* Start a VM session using the delivered VBox GUI. */
hr = machine->LaunchVMProcess(session, sessiontype,
NULL, &progress);
/* Wait until VM is running. */
hr = progress->WaitForCompletion (-1);
/* Get console object. */
session->get_Console(&console);
/* Bring console window to front. */
machine->ShowConsoleWindow(0);
Code fails at hr = machine->AddStorageController(loc, StorageBus_SCSI, &cont);. What I am doing wrong?
You can add a AddStorageController to a mutable machine, get machine object from session.machine and do the addition on the mutablemachine
hr = machine->LockMachine(session, LockType_Write);
IStorageController* cont = NULL;
BSTR loc = ::SysAllocString(L"BusLogic");
hr = machine->AddStorageController(loc, StorageBus_SCSI, &cont);
Change to following
hr = machine->LockMachine(session, LockType_Write);
Imachine *mutableMachine = NULL;
hr= session->get_Machine(&mutableMachine );
IStorageController* cont = NULL;
BSTR loc = ::SysAllocString(L"BusLogic");
hr = mutableMachine ->AddStorageController(loc, StorageBus_SCSI, &cont);

Raw C++ code to display the names of tables in an SQL compact server using OLE DB

Does anyone have a sample code that given the database file displays the names of all the user tables there?
I am not interested in a .NET code, just the C++.
I am trying to grok OLE DB to do the task - rocket science seems child play in comparison.
I'm going to assume SQL Server CE 3.0/3.1 but, for your reference, here are provider strings I'm aware of:
SQL Server CE 3.0 / 3.1 - Microsoft.SQLLITE.MOBILE.OLEDB.3.0
SQL Server CE 3.5 - Microsoft.SQLSERVER.CE.OLEDB.3.5
Also, I will be providing you with two code examples:
ICommandText on "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES"
IDBSchemaRowset on DBSCHEMA_TABLES
I'm providing you the samples as C++ console application and have used ATL to make the code short. The code is complete and working but does not include the necessary error checking of the HRESULT hr.
Here's the C++ console application sample for querying a SQL Server CE 3.0/3.1 database for executing "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES" using ICommandText and IRowset:
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <oledb.h>
#include <atlbase.h>
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hr = S_OK;
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
// Connect to SQL Server.
CComPtr<IDBInitialize> spIDBInitialize;
hr = spIDBInitialize.CoCreateInstance(OLESTR("Microsoft.SQLLITE.MOBILE.OLEDB.3.0"));
CComPtr<IDBProperties> spIDBProperties;
hr = spIDBInitialize->QueryInterface(&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();
// Execute the query.
CComPtr<IDBCreateSession> spIDBCreateSession;
hr = spIDBInitialize->QueryInterface(&spIDBCreateSession);
CComPtr<IDBCreateCommand> spIDBCreateCommand;
hr = spIDBCreateSession->CreateSession(NULL, IID_IDBCreateCommand, (IUnknown**) &spIDBCreateCommand);
spIDBCreateSession = NULL;
CComPtr<ICommandText> spICommandText;
hr = spIDBCreateCommand->CreateCommand(NULL, IID_ICommandText, (IUnknown**) &spICommandText);
spIDBCreateCommand = NULL;
hr = spICommandText->SetCommandText(DBGUID_SQL, OLESTR("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES"));
DBROWCOUNT cRowsAffected = 0;
CComPtr<IRowset> spIRowset;
hr = spICommandText->Execute(NULL, IID_IRowset, NULL, &cRowsAffected, (IUnknown**) &spIRowset);
spICommandText = NULL;
// Retrieve records.
HROW hRow = NULL;
HROW *rghRow = &hRow;
DBCOUNTITEM cRowsObtained = 0;
hr = spIRowset->GetNextRows(DB_NULL_HCHAPTER, 0, 1, &cRowsObtained, &rghRow);
while (hr == S_OK && cRowsObtained == 1)
{
// Fetch the TABLE_NAME field.
struct
{
DBSTATUS dbTableNameStatus;
ULONG nTableNameLength;
WCHAR szTableName[128 + 1];
} data = {0};
DBBINDING Binding = {0};
Binding.iOrdinal = 1;
Binding.obValue = sizeof(DBSTATUS) + sizeof(ULONG);
Binding.obLength = sizeof(DBSTATUS);
Binding.obStatus = 0;
Binding.pTypeInfo = NULL;
Binding.pObject = NULL;
Binding.pBindExt = NULL;
Binding.dwPart = DBPART_STATUS | DBPART_LENGTH | DBPART_VALUE;
Binding.dwMemOwner = DBMEMOWNER_CLIENTOWNED;
Binding.eParamIO = DBPARAMIO_NOTPARAM;
Binding.cbMaxLen = (128 + 1) * sizeof(WCHAR);
Binding.wType = DBTYPE_WSTR;
Binding.dwFlags = 0;
Binding.bPrecision = 0;
Binding.bScale = 0;
CComPtr<IAccessor> spIAccessor;
hr = spIRowset->QueryInterface(IID_IAccessor, (void**) &spIAccessor);
HACCESSOR hAccessor = NULL;
hr = spIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 1, &Binding, 0, &hAccessor, NULL);
hr = spIRowset->GetData(hRow, hAccessor, &data);
DBREFCOUNT cRefCount = 0;
hr = spIAccessor->ReleaseAccessor(hAccessor, &cRefCount);
spIAccessor = NULL;
// ##TODO: Do something with data.szTableName and data.nTableNameLength
_tprintf(_T("%s\n"), data.szTableName);
// Fetch next row of data.
hr = spIRowset->ReleaseRows(1, rghRow, NULL, NULL, NULL);
cRowsObtained = 0;
hr = spIRowset->GetNextRows(DB_NULL_HCHAPTER, 0, 1, &cRowsObtained, &rghRow);
}
// Release everything
spIRowset = NULL;
spIDBInitialize = NULL;
CoUninitialize();
return 0;
}
Here's the C++ console application sample for querying a SQL Server CE 3.0/3.1 database for browsing the tables using IDBSchemaRowset and IRowset (note that TABLE_NAME is now at iOrdinal 3 instead of 1):
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <oledb.h>
#include <atlbase.h>
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hr = S_OK;
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
// Connect to SQL Server.
CComPtr<IDBInitialize> spIDBInitialize;
hr = spIDBInitialize.CoCreateInstance(OLESTR("Microsoft.SQLLITE.MOBILE.OLEDB.3.0"));
CComPtr<IDBProperties> spIDBProperties;
hr = spIDBInitialize->QueryInterface(&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();
// Execute the query.
CComPtr<IDBCreateSession> spIDBCreateSession;
hr = spIDBInitialize->QueryInterface(&spIDBCreateSession);
CComPtr<IDBSchemaRowset> spIDBSchemaRowset;
hr = spIDBCreateSession->CreateSession(NULL, IID_IDBSchemaRowset, (IUnknown**) &spIDBSchemaRowset);
spIDBCreateSession = NULL;
CComVariant rgRestrictions[CRESTRICTIONS_DBSCHEMA_TABLES];
// rgRestrictions[2] = OLESTR("CENSUS"); TABLE_NAME restriction
rgRestrictions[3] = OLESTR("TABLE"); // TABLE_TYPE restriction
CComPtr<IRowset> spIRowset;
hr = spIDBSchemaRowset->GetRowset(NULL, DBSCHEMA_TABLES, CRESTRICTIONS_DBSCHEMA_TABLES, rgRestrictions, IID_IRowset, 0, NULL, (IUnknown**) &spIRowset);
spIDBSchemaRowset = NULL;
// Retrieve records.
HROW hRow = NULL;
HROW *rghRow = &hRow;
DBCOUNTITEM cRowsObtained = 0;
hr = spIRowset->GetNextRows(DB_NULL_HCHAPTER, 0, 1, &cRowsObtained, &rghRow);
while (hr == S_OK && cRowsObtained == 1)
{
// Fetch the TABLE_NAME field.
struct
{
DBSTATUS dbTableNameStatus;
ULONG nTableNameLength;
WCHAR szTableName[128 + 1];
} data = {0};
DBBINDING Binding = {0};
Binding.iOrdinal = 3;
Binding.obValue = sizeof(DBSTATUS) + sizeof(ULONG);
Binding.obLength = sizeof(DBSTATUS);
Binding.obStatus = 0;
Binding.pTypeInfo = NULL;
Binding.pObject = NULL;
Binding.pBindExt = NULL;
Binding.dwPart = DBPART_STATUS | DBPART_LENGTH | DBPART_VALUE;
Binding.dwMemOwner = DBMEMOWNER_CLIENTOWNED;
Binding.eParamIO = DBPARAMIO_NOTPARAM;
Binding.cbMaxLen = (128 + 1) * sizeof(WCHAR);
Binding.wType = DBTYPE_WSTR;
Binding.dwFlags = 0;
Binding.bPrecision = 0;
Binding.bScale = 0;
CComPtr<IAccessor> spIAccessor;
hr = spIRowset->QueryInterface(IID_IAccessor, (void**) &spIAccessor);
HACCESSOR hAccessor = NULL;
hr = spIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 1, &Binding, 0, &hAccessor, NULL);
hr = spIRowset->GetData(hRow, hAccessor, &data);
DBREFCOUNT cRefCount = 0;
hr = spIAccessor->ReleaseAccessor(hAccessor, &cRefCount);
spIAccessor = NULL;
// ##TODO: Do something with data.szTableName and data.nTableNameLength
_tprintf(_T("%s\n"), data.szTableName);
// Fetch next row of data.
hr = spIRowset->ReleaseRows(1, rghRow, NULL, NULL, NULL);
cRowsObtained = 0;
hr = spIRowset->GetNextRows(DB_NULL_HCHAPTER, 0, 1, &cRowsObtained, &rghRow);
}
// Release everything
spIRowset = NULL;
spIDBInitialize = NULL;
CoUninitialize();
return 0;
}
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES