I have a vc++ dll which has a funciton call like this :
typedef void * SIS_HANDLE;
EXTERN_C SDK4OpenDevice (SIS_HANDLE* sDev );
Now am trying to call the VC++ dll in VB6 is there any equivalent for the same in VB6.
Thanks
Yes, it's a pointer-sized integer, which is Long in VB6. And your function takes a pointer to a pointer, so it will be ByRef.
Declare Sub SDK4OpenDevice(ByRef sDev As Long);
Watch out for the calling convention though, if that EXTERN_C macro doesn't hide a __stdcall or __pascal keyword, the function can't be called from VB6 directly.
Related
first at all sorry for my English, it's not my native language.
I'd like to associate the address of a procedure that I created to a variable. Actually, I'm using a Windows Timer and in the Timer code, the function SetTimer is used this way :
Sub StartTimer()
TimerSeconds = 0.1 ' how often to "pop" the timer.
TimerID = SetTimer(0&, 0&, TimerSeconds * 1000&, AddressOf move2)
End Sub
I'd like to replace "AddressOf move2" with a public variable and to do so I need to obtain the address of the procedure but I don't know how to do this.
I tried to write
variable = AddressOf move2
And it doesn't work (variable type = long)
That is easy to implement. The only thing you didn't tell us is the "bitness" of your Excel. Well, I'm using Excel2019 64Bit. So, in my case, I'm using LongLong integers (8 Bytes). If you're running a 32Bit version, you have to account for that. On 32Bit platforms, you do not have LongLongs, but only Long integers (4 Bytes). I just mention that, because you wrote:
And it doesn't work (variable type = long)
The best thing you can do is declare your pointer variable of type LongPtr. A LongPtr is not really a type of its own, but a neat feature that was introduced with VBA7. Any integer variable you declare as of type LongPtr is a Long on 32Bit systems and a LongLong on 64Bit systems.
In the declaration section of your module set your variable to
Public LngPtrMove2 As LongPtr
If you still running VBA6 you can use
Public LngPtrMove2 As Long ' for 32Bit
or, on a 64Bit system, you can use conditional compilation if you have to support backward-compatibility:
#If Win64 Then
Public LngPtrMove2 As LongLong
#Else
Public LngPtrMove2 As Long
#End If
Now, use the following function to assign the function pointer to your public variable on a 64Bit system running VBA 7 like so:
Public Function LngPtrMove2() As LongPtr
LngPtrMove2 = VBA.CLngPtr(AddressOf move2)
End Function
On a 64Bit VBA 6 and on all 32Bit systems use this:
Public Function LngPtrMove2() As Long
LngPtrMove2 = Vba.CLng(AddressOf move2)
End Function
Please be aware of two things:
You cannot test the assignment in the VBE Immediate Window!
You must keep the leading "VBA." in all calling variants. For more information read this SO question: Difference between VBA.CBlah and CBlah
Hope this helps :-)
Consider this registered type library in a DLL:
[uuid(…), version(1.0)]
library structLib
{
importlib("stdole2.tlb");
[uuid(…)]
typedef struct MyStruct
{
BSTR m_sStr;
} MyStruct;
};
In vb6 I can reference this type library and use the UDT / struct in a compiled exe (simple form with a button), named a.exe:
Private Sub Command1_Click()
Dim obj As structLib.MyStruct
obj.m_sStr = "Hello"
MsgBox obj.m_sStr
End Sub
When I remove the struct from the type library and recompile it, the previously compiled a.exe still works, even though the struct definition is no longer present. I assume this succeeds because the definition is embedded into the executable during the vb6 compilation process.
However, things work differently when I compile the following vb6 code against the unmodified type library (struct included) into a new executable, named b.exe:
Private Sub Command1_Click()
Dim obj As structLib.MyStruct
obj.m_sStr = "Hello"
MsgBox obj.m_sStr
Dim vt as Variant
vt = obj
MsgBox vt.m_sStr
End Sub
Notice the assignment of the struct to a Variant.
When I remove the struct definition from the type library once again, recompile it, and try to run the previously compiled b.exe, the program silently fails as the form won't even show up. At minimum, I expected
Starting the executable loads the form.
Clicking the button throws an error, due to assigning the struct with missing type information to the Variant.
For the record, I have tried to reproduce this behavior in C++:
structLib::MyStruct obj;
obj.m_sStr = SysAllocString(L"Hello");
MessageBox(GetActiveWindow(), obj.m_sStr, obj.m_sStr, MB_OK);
ATL::CComVariant vtRec;
ATL::CComPtr<IRecordInfo> piRecInfo;
HRESULT hr = GetRecordInfoFromGuids(__uuidof(structLib::__structLib), 1, 0, 0, __uuidof(structLib::MyStruct), &piRecInfo);
vtRec.pRecInfo = piRecInfo;
vtRec.pvRecord = &obj;
PVOID pvItem = vtRec.pvRecord;
CComVariant vtStr;
hr = piRecInfo->GetField(pvItem, L"m_sStr", &vtStr);
MessageBox(GetActiveWindow(), vtStr.bstrVal, vtStr.bstrVal, MB_OK);
Here, the C++ client runs and GetRecordInfoFromGuids() correctly returns
0x8002802b (Element not found)
when the struct definition is missing in the type library.
Is this behavior in vb6 by design? What's the cause? And is it possible to start the vb6 executable and catch error information, even when extracting type information of a referenced struct fails?
Is this behavior in vb6 by design?
I don't think so.
What's the cause?
When you assign a IDL structure to a VARIANT, the [uuid] attribute is intrinsically used. As it doesn't exist anymore, you get an exception.
That's what you do when calling GetRecordInfoFromGuids in C++, you provide explicitely the uuid of the IDL structure __uuidof(structLib::MyStruct).
And is it possible to start the executable even when extracting type
information of a referenced struct fails?
I see 2 possibilities to achieve this goal:
use late binding instead of early binding, and check the reference
handle the exception which is thrown
Is it possible to call a JNI C function inside another JNI C function? (directly or indirectly), or, a JNI function inside a normal C function?
For example:
int inverse_transform(double real[], double imag[], size_t n) {
return Java_com_example_ffttest_FFTActivity_transform(imag, real, n);
}
and inverse_transform() is later called inside another method.
JNIEXPORT jint JNICALL Java_com_example_ffttest_FFTActivity_convolve(...)
{
....
inverse_transform();
}
Does this work? I tried but it gives me errors about parameters and I don't know how to use *env and obj.
Certainly it's possible. Those are just functions with funny names as far as C is concerned.
One word of caution though - if the JNI function uses its JNIEnv parameter, you need to pass a valid one from a non-JNI function.
At the end JNI methods are normal c++ methods so offcourse you can do it .
How do you cast a COM interface pointer to void pointer and then back to the COM pointer? Here is some code to illustrate my problem. It's very similar to this sample code: _com_ptr_t assignment in VC++
CoInitialize(NULL);
COMLib::ICalcPtr pCalc = COMLib::ICalcPtr("MyLibrary.Calculator");
pCalc->doSomething();
CoUninitialize();
return 0;
Now, if I were to cast the pCalc object to void*, how would I cast it back to COMLib::ICalcPtr? For example, the second line in the following code gives me a compile error 'QueryInterface' : is not a member of 'System::Void'. Obviously, it's trying to call IUknown.QueryInterface() on the object. Preferably I would like to do this without creating a new interface (hence, without implicitly calling QueryInterface and AddRef).
void *test = pCalc;
COMLib::ICalcPtr pCalc2 = test;//'QueryInterface' : is not a member of 'System::Void'
FYI, the reason I'm doing this is that the object is going to be passed around from java to jni VC++ code as a void* type. I'm open to any suggestion on what to do or what is going on behind the scene.
Same way you pass any other opaque structure that either doesn't fit in a pointer or doesn't convert easily: by passing its address.
void* test = new COMLib::ICalcPtr(pCalc);
...
COMLib::ICalcPtr pCalc2 = *(COMLib::ICalcPtr*)test;
delete (COMLib::ICalcPtr*)test;
This will result in calls to AddRef and Release, but not QueryInterface.
I have a vc++ dll in _cdecl calling convention. I want to use the exported function of that dll from the code in _stdcall calling convention. I m getting the linker error as expected. But how can i do that.
If you don't have sources to the stdcall DLL, You could load dynamically and specify the calling convention on the function pointer, otherwise project setting is used. Don't do this:
BOOL (*pBeep)(UINT) = 0; // defaults to project calling convention setting (/Gd etc)
If your project is set to __cdecl which is default, you'd actually want to explicitly set the function pointer to __stdcall:
BOOL (__stdcall *pBeep)(UINT) = 0;
make sure to cast correctly when assigning the function pointer as well:
pBeep = (BOOL (__stdcall *)(UINT))GetProcAddress(beepLibrary, "MessageBeep");