How to use com objects in msvbvm60.dll or vba6.dll, e.g. use module datetime - visual-c++

There are many com objects in msvbvm60.dll or vba6.dll, and there are two type libraries in there.
My question is how to use them(in VC++) without any docs, e.g. use module "DateTime" function "Now".
You can view VBA "Visual Basic For Applications" by using "oleview.exe" in windows sdk bin folder.
This is a part of the VBA idl generated by oleview:
// Generated .IDL file (by the OLE/COM Object Viewer)
//
// typelib filename: msvbvm60.dll
[
uuid(000204EF-0000-0000-C000-000000000046),
version(6.0),
helpstring("Visual Basic For Applications"),
helpfile("VBA.HLP"),
helpcontext(0x000f6791)
]
library VBA
{
// TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
importlib("stdole2.tlb");
// Forward declare all types defined in this typelib
interface _HiddenInterface;
interface _ErrObject;
interface _Collection;
***// omit some definitions here***
[
dllname("VBA6.DLL"),
uuid(37D75300-2BCC-1069-82D8-00DD010EDFAA),
helpcontext(0x000f6ebf)
]
module DateTime {
[entry(610), propget, helpcontext(0x000f6d5e)]
VARIANT _stdcall _B_var_Date();
[entry(549), propput, helpcontext(0x000f6d5e)]
void _stdcall _B_str_Date([in] BSTR rhs);
[entry(548), propput, helpcontext(0x000f6d5e)]
void _stdcall _B_var_Date([in] VARIANT* rhs);
[entry(609), propget, helpcontext(0x000f6d5e)]
BSTR _stdcall _B_str_Date();
[entry(538), helpcontext(0x000f64f8)]
VARIANT _stdcall DateSerial(
[in] short Year,
[in] short Month,
[in] short Day);
[entry(540), helpcontext(0x000f64f9)]
VARIANT _stdcall DateValue([in] BSTR Date);
[entry(542), helpcontext(0x000f64fa)]
VARIANT _stdcall Day([in] VARIANT* Date);
[entry(543), helpcontext(0x000f652b)]
VARIANT _stdcall Hour([in] VARIANT* Time);
[entry(544), helpcontext(0x000f654e)]
VARIANT _stdcall Minute([in] VARIANT* Time);
[entry(545), helpcontext(0x000f6551)]
VARIANT _stdcall Month([in] VARIANT* Date);
[entry(546), propget, helpcontext(0x000f6556)]
VARIANT _stdcall Now();
[entry(547), helpcontext(0x000f6573)]
VARIANT _stdcall Second([in] VARIANT* Time);
[entry(612), propget, helpcontext(0x000f6d5f)]
VARIANT _stdcall _B_var_Time();
[entry(551), propput, helpcontext(0x000f6d5f)]
void _stdcall _B_str_Time([in] BSTR rhs);
[entry(550), propput, helpcontext(0x000f6d5f)]
void _stdcall _B_var_Time([in] VARIANT* rhs);
[entry(611), propget, helpcontext(0x000f6d5f)]
BSTR _stdcall _B_str_Time();
[entry(535), propget, helpcontext(0x000f6593)]
single _stdcall Timer();
[entry(539), helpcontext(0x000f6594)]
VARIANT _stdcall TimeSerial(
[in] short Hour,
[in] short Minute,
[in] short Second);
[entry(541), helpcontext(0x000f6595)]
VARIANT _stdcall TimeValue([in] BSTR Time);
[entry(552), helpcontext(0x000f65a2)]
VARIANT _stdcall Weekday(
[in] VARIANT* Date,
[in, optional, defaultvalue(1)] VbDayOfWeek FirstDayOfWeek);
[entry(553), helpcontext(0x000f65a7)]
VARIANT _stdcall Year([in] VARIANT* Date);
[entry(661), helpcontext(0x000f7566)]
VARIANT _stdcall DateAdd(
[in] BSTR Interval,
[in] double Number,
[in] VARIANT* Date);
[entry(662), helpcontext(0x000f74d6)]
VARIANT _stdcall DateDiff(
[in] BSTR Interval,
[in] VARIANT* Date1,
[in] VARIANT* Date2,
[in, optional, defaultvalue(1)] VbDayOfWeek FirstDayOfWeek,
[in, optional, defaultvalue(1)] VbFirstWeekOfYear FirstWeekOfYear);
[entry(663), helpcontext(0x000f74d7)]
VARIANT _stdcall DatePart(
[in] BSTR Interval,
[in] VARIANT* Date,
[in, optional, defaultvalue(1)] VbDayOfWeek FirstDayOfWeek,
[in, optional, defaultvalue(1)] VbFirstWeekOfYear FirstWeekOfYear);
[entry(700), propget, helpcontext(0x00110c12)]
VbCalendar _stdcall Calendar();
[entry(699), propput, helpcontext(0x00110c12)]
void _stdcall Calendar([in] VbCalendar rhs);
};
***// omit some definitions here***
[
uuid(A4C4671C-499F-101B-BB78-00AA00383CBB),
helpcontext(0x000f8c67)
]
coclass Collection {
[default] interface _Collection;
};
};
How to use them(in VC++) without any docs, e.g. use module "DateTime" function "Now".

Related

How to avoid Conflict of defined seconds() method and ptime seconds(default) method?

Here unsigned long EVTime::seconds() method is conflicting with ptime p(d,seconds(s));. If I change ptime seconds(s) to minutes/hours then it works fine.
If i change that seconds(s) to minutes(s) or hours(s) then only it will work. I am new to C++, anyone please help to resolve this conflict.
evt.cpp:
unsigned long EVTime::seconds()
{
ptime t(date(1901,Jan,1),time_duration(0,0,0));
time_duration td = utcdatetime - t;
return (unsigned long)td.total_seconds();
}
EVTime::EVTime(unsigned long s)
{
date d(1901,1,1);
ptime p(d,seconds(s));
utcdatetime=p;
}
evt.h:
class EVTime
{
public:
EVTime(unsigned long s);
unsigned long seconds();
ptime utcdatetime;
};
main.cpp:
int main()
{
EVTime t(222l);
cout<<"seconds since 1901: "<<t.seconds()<<endl;
}
Error code:
evtime.cpp: In constructor ‘EVTime::EVTime(long unsigned int)’:
evtime.cpp:35: error: no matching function for call to ‘EVTime::seconds(long
unsigned int&)’
evtime.cpp:14: note: candidates are: long unsigned int EVTime::seconds()
Your function seconds() takes no parameters, but you send it s when you call it: ptime p(d,seconds(s));
This causes the error "no matching function for call to EVTime::seconds(long unsigned int&)", since you don't have a matching function.
Either call ptime p(d,seconds()); or change the seconds function signature to take the parameter and do something with it.

C++ to C# char[]

C# code:
class Hello{
public void helloWorld(char[] chars){
//do something
}
}
C++ code to call C#:
MyCSDLL::Hello* hello;
//init hello, some calls are ok.
char* myCharPtr;
//init with message
HRESULT result = hello->helloWorld(safeArray, (MyCSDLL::_MyRetVal) _retValPtr);
Adapting from How to create and initialize SAFEARRAY of doubles in C++ to pass to C#
void createSafeArray(SAFEARRAY** saData, char* charPtr)
{
char* iterator = charPtr;
SAFEARRAYBOUND Bound;
Bound.lLbound = 0;
Bound.cElements = 10;
*saData = SafeArrayCreate(VT_R8, 1, &Bound);
char HUGEP *pdFreq;
HRESULT hr = SafeArrayAccessData(*saData, (void HUGEP* FAR*)&pdFreq);
if (SUCCEEDED(hr))
{
do {
*pdFreq++ = *iterator;
} while (*iterator++);
}
}
How to call hello->helloWorld()? it is expecting SAFEARRAY*. The current code gives 80131538 error. How to fix it?
C++ Project is not CLR.
Let's suppose the C# code is this:
namespace ClassLibrary1
{
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class Hello
{
public void helloWorld(char[] chars)
{
...
}
}
}
Then, you can call it with this C/C++ code, for example:
#import "C:\mycode\ClassLibrary1\bin\Debug\classlibrary1.tlb" raw_interfaces_only
using namespace ClassLibrary1;
HRESULT CallHello(wchar_t* charPtr, int count)
{
CComPtr<_Hello> p;
HRESULT hr = p.CoCreateInstance(__uuidof(Hello));
if (FAILED(hr))
return hr;
SAFEARRAY* psa = SafeArrayCreateVector(VT_UI2, 0, count);
if (!psa)
return E_OUTOFMEMORY;
LPVOID pdata;
hr = SafeArrayAccessData(psa, &pdata);
if (SUCCEEDED(hr))
{
CopyMemory(pdata, charPtr, count * 2); // count is the number of chars
SafeArrayUnaccessData(psa);
hr = p->helloWorld(psa);
}
SafeArrayDestroy(psa);
return hr;
}
.NET's char type is unicode, so the binary size is two bytes, the C equivalent is wchar_t (or unsigned short, etc...). So the safearray element type must match that, that's why I used VT_UI2 (VT_R8 that you used is Real of size 8 bytes, so it's equivalent to .NET's double type).
If you really want to use C's char, then you must do some kind of conversion to a 2-byte character.
Also, you can use the SafeArrayCreateVector function which directly allocates a 1-dimension safe array. Don't forget to call cleanup methods.

What happen with MFC CString in " CStringA csA = CStringW("hello", 5);"

It does compiled. But I do not think it should. It compile both in VS2008 and VS2013.
I Add a picture to show it does compile. but I am really confused at this. The picture is VS2013.
Why shouldn't it compile? There's explicit code in CString to handle exactly such unicode-to-ascii conversions:
CStringT& operator=(_In_opt_z_ PCYSTR pszSrc)
{
...
PXSTR pszBuffer = GetBuffer( nDestLength );
StringTraits::ConvertToBaseType( pszBuffer, nDestLength, pszSrc);
...
}
and internally (note the explicit LPSTR and LPCWSTR in the signature):
static void __cdecl ConvertToBaseType(
_Out_writes_(nDestLength) LPSTR pszDest,
_In_ int nDestLength,
_In_ LPCWSTR pszSrc,
_In_ int nSrcLength = -1) throw()
{
// nLen is in XCHARs
::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSrc, nSrcLength, pszDest, nDestLength, NULL, NULL );
}
You can step into it from the debugger.

Marshalling an unsigned char * from a COM interface

I have a COM interface defined in the file IPlan.idl that defines a property for an unsigned char* buffer.
[
object,
uuid(...),
dual,
helpstring("..."),
pointer_default(unique)
]
interface IPlan : IDispatch
{
...
[id(28), helpstring("method SetByte")
HRESULT SetByte([in] long index, [in] unsigned char buffer);
[id(29), helpstring("method GetByte")
HRESULT GetByte([in] long index, [out, retval] unsigned char * pBuffer);
[id(30), propget, helpstring("property Buffer")]
HRESULT Buffer([out, retval] unsigned char** pBuffer);
[id(30), propput, helpstring("property Buffer")]
HRESULT Buffer([in] unsigned char* newBuffer);
...
}
My implementation class, MyPlan, is defined in C#. This class talks to a C++ COM class, CProcessor. CProcessor calculates some data into a unsigned char* buffer. This data is loaded into a MyPlan object once all the data in CProcessor has been stored in its buffer.
The metadata for IPlan defines the following function signatures:
public interface IPlan
{
...
byte GetByte(int index);
void SetByte(int index, byte buffer);
IntPtr get_Buffer();
void set_Buffer(ref byte pBuffer);
...
}
I am able to use GetByte and SetByte from CProcessor to access and modify a byte[] variable in MyPlan. I am also able to use get_Buffer() by marshalling the byte[] variable.
My question is how can I utilize the
set_Buffer(ref byte pBuffer)
function? When I call it in CProcessor, pBuffer only contains the first byte of the buffer (like a call to SetByte(0, data)). I assume that I need to marshal the setter just as I did in the getter but my searches have come up empty. I have tried
set_Buffer([MarshalAs(UnmanagedType.LPStr)] ref byte pBuffer);
but that doesn't seem to do anything to pass in the entire array.
MarshalAs(UnmanagedType.LPStr) - how does this convert utf-8 strings to char*
Problem using dll in c#
I was able to use
[id(1), propget, helpstring("Buffer")]
HRESULT Buffer([out, retval] VARIANT* pBuffer);
[id(1), propput, helpstring("Buffer")]
HRESULT Buffer([in] VARIANT pBuffer);
to pass an unsigned char array from C++ to C#. The C# just requires a cast to byte[]
this.buffer = (byte[])myPlan.Buffer;

multithreaded using _beginthreadex passing parameters

Visual Studio C++ 2008
I am using threads. However, I have this warnings and not sure what I am doing wrong.
1. unsigned int (__stdcall *)(void *) differs in levels of indirection from 'void *(__stdcall *)(void *)'
2. _beginthreadex different types for formal and actual parameters 3
/* Function prototype */
void* WINAPI get_info(void *arg_list)
DWORD thread_hd;
DWORD thread_id;
/* Value to pass to the function */
int th_sock_desc = 0;
/* Create thread */
thread_hd = _beginthreadex(NULL, 0, get_info, (void*) th_sock_desc, 0, &thread_id);
if(thread_hd == 0)
{
/* Failed to create thread */
fprintf(stderr, "[ %s ] [ %s ] [ %d ]\n", strerror(errno), __func__, __LINE__);
return 1;
}
the Thread function that you pass to _beginthreadex has a different prototype than the one you pass to _beginthread
uintptr_t _beginthread(
void( *start_address )( void * ),
unsigned stack_size,
void *arglist
);
uintptr_t _beginthreadex(
void *security,
unsigned stack_size,
unsigned ( *start_address )( void * ),
void *arglist,
unsigned initflag,
unsigned *thrdaddr
);
It's the same as what CreateThread expects,
DWORD WINAPI ThreadProc(
__in LPVOID lpParameter
);
So you need to change the function signature of your thread proc to
unsigned WINAPI get_info(void *arg_list)
remove WINAPI and change the return type.
Edit :
WINAPI is actually needed, the docs show the wrong prototype for _beginthredex, but they explicitly state that __stdcall is needed. Your problem is just the return type. Also, the error message, says that __stdcall is expected, so that settles it.

Resources