I am having some problems with a c++ dll i recently got from a friend.
I am trying to import the dll into an Excel VBA Add-in.
(I am using Excel 2010 32bit and the dll is compiled in Visual Studio 2008)
First of all i tried to import it but it failed with a runtime error 49.
I concluded that it possibly comes from a missing c++ declaration (__stdcal).
(i thought visual studio should do this automatically but okay)
Now i have a new dll with __stdcal in its declaration, but the methods are declared with a underscore ( _ ) at its beginning.
So when i try to declare the Sub, Excel tells me something like "invalid character"
is there a possibility to avoid this without altering the c++ files ?
'void _SaveFile(const char *FileName_);'
Declare Sub _SaveFile Lib "D:/DLL/TableController.dll" (ByRef FileName_ As String)
^
|
Thanks in advance
Here are some additional informations which maybe lead to a solution for my problems.
I got now some c++ code to debug my problem...
I still get the runtime error 49 but the dependency walker gives me now the right names of the methods( which is pretty awesome i think ;) )
I tried to use the same dll in an C# program.
As i expected it worked perfectly normal.
Here is my C# code
this is the import:
[DllImport("JLTable.dll",CallingConvention=CallingConvention.StdCall)]
internal static extern void JLReadFile(string _FileName);
[DllImport("JLTable.dll", CallingConvention = CallingConvention.StdCall)]
internal static extern long JLGetRowCount();
annd this happens if i click a Button
TableRunner.JLReadFile(#"D:\file.tab");
long rows = TableRunner.JLGetRowCount();
MessageBox.Show(rows.ToString());
Here is my code in VBA
The declaration:
Declare Function JLReadFile Lib "D:/JLTable.dll" (ByRef FileName_ As String)
Declare Function JLGetRowCount Lib "D:/JLTable.dll" () As Long
And the call:
Sub Read()
Dim path As String
path = "D:/file.tab"
JLReadFile (path)
Dim count As Long
count = JLGetRowCount()
End Sub
And Here is also the c++ code i want to call.
Because of some reason my friend doesn’t want me to show what the code exactly does but it still behaves the same way with this code.
The .h file(the JLTable_API is something like #define JLTable_API __declspec(dllexport))
#define STDCALL
extern "C"
{
JLTABLE_API void STDCALL JLReadFile(const char *FileName_);
JLTABLE_API void STDCALL JLSaveFile(const char *FileName_);
}
The .c++ file
void STDCALL JLReadFile(const char *FileName_)
{
//log something to a file
}
long STDCALL JLGetRowCount()
{
//log something to a file
return 0;
}
I am very grateful for every hint you can give me
And as always
Thanks in advance
I finally have a solution.
i found a blog which showed me what i did wrong.
http://aandreasen.wordpress.com/2008/05/05/how-to-create-a-dll-for-ms-excel-vba-with-microsoft-visual-c-2008-command-line-tools/
As described you need the correct method name, to figure out which is the correct one i used the dependency walker.
This finally led me to this declaration
VBA:
Declare Sub JLReadFile Lib "D:/JLTable.dll" (ByRef FileName_ As String) Alias "_JLReadFile#4" (ByRef FileName_ As String)
C++:
void __declspec (dllexport) _stdcall JLReadFile(const char *FileName_);
From a similar test I ran, you need to use the "Alias" keyword. So that it would be written similar to: Declare Sub SaveFile Lib "D:/DLL/TableController.dll" Alias "_SaveFile" (ByRef FileName_ As String)
Additionally, I don't think you have to pass filename by reference, but I could be wrong. It's been a while since I've used VB.
More information on importing functions from a dynamic library, check this page out
Related
First post here. I'm trying to follow the numerous tutorials out there for compiling a C++ dll as an Excel function and running it as an Excel function, but can't seem to get it to work. I'm running Windows 10 64-bit, Visual Studio Community 2017, and Excel 2016 64-bit.
I've followed the tutorials out there. I started a new project as a "Windows Desktop Wizard", and created an empty project as a DLL. This is my code below.
There are only these two files, in the "Source Files" folder under my project.
funct.cpp:
double __stdcall squareFxn(double x) {
return x * x;
}
This is my Def file, defFile.def:
LIBRARY "square"
EXPORTS
squareFxn
In the project properties, I made sure to set the Platform to x64 in the configuration manager, and added "defFile.def" without quotes to Linker/Input/Module Definition File.
It compiled fine. I put the following into VBA:
Declare PtrSafe Function squareFxn Lib "C:\MyPath\square.dll" (ByVal x As Double) As Double
When I debugged in Visual Studio, and ran in an Excel cell:
=squareFxn(5)
Visual studio is saying that x is an extremely small number (6.234E-310) and the function is returning zero.
The other problem I'm having is when I try to do this as a reference, with the appropriate changes (squareFxn(double &x) in funct.cpp and ByRef instead of ByVal in the VBA function declaration), I'm getting a read access error. I tried running Excel as an administrator, to no avail.
Does anybody know what's going on here? Any help would be greatly appreciated!!
You might need a wrapper function in VBA in order to cast the Variant (14 bytes) representing a cell to a Double (8 bytes). At least, this works in my situation: VSE2017, x64 DLL-build together with XL2016x64. For example:
in CPP:
extern "C" __declspec(dllexport) double __cdecl myCPPfunc(double x)
{
return some_double_expression;
}
in VBA:
Public Declare PtrSafe Function myVBAfunc Lib "complete_path_to_my.DLL" Alias "myCPPfunc" (ByVal x As Double) As Double
Function WS_myVBAfunc(ByVal x#)
Dim result#
result = myVBAfunc(x)
WS_myVBAfunc = result
End Function
You would also want to modify WS_myVBAfunc so that it accepts and returns an entire range of cells. This speeds up the whole process considerably.
Hello I am trying to create a simple C++ dll to be used in Excel.
Here is what I did:
.cpp file:
double _stdcall Test(double z)
{
return z+2.0;
}
.def file:
LIBRARY
EXPORTS
Test
In visual studio:
Project Properties > Configuration properties > Command > "Path/EXCEL.EXE"
Configuration manager > Platform > x64
In VBA:
Declare PtrSafe Function Test Lib _
"Path\MyDLL" (ByVal z As Double) As Double
But when I call Test(2) in Excel, it returns 2, and not 4. It seems like argument are seen as 0 alway (actually if I output the value of z in a file while calling the function, it is 2.122e-314).
Any inputs would be greatly appreciated.
Thanks
Edit 1:
If I change the argument and return value to int and in VBA to Long, Test(2) returns 3.
Anyone has an idea why the argument is 1 for int?
Apologies: Would have posted this as a comment but can't yet:
First: Your function may be exported as a C++ mangled name.
Use extern "C" to prevent name mangling. There are other ways to do this, but this is most direct. However if the Test function is successfully being called I'm not sure this is the issue.
Using extern "C" your C function would look like this.
extern "C"
double _stdcall Test(double z)
{
return z+2.0;
}
Second: Are you absolutely certain you are picking up the right DLL, not an old one which is missing your fixes? Try changing the function name to something more specific in your source and in the Excel VBA wrapper.
Third: If you are not running on a 64bit Excel system remove the PtrSafe declaration from your function specification in VB and recompile as 32-bit.
Fourth: Do not try to call your DLL directly from an Excel Cell. Wrap the function in VBA (example below) or use the CALL function.
The code below is an example how to wrap write a VBA cell function.
Public Function CellFunction_Test(x As Double) As Double
'' Tells excel to call this function only if the inputs change
'' and not on every recalculation
Application.Volatile False
'' Set an error handler, good practise for more complicated functions you might write later
On Error GoTo CellFunction_Test_EH:
'' Call into the DLL
CellFunction_Test = Test(x)
Exit Function
'' Error Handler
CellFunction_Test_EH:
CellFunction_Test = "Error - " & Err.Description
End Function
I was searching through stackoverflow questions but none of them answered my question. I have a game engine and I want to load player AI (written in c++) in runtime.
Click on button, file dialog appears
Choose file with AI (.dll or something?)
Click on 'start' button, game starts using AI's that I add.
AI could be a method or whole class, it doesn't matter. I think I should generate .dll but I not sure how to do that. This class should look like this:
class PlayerAI
{
void computeSomething(list of argument, Object& output)
{
// some logic
}
}
Assuming pure Windows platform since none specified -
If you want to inject DLL, first obtain a handle to it using LoadLibrary-function like so:
HINSTANCE handleLib;
handleLib = LoadLibrary(TEXT("YourDLL.dll"));
You may then obtain a function pointer to a specific function in the lib. Like this:
FUNC_PTR func;
func = (FUNC_PTR) GetProcAddress(handleLib, "yourFunc");
Then you can call the function like so:
(func) (L"TESTSTRING HERE");
When done, call FreeLibrary(libhandle)
How to declare a function as exported is in VS for instance like this (this is needed to mark your function in your DLL that you precompile:
__declspec(dllexport) int __cdecl yourFunc(LPWSTR someString)
{
//Code here...
}
Since you mention already compiled DLLs, you want to look at LoadLibrary and GetProcAddress. That's how you do runtime loads of DLLs and extract specific functions from them.
Examples can be found under Using Run-Time Dynamic Linking.
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.
I have tired to create a dll file in code blocks and then use it in my powerpoint presentation. In the dll file as I have mentioned below the argument of the function contains (LPCSTR)
void DLL_EXPORT SomeFunction(const LPCSTR sometext)
{
MessageBoxA(0, sometext, " DLL Message ", MB_OK | MB_ICONINFORMATION);
}
In my powerpoint file I have
Declare Function DLL_EXPORT _
Lib "myfile.dll" _
Alias "SomeFunction" (???)
and when I run the file I get
Because I do not know how to define the argument of my function in the powerpoint. I mean this part of the code:
Alias "SomeFunction" (???)
Your C++ code uses the wrong calling convention. It should be:
__declspec(dllexport) void __stdcall SomeFunction(const char* sometext)
You can use macros like DLL_EXPORT, APIENTRY, LPCSTR etc. if you wish. However, at least until you know what the macros all mean, it is probably easier to be explicit, as I show above.
The correct VBA declaration for your function is:
Declare Sub SomeFunction Lib "myfile.dll" (ByVal sometext As String)
However, this alone is not enough because your function will be subject to name decoration and mangling. You can use dumpbin or Dependency Walker to view the actual name by which your function is exported. Then your VBA declaration would need to be modified like so:
Declare Sub SomeFunction Lib "myfile.dll" Alias "<DecoratedNameHere>" (ByVal sometext As String)