why vba can't successfully call dll that's written in c++? - c++

I got a c++ demo that has successfully called the API written in c++, now am trying to call those API from excel VBA. I've done quite a bit research but still not able to link them together.
Basically there's a API(TapQuoteAPI.dll) export function like this in demo
'TapQuote.h
TAP_DLLEXPORT const TAPICHAR *TAP_CDECL GetTapQuoteAPIVersion();
in demo c++ solution(TapQuoteAPI_Demo), i include the 'TapQuote.h' in demo.cpp,
the cout<<GetTapQuoteAPIVersion()<<endl; is successfully called, and result is print.
but when it comes to call this function in excel vba, i keep failing.
I tried to directly use the TapQuoteAPI.dll in excel like this, but not working.
Declare Function GetTapQuoteAPIVersion Lib "D:\Proejct\WIN32\TapQuoteAPI.dll" () As String
Then I also try to build another dll function with a deFile.def from TapQuoteAPI_Demo.dll since i successfully call it within the c++ demo.
Declare Function GetTapQuoteAPIVersion Lib "D:\Proejct\WIN32\TapQuoteAPI_demo.dll" () As String
also failed.
Could anyone shed some lights for me please?

Related

Can't find COM object from C++, although Guid it's registered

First of all happy new year to everyone, hope you're doing well!
I'm working on a C++ project in which I need to call a C# DLL I created following the first answer of this post. Once I have the DLL, I need to call it from Qt, so by using dumpcpp and the .tlb file generated by regasm, I managed to get the .cpp and .h files to use my classes. Just as a reference, the namespace of the classes is Wrapper, and the main class is Device with guid {DD4A4896-C105-4C60-839B-B18C99C8FE15}.
Once I have the generated files to use the DLL, if I try to create a Wrapper:: Device instance on Qt, I get the following error:
QAxBase::setControl: requested control {dd4a4896-c105-4c60-839b-b18c99c8fe15} could not be instantiated
QAxBase::qt_metacall: Object is not initialized, or initialization failed
It doesn't give any more information, so I tried to check if the guid was stored on the system registry (I used the regasm command explained on the previously quoted post, and It said that it was successful, but you never know). Opening Registry editor and searching for the Guid revealed that it's present at: Computer\HKEY_CLASSES_ROOT\WOW6432Node\CLSID\{DD4A4896-C105-4C60-839B-B18C99C8FE15}, which, as far as I know, is the right route for these guids, and it points to the right DLL.
I though It may be due to some kind ActiveQt problem, and as the previously quoted post explained how to use that DLL from VS C++, I decided to give it a try, using this as an another reference. I've finished with this code, which is supposed to create an instance of my Device object
#include <iostream>
#include <atlstr.h>
#import "C:\Users\javie\Documents\Wrapper\Wrapper\bin\x86\Release\netstandard2.0\Wrapper.tlb" named_guids raw_interfaces_only
inline void TESTHR(HRESULT x) { if FAILED(x) _com_issue_error(x); };
int main()
{
try
{
TESTHR(CoInitialize(0));
Wrapper::IDevicePtr devPtr = nullptr;
TESTHR(devPtr.CreateInstance("{DD4A4896-C105-4c60-839B-B18C99C8FE15}"));
}
catch (const _com_error& e)
{
CStringW out;
out.Format(L"Exception occurred. HR = %lx, error = %s", e.Error(), e.ErrorMessage());
MessageBoxW(NULL, out, L"Error", MB_OK);
}
CoUninitialize();// Uninitialize COM
std::cout << "Hello World!\n";
}
However, this doesn't work either, the createInstance method throws an exception of Class not registered and HR=80040154. Again, according to Registry editor, the class is registered, so I don't understand the error. I've also tried with devPtr.CreateInstance("Wrapper.Device"), devPtr.CreateInstance("Wrapper::Device") or `devPtr.CreateInstance("Wrapper::CLSID_Device") as the links I posted suggest, but in those cases I get another exception with HR=800401f3 and message Invalid class string.
It doesn't matter whether VS or Qt Creator are opened as administrator or not, I get the exact same error.
I have run out of ideas, and I really need to be able to use that DLL from Qt using the files generated by dumpcpp.
Does any one know what could be happening? It feels quite strange to me.
If your C++ application is 64-bit, that's the answer right there, because your C# component is 32-bit (or MSIL but registered to the 32-bit hive). In situations like these, a simple test using VBScript is always useful.
Write a simple VB Script (test.vbs)
Dim obj
Set obj = CreateObject("Wrapper.Device") ' or whatever your ProgID is
MsgBox TypeName(obj)
Now, run this macro 2 ways: with 32-bit and 64-bit versions of VBScript:
32-bit > c:\windows\SysWow64\cscript.exe test.vbs
64-bit > c:\windows\system32\cscript.exe test.vbs
This is assuming your C# component is dispatch compatible. If it's not, then it will still give you differing results that you can use to debug.
Assuming automation/IDispatch compatible, one will work and one won't if you have registered your component correctly.
Have you registered correctly? When I use regasm, I always use the the switches /tlb /codebase when registering the C# component for COM.
Ok, in case someone find the same error, I'll explain the solution I found.
The problem was that in my case, the C# class I developed depended on another 32 bits dll which was not registered on my PC. Once I registered the other dll, everything worked fine.
I don't know why VS kept telling me that the class was not registered when my class itselft was registered, it was one of its dependencies that wasn't registered.
Anyway, I discovered this thanks to Joseph's comments, so thanks a lot for your help.

How to call javascript function in cocos2d-js

How can I call javascript function in cocos2d-js.
I need to call split method.
If I call "This is a sample string".split(/ /g) it works fine. But I need to call it on a cocos2d object.
I believe somehow I need to convert cocos2d-js variable(string) to javascript executable object.
Please help.

"Invalid use of New Keyword" in VBA using old com object written in c++

I've scoured the web and stackoverflow for this answer but can't find anything. I have written a com object in C++ (for the fist time) that works when used in vbscript and through cocreateinstance in an executable file. So I decided to see if it would work in Excel VBA.
So I went into "References" and located my object there. Checked the box and started coding away. The following is the VBA code.
Function doCos(x As Double) As Double
Dim t As SimpleLib.IMath
Set t = New SimpleLib.IMath ' <- "Invalid use of New keyword" error here
doCos = t.Cos(x)
End Function
Intellisense recognizes my object in the Dim statement, but it does not appear when I use a Set statement. Obviously I am using a registered type library or else intellisense wouldn't work at all. Again, the com object can be used in vbscript or an executable, but for some reason can't be used, at least with the new keyword, in VBA.
Does anyone have an idea what may be wrong, or what may have to be added to the com object? Thanks.
One approach is to define a coclass in the IDL that includes the interface needed (IMath in my case). NOTE: That the [default] interface is hidden by default. So I simply defined interface IUnknown as the default. After compiling with MIDL a type library is generated which one should register with regtlibv12.exe.
I then included an additional IF statement in DllGetClassObject like if (rclsid == CLSID_Math) where CLSID_Math is corresponds to the CLSID defined in the file automatically generated from MIDL. All I did was copy and paste the body of the IF statement from if ( rclsid == IID_IMath ), updated the DLLRegisterServer and DLLUnRegisterServer functions, recompiled the project, and regsvr32.exe.
So the following works now.
Function docos(x As Double) As Double
Dim a As SimpleLib.IMath
Set a = New SimpleLib.Math
docos = a.Cos(x)
End Function
Thanks to Hans for the tip about the coclass. Learned something new and useful.

Regular Expression Search in Visual Studio 2010

I'm not sure if this is possible within VS, but I'm working with a massive VB.NET file that needs to log every function call for debug purposes. Problem is, that not every function has the Log command in it. I'm trying to use RegEx to find the function definitions that do not have a log within them.
This would NOT be a match:
Public Function Test1() as Boolean
Log.Tracelog("Test1()")
Return True
End Function
This WOULD be a match:
Public Function Test2() as Boolean
Return False
End Function
The closest I've come is using the following:
(function|sub|property) .*\n.*~(Log\.t)
In my own mind, it should work, but no matter how I word it, it's still pulling every function as a match, even those that have the "Log.Tracelog" call in the function.
Is there anyway I can search to find the latter case?
Try this:
(function|sub|property) .*\n~(.*Log\.t)
I moved .* from just before the ~() (preventmatch) to just inside it.
Why not use the debug.WriteLine methods for the functions you want logged. You can also use the stack to get the method name:
Private Function test1() As Boolean
Debug.WriteLine(New System.Diagnostics.StackTrace().GetFrame(0).GetMethod.Name)
Return False
End Function
Then the messages only output when debugging and only in the methods you want.

DLL interop / interesting error

char ARRAY[1024]; // <-- global
Code below works
myFunctionInDll("some string"); // everything ok
Code below doesn't work
myFunctionInDll(ARRAY); // after compilation the entry point of DLL cannot be found
So, to sum up, if I pass a "static string" to my function inside my dll the dll compiles and loads perfectly. However, if I populate the global array (chars) and then try and pass that to my function, again it compiles but when I try and call the function from my C# app I get 'entry point cannot be found.' This is really strange and I can find no reason why...
Thanks RU.
Anyone know why?
Did you write the interop or are you just using the .NET generated interop class? If the later try
string myStr = "some string";
myFunctionInDll(myStr);
Hope that helps.