EDIT: Beaten!
Passing COM interface pointers between threads is a somewhat complicated affair. This page on multi-threading and COM, although Delphi centric, provides a good overview. This codeguru article on COM threading may also be helpful. You can get more information via a search on COM threading.
Basically, when you wish to pass an interface pointer between threads you must marshal it. There are a couple of "simple" methods to do this. The first is the briefly named CoMarshalInterThreadInterfaceInStream()/CoGetInterfaceAndReleaseStream() functions. There are also ATL wrappers for these functions.
Code:
/*
ThreadFunc is responsible for accessing the Recordset. and moving through
recordset.
*/
DWORD WINAPI ThreadFunc(LPVOID lpParam)
{
EnterCriticalSection(&cs);
// Don't make pRs global
_RecordsetPtr pRs;
// Unmarshal interface from pStream
LPSTREAM pStream = (LPSTREAM) lpParam;
CoGetInterfaceAndReleaseStream(pStream, __uuidof(Recordset), (void **) &pRs);
// Now you can safely use pRs in this thread.
_bstr_t val = pRs->Fields->Item[_variant_t("BTN")]->Value;
printf("%s\n",(char*)val);
pRs->MoveNext();
//printf("Hello World, I'm thread# %d\n", (int)lpParam);
//printf("hello world \n");
LeaveCriticalSection(&cs);
return 0;
}//ThreadFunc
void main(){
DWORD dwThreadId;
HANDLE hThread[NUM_THREADS];
int n;
CoInitialize(NULL);
InitializeCriticalSection(&cs);
// Create an ADO connection to database
try{
hr = pConn.CreateInstance(__uuidof(Connection));
hr = pRs.CreateInstance(__uuidof(Recordset));
_bstr_t strConn("Provider=sqloledb;server=SINF005;Trusted_Connectio n=yes;database=Core;");
pConn->Open(strConn,"","",adConnectUnspecified);
pRs->Open("SELECT top 10 Npa_Num from Npa (NOLOCK)", pConn.GetInterfacePtr(), adOpenForwardOnly, adLockReadOnly, adCmdText);
//pRs->Open("SELECT BTN from mbs_GetSpitFireEasyPay (NOLOCK)", pConn.GetInterfacePtr(), adOpenForwardOnly, adLockReadOnly, adCmdText);
}catch(_com_error &e){
printf("Error\n");
printf("\tCode meaning = %s", e.ErrorMessage());
}
// create all the threads
for (n = 0; n < NUM_THREADS; n++)
{
// Marshal interface into pStream
LPSTREAM pStream;
CoMarshalInterThreadInterfaceInStream(__uuidof(Recordset), pRs, &pStream);
hThread[n] = CreateThread(NULL, 0, ThreadFunc, pStream, 0, &dwThreadId);
if (hThread == NULL)
fprintf(stderr, "Failed to create thread# %d", n);
}//for
for (n = 0; n < NUM_THREADS; n++)
{
if (hThread[n] != NULL)
WaitForSingleObject(hThread[n], INFINITE);
}//for
DeleteCriticalSection(&cs);
printf("This is after all threads exited\n");
CoUninitialize();
}
The other method is to use a global interface table in the form of IGlobalInterfaceTable. You add an interface using RegisterInterfaceInGlobal() and can retrieve the interface from other threads using GetInterfaceFromGlobal(). This method may be simpler, especially when you have multiple interface pointers to marshal:
Code:
#import "C:\Program files\Common Files\System\Ado\msado15.dll" no_namespace rename("EOF", "ADOEOF")
#include <windows.h>
#include <stdio.h>
#include <ole2.h>
#include <conio.h>
#define NUM_THREADS 12
CRITICAL_SECTION cs;
HRESULT hr;
DWORD g_dwConnCookie;
DWORD g_dwRsCookie;
IGlobalInterfaceTable * g_pGIT;
DWORD WINAPI ThreadFunc(LPVOID lpParam)
{
EnterCriticalSection(&cs);
// Retrieve desired interface pointers from global interface table
_RecordsetPtr pRs;
g_pGIT->GetInterfaceFromGlobal(g_dwRsCookie, __uuidof(Recordset), (void **) &pRs);
_bstr_t val = pRs->Fields->Item[_variant_t("BTN")]->Value;
printf("%s\n",(char*)val);
pRs->MoveNext();
LeaveCriticalSection(&cs);
return 0;
}
void main(){
DWORD dwThreadId;
HANDLE hThread[NUM_THREADS];
int n;
_ConnectionPtr pConn;
_RecordsetPtr pRs;
CoInitialize(NULL);
InitializeCriticalSection(&cs);
// Create global interface table
CoCreateInstance(CLSID_StdGlobalInterfaceTable,
NULL,
CLSCTX_INPROC_SERVER,
IID_IGlobalInterfaceTable,
(void **) &g_pGIT);
try
{
hr = pConn.CreateInstance(__uuidof(Connection));
hr = pRs.CreateInstance(__uuidof(Recordset));
_bstr_t strConn("Provider=sqloledb;server=SINF005;Trusted_Connectio n=yes;database=Core;");
pConn->Open(strConn,"","",adConnectUnspecified);
pRs->Open("SELECT top 10 Npa_Num from Npa (NOLOCK)", pConn.GetInterfacePtr(), adOpenForwardOnly, adLockReadOnly, adCmdText);
//pRs->Open("SELECT BTN from mbs_GetSpitFireEasyPay (NOLOCK)", pConn.GetInterfacePtr(), adOpenForwardOnly, adLockReadOnly, adCmdText);
}
catch(_com_error &e)
{
printf("Error\n");
printf("\tCode meaning = %s", e.ErrorMessage());
}
// Add interface pointers to global interface table
g_pGIT->RegisterInterfaceInGlobal((IUnknown *) pRs, __uuidof(Recordset), &g_dwRsCookie);
g_pGIT->RegisterInterfaceInGlobal((IUnknown *) pConn, __uuidof(Connection), &g_dwConnCookie);
// create all the threads
for (n = 0; n < NUM_THREADS; n++)
{
hThread[n] = CreateThread(NULL, 0, ThreadFunc, &pRs, 0, &dwThreadId);
if (hThread[n] == NULL)
fprintf(stderr, "Failed to create thread# %d", n);
}
for (n = 0; n < NUM_THREADS; n++)
{
if (hThread[n] != NULL)
WaitForSingleObject(hThread[n], INFINITE);
}
DeleteCriticalSection(&cs);
printf("This is after all threads exited\n");
CoUninitialize();
}
MSDN has an article, In-Process Marshaling Helpers, that describes both these methods.
Neither of these are compiled examples so you will have to fix the variables, release everything, etc.