Re: VB function called from c++
Alex Blekhman wrote:
"Jake" wrote:
I have a C++ function that calls a VB dll but I am not
that familiar
with VB in order to resolve the crash that I am having.
This is my code
int u_dll_imstest_call(wchar_t *TheConnectString, wchar_t
*TheTable,
wchar_t *TheFields, wchar_t *ThePopupTitle, wchar_t
*TheOrderBy,
wchar_t *TheWhereClause, wchar_t *ThePosition)
{
// Declare an HRESULT and a pointer to the
clsVBTestClass interface
HRESULT hr;
BSTR bTheConnectString = L"Provider =
Microsoft.Jet.OLEDB.4.0;Data
Source=C:\\Imstestfor8.2\\database\\CAT16.mdb";
BSTR bTheTable = L"USR";
BSTR bTheFields =
L"USERNAME,Name,USER_ID,ID,U_LOGIN,Log-in";
BSTR bThePopupTitle = L"User Table";
BSTR bTheOrderBy = L"USERNAME";
BSTR bTheWhereClause = L"!=0000000001";
BSTR bThePosition = L"b";
You cannot use BSTR like that. In order to be valid BSTR
must be allocated with `SysAllocString' function call. There
are many C++ wrappers for BSTR out there in the world.
`_bstr_t' class is one of them. Just use it instead of raw
BSTR. Where `BSTR*' type is required call
`_bstr_t::GetAddress' to get a pointer to contained BSTR.
_bstr_t value;
_clsCat16 *IclsCat16 = NULL;
// Now we will intilize COM
hr = CoInitialize(0);
// Use the SUCCEEDED macro and see if we can get a pointer
// to the interface
if(SUCCEEDED(hr))
{
hr = CoCreateInstance(__uuidof (clsCat16),
NULL,
CLSCTX_INPROC_SERVER,
_uuidof (_clsCat16),
(void**) &IclsCat16);
// If we succeeded then call the CountStringLength method,
// if it failed then display an appropriate message to the
user.
if(SUCCEEDED(hr))
{
value = IclsCat16->Popup(&bTheConnectString, &bTheTable,
&bTheFields, &bThePopupTitle,
&bTheOrderBy, &bTheWhereClause,
&bThePosition);
return 0;
^^^^^^^^
BUG! Because of this `return' statement `IclsCat16'
interface is never released, therefore it's leaked. Also,
call to `CoUninitialize' is unreachable.
}
else
{
}
}
// Uninitialize COM
CoUninitialize();
return 0;
}
I am using #import "WFCat16.dll" no_namespace in order to
import the
tlh file
This is what the function looks like in the tlh
struct
__declspec(uuid("21eb71ba-4e5f-4948-9315-b38c29fd296c"))
_clsCat16 : IDispatch
{
//
// Wrapper methods for error-handling
//
_bstr_t Popup (
BSTR * TheConnectString,
BSTR * TheTable,
BSTR * TheFields,
BSTR * ThePopupTitle,
BSTR * TheOrderBy,
BSTR * TheWhereClause,
BSTR * ThePosition );
//
// Raw methods provided by interface
//
virtual HRESULT __stdcall raw_Popup (
/*[in,out]*/ BSTR * TheConnectString,
/*[in,out]*/ BSTR * TheTable,
/*[in,out]*/ BSTR * TheFields,
/*[in,out]*/ BSTR * ThePopupTitle,
/*[in,out]*/ BSTR * TheOrderBy,
/*[in,out]*/ BSTR * TheWhereClause,
/*[in,out]*/ BSTR * ThePosition,
/*[out,retval]*/ BSTR * _arg8 ) = 0;
};
Look further in generated .TLH file. There should be smart
pointer wrapper declaration for `_clsCat16' class. Look for
"_COM_SMARTPTR_TYPEDEF(_clsCat16)" declaration or similar.
Just try to use `_clsCat16Ptr' instead of raw interface.
Using smart pointer wrapper will reduce places of potential
errors in your code. Usually you don't need to create COM
object's instance with call to `CoCreateInstance' when smart
pointers generated by `#pragma' directive are used. You
create it like that:
_clsCat16Ptr ptrCat16(__uuidof(clsCat16));
Then use it as regular pointer:
_bstr_t btRet = ptrCat16->Popup(...);
I guess my question is am I right in defining my input as
BSTR and then
sending the address of the data to the VB function?
No, you didn't allocate BSTR properly. Either use C++
wrappers like `_bstr_t' or Win32 API functions like
`SysAllocString'.
I am using _bstr_t to define my return value because that
is how it
should be returned from the VB call - Do I need to
allocate the _bstr_t
field before I use it?
No allocation is required here. `_bstr_t' class will perform
all necessary acclocations for you.
Eventually I want to take wchar_t * values and send them
to this
function but for right now I just trying to get it to
work - Anybody
have any ideas?
`_bstr_t' instance can be contructed from `wchar_t*' without
any problem:
wchar_t* pwsz = L"Hello!";
_bstr_t bt(pwsz); // bt contains "Hello!" now
HTH
Alex
Alex first of all thanks for responding -
I made a few changes based upon what you said and I think I am closer
to getting what I need but I don't think I am completely there yet as I
am getting a compile error on the function call
This is my code
int u_dll_imstest_call(wchar_t *TheConnectString, wchar_t *TheTable,
wchar_t *TheFields, wchar_t *ThePopupTitle, wchar_t *TheOrderBy,
wchar_t *TheWhereClause, wchar_t *ThePosition)
{
// Declare an HRESULT and a pointer to the clsCat16 interface
HRESULT hr;
_bstr_t bTheConnectString(TheConnectString); //TheConnectString
creates a _bstr_t wrapper
_bstr_t bTheTable(TheTable); //TheTable creates a _bstr_t wrapper
_bstr_t bTheFields(TheFields); //TheFields creates a _bstr_t wrapper
_bstr_t bThePopupTitle(ThePopupTitle); // ThePopupTitle creates a
_bstr_t wrapper
_bstr_t bTheOrderBy(TheOrderBy); //TheOrderBy creates a _bstr_t
wrapper
_bstr_t bTheWhereClause(TheWhereClause); //TheWhereClause creates a
_bstr_t wrapper
_bstr_t bThePosition(ThePosition); //ThePosition creates a _bstr_t
wrapper
_bstr_t bvalue;
_clsCat16Ptr ptrCat16(__uuidof(_clsCat16));
// Now we will intilize COM
hr = CoInitialize(0);
if(SUCCEEDED(hr))
{
bvalue = _clsCat16Ptr->Popup(bTheConnectString, bTheTable,
bTheFields, bThePopupTitle, bTheOrderBy, bTheWhereClause, bThePosition,
bvalue);
CoUninitialize();
return 0;
}
else
{
return 1;
}
}
These are the values being passed
//Values being passed//
//TheConnectString = L"Provider = Microsoft.Jet.OLEDB.4.0;Data
Source=C:\\Imstestfor8.2\\database\\CAT16.mdb";
//TheTable = L"USR";
//TheFields = L"USERNAME,Name,USER_ID,ID,U_LOGIN,Log-in";
//ThePopupTitle = L"User Table";
//TheOrderBy = L"USERNAME";
//TheWhereClause = NULL;
//ThePosition = NULL;
Compile error
error C2664: '_clsCat16::Popup' : cannot convert parameter 1 from
'_bstr_t' to 'BSTR * '
This is my complete tlh file
// Created by Microsoft (R) C/C++ Compiler Version 13.10.3077
(32495ecb).
//
// c:\flotiva\ftims21\ftims21\debug\wfcat16.tlh
//
// C++ source equivalent of Win32 type library WFCat16.dll
// compiler-generated file created 11/21/06 at 10:25:52 - DO NOT EDIT!
#pragma once
#pragma pack(push, 8)
#include <comdef.h>
//
// Forward references and typedefs
//
struct __declspec(uuid("2133ec3c-f108-46d5-a85b-8affe7802f94"))
/* LIBID */ __WfCat16;
struct __declspec(uuid("21eb71ba-4e5f-4948-9315-b38c29fd296c"))
/* dual interface */ _clsCat16;
struct /* coclass */ clsCat16;
//
// Smart pointer typedef declarations
//
_COM_SMARTPTR_TYPEDEF(_clsCat16, __uuidof(_clsCat16));
//
// Type library items
//
struct __declspec(uuid("21eb71ba-4e5f-4948-9315-b38c29fd296c"))
_clsCat16 : IDispatch
{
//
// Wrapper methods for error-handling
//
_bstr_t Popup (
BSTR * TheConnectString,
BSTR * TheTable,
BSTR * TheFields,
BSTR * ThePopupTitle,
BSTR * TheOrderBy,
BSTR * TheWhereClause,
BSTR * ThePosition );
//
// Raw methods provided by interface
//
virtual HRESULT __stdcall raw_Popup (
/*[in,out]*/ BSTR * TheConnectString,
/*[in,out]*/ BSTR * TheTable,
/*[in,out]*/ BSTR * TheFields,
/*[in,out]*/ BSTR * ThePopupTitle,
/*[in,out]*/ BSTR * TheOrderBy,
/*[in,out]*/ BSTR * TheWhereClause,
/*[in,out]*/ BSTR * ThePosition,
/*[out,retval]*/ BSTR * _arg8 ) = 0;
};
struct __declspec(uuid("f574c6a6-5e79-400e-8989-ede288e78cc8"))
clsCat16;
// [ default ] interface _clsCat16
//
// Wrapper method implementations
//
#include "c:\flotiva\ftims21\ftims21\debug\wfcat16.tli"
#pragma pack(pop)
I guess I need to do something else to the value passed before I pass
it but I am not sure what
I tried
*bTheConnectString.GetAddress() = bTheConnectString;
for the connect string but that does not work either.
I'm almost over the hump just not there yet - any ideas?
Thanks
Jake