Creating and using a DLL in CPP - c++

I am working on a project where I am creating a small DLL and then also creating a windows application to use it.
I can not figure out what is going on.
I have a function in the DLL called "startPicadorVisual" which takes one parameter which is a std::string.
In the application which is dependent on the DLL I have the following code in a mostly auto-generated .h file:
typedef void (__stdcall *f_startPicadorVisual)(string s);
namespace PicadorPrototype {
f_startPicadorVisual startPicadorVisual;
Form1(void) {
//Load DLL Funcs
HINSTANCE hGetProcIDDLL = LoadLibrary(L"..\\Debug\\Picador.dll");
if (!hGetProcIDDLL) {
std::cout << "could not load the dynamic library" << std::endl;
throw "Bad Stuff";
}
startPicadorVisual = (f_startPicadorVisual)GetProcAddress(hGetProcIDDLL, "startPicadorVisual");
if (!startPicadorVisual) {
std::cout << "could not locate the function" << std::endl;
throw "More Bad Stuff";
}
When which fails on the second step when I call GetProcAddress.
The functions are defined as follows in my DLL:
void __declspec(dllexport) startPicadorVisual(string fixtureNamet);
PicadorResults __declspec(dllexport) getPicadorReading(string fixtureName);
Can anyone tell me why this isn't working?

GetProcAddress fails if the name you give GetProcAddress doesn't match exactly the name of the function you're calling. By exact I mean everything -- characters that make up the function name, the function name must match casing, etc.
So either your DLL exported a different name and you didn't realize it, or you're not exporting the name at all.
The way you can find out the names of the exported DLL functions easily, you can use the Dependency Walker program found here: http://www.dependencywalker.com/
Also, it isn't a good idea to use C++ objects that allocate dynamic memory such as std::string as parameters. If you do that, your DLL will only work for applications that
Are compiled with the same version of Visual C++ as the DLL
Use the same compiler options when building the application and DLL
All components (DLL and app) must use the DLL version of the C runtime library.
Otherwise, your code would have undefined behavior, more than likely crash, even if you got as far as retrieving the function pointer correctly.

Related

SetDllDirectory LoadLibrary inside a DLL

Can I use C++ SetDllDirectory and LoadLibrary commands inside a C++ DLL to load another DLL? I have tried using them like this:
Executable calls the 1st DLL,
then 1st DLL loads the 2nd DLL,
then 2nd DLL does the calculations...
but when I run the executable, I get this error message:
This application has requested the Runtime to terminate it in an unusual way. Please contact the applications support team for more information.
2nd DLL works fine when linked directly to Executable!
This is the code inside my executable:
#include <windows.h>
#include <iostream>
int main(){
HINSTANCE hDLL_Link=NULL;
SetDllDirectory((LPCWSTR)L"C:\\Users\\MC\\Documents\\2014_07_01a_FDD_VC2008\\test_call_DLL\\EXE_calls_Link_DLL\\Release");
hDLL_Link=LoadLibrary((LPCWSTR)L"Link_DLL.dll");
if(hDLL_Link==NULL) std::cout<<"did not load"<<'\n';
typedef void (*Ptr_OPS_Link)();
Ptr_OPS_Link Ptr_OPS_Link_0;
Ptr_OPS_Link_0=(Ptr_OPS_Link)GetProcAddress(hDLL_Link,"OPS_Link");
Ptr_OPS_Link_0();
FreeLibrary(hDLL_Link);
system("pause");
}
this is the code inside the 1st DLL:
#include "Link.h"
extern "C" __declspec(dllexport)
void OPS_Link(){
Link*Link_Ptr_Object=NULL;
if(Link_Ptr_Object==NULL){
Link_Ptr_Object=new Link();
}
if(Link_Ptr_Object==NULL){
//can not throw inside __declspec(dllexport) functions marked extern "C" that's why std::cout is implemented:
std::cout<<"Error: could not link to FDD DLL"<<'\n';
system("pause");
}
delete Link_Ptr_Object;
Link_Ptr_Object=NULL;
}
Link::Link()
:m_void_Ptr_ObjectByDLL(NULL){
HINSTANCE hDLL=NULL;//handle to DLL
SetDllDirectory((LPCWSTR)L"C:\\Software\\Octave-3.6.1\\bin\\");
hDLL=LoadLibrary((LPCWSTR)L"C:\\Users\\MC\\Documents\\2014_07_01a_FDD_VC2008\\Executable\\Release\\FDD_DLL.dll");
if(hDLL==NULL){
throw "DLL loading could not be done";
}else if(hDLL!=NULL){
typedef void (*Ptr_OPS_FDD)(std::string, int, int);
Ptr_OPS_FDD Ptr_OPS_FDD_0;//pointer to procedure inside DLL
Ptr_OPS_FDD_0=NULL;
Ptr_OPS_FDD_0=(Ptr_OPS_FDD)GetProcAddress(hDLL,"OPS_FDD");
if(Ptr_OPS_FDD_0==NULL){
FreeLibrary(hDLL);
throw "DLL exported function address could not be determined";
}else{
//run the procedure inside DLL:
Ptr_OPS_FDD_0("FDD_INPUT_Truss_Bridge_Data2_Ambient_Inch_11Channels_77824Samples_SamplingFreq_256Hz.txt",11,256);//LabScaleTruss
//Ptr_OPS_FDD_0("FDD_INPUT_Ambient_EW_15Channels_3000Samples_SamplingFreq_20Hz.txt",15,20);//AmbientEW
//Ptr_OPS_FDD_0("FDD_INPUT_Meriden_3Channels(3_5_8)_3686400Samples_SamplingFreq_2048Hz.txt",3,2048);//MeridenBridge
FreeLibrary(hDLL);
}
}
}
There are a few things in your code that can cause failure:
You do not exit if the DLL cannot be loaded:
You are passing objects that internally use dynamic allocation, and thus will use the heap manager.
For 1. above, your main() function only does a simple cout if the library cannot be found. However instead of exiting, the main function proceeds as if the library was found.
For 2. above, passing std::string as a parameter to a DLL function is error prone and not recommended unless you know exactly what you're doing. The reason it is error prone is
The DLL that contains the function call may have been built with a different set of options than the DLL that calls the function. These differing options could cause a difference in the way that std::string is implemeted, how it's layed out in memory, etc.
The DLL that contains the function call may have been built by a different version of the compiler than the DLL that calls the function. Again, same issue with differing implementations of std::string
The DLL's and modules using std::string may not have been built using the DLL version of the C runtime library. If the DLL's/modules are not built and linked using the DLL version of the runtime library, the DLL will be using a different heap than the module. Any operation on std::string will be invalid, due to differing memory heaps being used.
So in a nutshell, unless you can guarantee that
You are building the modules and DLL's with the exact same version of the compiler and compiler options.
You are linking all modules to the DLL version of the runtime library.
Then passing std::string as a parameter, and in general, passing any object that maintains dynamically allocated memory, may or will lead to runtime errors.
Besides the inadequate error handling and using the standard library across module boudaries ,there are two other things to consider.
Can I use SetDllDirectory in a dll to ... ?
Yes you can ,but you SHOULDN'T ! (BUGS waiting to happen).
Why ? because the only entity that is responsable for changing environment is the main-application.
Library code (static or dll) doesn't know in which application it's going to be used.
It might work correctly in some programs and it may fail in others.
Can I use C++ LoadLibrary/FreeLibrary in a dll to ... ?
Yes you can ,but don't use them in the dllmain function since it can deadlock your program.
I solved the problem, and showed how here:
I changed the code inside executable and 1st DLL like below, to consider error handling, and also I added the "return 0;" now the executable links to 1st DLL and it works perfect... Actually the problem was that main needed to return something...I raplaced all the "std::string" with "char*" at the DLL boundaries...By the way, the reason that I want to develop two DLLs and I'm using "SetDllDirectory" inside the 1st one is that I want to call a DLL with a C# GUI, and the problem is that there is no "SetDllDirectory" command available in C#, therefore, I came up with the idea of developing two DLLs, inside first DLL, I will use "SetDllDirectory" to take care of the required dependencies (DLL is dependent on Octave and Octave Bin directory) and then I developed a 2nd DLL which carries out the actual computations...I know that there are some methods like "[DllImport("Kernel32.dll")]" and from there we can use "SetDllDirectory" in C# but that method looks painful.
The corrected code inside executable:
#include <windows.h>
#include <iostream>
int main(){
try{
HINSTANCE hDLL_Link=NULL;
hDLL_Link=LoadLibrary((LPCWSTR)L"Link_DLL.dll");
if(hDLL_Link==NULL){
throw "Link DLL did not load";
}else{
typedef void (*Ptr_OPS_Link)();
Ptr_OPS_Link Ptr_OPS_Link_0=NULL;
Ptr_OPS_Link_0=(Ptr_OPS_Link)GetProcAddress(hDLL_Link,"OPS_Link");
if(Ptr_OPS_Link_0==NULL){
throw "Link DLL exported function not found";
FreeLibrary(hDLL_Link);
}else{
Ptr_OPS_Link_0();
FreeLibrary(hDLL_Link);
}
}
}
catch(char*char_Ptr_Exception){
std::cerr<<"Error: "<<char_Ptr_Exception<<'\n';
}
system("pause");
return 0;
}
The corrected code inside 1st DLL:
#include "Link.h"
extern "C" __declspec(dllexport)
void OPS_Link(){
Link*Link_Ptr_Object=NULL;
if(Link_Ptr_Object==NULL){
Link_Ptr_Object=new Link();
}
if(Link_Ptr_Object==NULL){
////can not throw inside __declspec(dllexport) functions marked extern "C" that's why std::cout is implemented:
//std::cout<<"Error: could not link to FDD DLL"<<'\n';
system("pause");
}
delete Link_Ptr_Object;
Link_Ptr_Object=NULL;
}
Link::Link()
:m_void_Ptr_ObjectByDLL(NULL){
HINSTANCE hDLL=NULL;//handle to DLL
SetDllDirectory((LPCWSTR)L"C:\\Software\\Octave-3.6.1\\bin\\");
//path relative to executable (C# executable or C++ executable)
hDLL=LoadLibrary((LPCWSTR)L"FDD_DLL.dll");
if(hDLL==NULL){
throw "FDD DLL did not load";
}else if(hDLL!=NULL){
typedef void (*Ptr_OPS_FDD)(char*, int, int);
Ptr_OPS_FDD Ptr_OPS_FDD_0;//pointer to procedure inside DLL
Ptr_OPS_FDD_0=NULL;
Ptr_OPS_FDD_0=(Ptr_OPS_FDD)GetProcAddress(hDLL,"OPS_FDD");
if(Ptr_OPS_FDD_0==NULL){
throw "FDD DLL exported function not found";
FreeLibrary(hDLL);
}else{
//run the procedure inside DLL:
Ptr_OPS_FDD_0("FDD_INPUT_Truss_Bridge_Data2_Ambient_Inch_11Channels_77824Samples_SamplingFreq_256Hz.txt",11,256);//LabScaleTruss
//Ptr_OPS_FDD_0("FDD_INPUT_Ambient_EW_15Channels_3000Samples_SamplingFreq_20Hz.txt",15,20);//AmbientEW
//Ptr_OPS_FDD_0("FDD_INPUT_Meriden_3Channels(3_5_8)_3686400Samples_SamplingFreq_2048Hz.txt",3,2048);//MeridenBridge
FreeLibrary(hDLL);
}
}
}

exporting C++ dll to Delphi program

I have a dll with exporting function
extern "C" __declspec(dllexport) IDriver * __stdcall GetDriver()
There is a programm which is written on Delphi. It can't see the function GetDriver().
It's double awful because I can not get and modify sources of this program.
What may be the reason of successful loading my dll (according log file) and failed call exporting function? Thank you.
Window 7 x64, Visual Studio 2010, C++ project for x86 target
The most likely explanation is that the function will have been exported with a decorated name. I'd expect it to have been exported with the name GetDriver#0. So you could import it like this:
function GetDriver: IDriver; stdcall; external 'DllName.dll' name 'GetDriver#0';
Use a tool like Dependency Walker to check the exact name used to export the function.
If you cannot modify the Delphi code, then you'll need to make your C++ DLL match. Do that by using a .def file which allows you control over the exported name.
The other problem you will face is that Delphi's ABI for return values differs from that used by most other tools on the Windows platform. Specifically a return value is semantically a var parameter. On the other hand, your C++ compiler will regard the return value as an out parameter. My question on Delphi WideString return values covers exactly this issue.
Because of this, I'd expect the function declaration above to lead to access violations. Instead you should declare the return value to be a Pointer and cast it to an interface reference in your Delphi code. You'll need to double check and make sure that the reference counting is handled appropriately.
Again, if you cannot modify the Delphi code, you need to make the C++ code match. A Delphi interface return value is implemented as an additional var parameter following the other parameters. So, to make your C++ function match, declare it like this:
void __stdcall GetDriver(IDriver* &retVal);

Can't use DLL (written in C++) in Delphi: The procedure entry point could not be located

I've compiled a DLL in Visual Studio (the source code is in C++, which I barely understand). Here's a piece of Scraper.h:
struct SWin
{
char title[512];
HWND hwnd;
};
SCRAPER_API bool ScraperGetWinList(SWin winList[100]);
Now I'm trying to use the above function in my Delphi application:
type
tWin = record
title: String;
hwnd: HWND;
end;
function ScraperGetWinList(var WinList: Array of tWin): Boolean; external 'Scraper.dll';
var
myWinList: Array [1..100] of tWin;
procedure TMainForm.GetWinListButtonClick(Sender: TObject);
begin
ScraperGetWinList(myWinList);
...
The project doesn't compile, and I get the following message: The procedure entry point ScraperGetWinList could not be located in the dynamic link library: Scraper.dll.
What am I doing wrong?
From my Linux experience, I'd say that you've encountered so-called "name-mangling" issue. The entry point of your procedure is not called "ScraperGetWinList", but something like "_ZN18ScraperGetWinListEpN4SWin".
The thing is that, Unlike in C, in C++ language the name of entry point is not the same as the function name. No wonder: assume, you have a set of overloaded functions; they should have different entry points in your DLL. That's where name mangling comes into play.
The most common solution to this problem is to define interface of your library in such a way that it will use C calling convention. No name mangling will happen with the interface functions then.
Note that you don't have to write the whole library in C, you only should declare functions for them to emit C-like entry points.
Usually it's written like this:
extern "C" {
SCRAPER_API bool ScraperGetWinList(SWin winList[100]);
// More functions
}
Recompile your library and use it in Delphi without problems.
Note, that you should also adjust calling conventions (stdcall or cdecl) for them to match in your C++ header and Delphi code. However, that's best explained in another question.
Name mangling is most likely the problem. Name mangling is usually done is C++ code,
and when writing a DLL in C++ that should be used by code in an other langauge,
you should use the Extern "C" construction as Pavel Shved already suggested.
When using DLLs, especially when writtin in other languages, you should also keep
an eye on calling conventions. I suggest that you specify in both delphi and c++ to use the stdcall calling convenstion. This is the calling convention also used by the windows api, so it guarantees the best interoperatability between different compilers.
This would mean
extern "C" {
SCRAPER_API __stdcall bool ScraperGetWinList(SWin winList[100]);
}
and
function ScraperGetWinList(var WinList: Array of tWin): Boolean; external 'Scraper.dll';
But that's not all, the stdcall calling convention has an impact on the name mangling, and it would turn out to be something like _ScraperGetWinList#4 (Where 4 is the size of the parameter, where an array would have a pointer to the first element, so 4 bytes)
To confirm the correct symbols to use, I suggest Dependency Walker
( http://www.dependencywalker.com/ ) this program shows that exactly the function names are exported by the dll. Having confirmed the name to be '_ScraperGetWinList#4' then you add this in delpgi like this:
function ScraperGetWinList(var WinList: Array of tWin): Boolean; external 'Scraper.dll' name '_ScraperGetWinList#4';
Have you actually exported the entry point function in the c++ code? This really stumped me the first time I compiled a C++ dll in Visual Studio for use in a dotnet app.
For example, I needed to expose a print driver in unmanaged code so some other developers could access it in VB.net. This is what I did.
In foo.cpp:
extern "c" {
___declspec(dllexport) bool FooBar()
{
// Call some code on my cpp objects to implement foobar
}
}
Then in a file called foo.def:
LIBRARY "mylib"
EXPORTS
FooBar
AnyOtherFunctionsItExports
This is how I got it to work. I might not be doing things the best possiable way. I am a little light on C++ experience and also mainly don't work on windows.

Explicit Loading of DLL

I'm trying to explicitly link with a DLL. No other resources is available except the DLL file itself and some documentation about the classes and its member functions.
From the documentation, each class comes with its own
member typedef
example: typedef std::map<std::string,std::string> Server::KeyValueMap, typedef std::vector<std::string> Server::String Array
member enumeration
example: enum Server::Role {NONE,HIGH,LOW}
member function
example: void Server::connect(const StringArray,const KeyValueMap), void Server::disconnect()
Implementing the codes from google search, i manage to load the dll can call the disconnect function..
dir.h
LPCSTR disconnect = "_Java_mas_com_oa_rollings_as_apiJNI_Server_1disconnect#20";
LPCSTR connect =
"_Java_mas_com_oa_rollings_as_apiJNI_Server_1connect#20";
I got the function name above from depends.exe. Is this what is called decorated/mangled function names in C++?
main.cpp
#include <iostream>
#include <windows.h>
#include <tchar.h>
#include "dir.h"
typedef void (*pdisconnect)();
int main()
{
HMODULE DLL = LoadLibrary(_T("server.dll"));
pdisconnect _pdisconnect;`
if(DLL)
{
std::cout<< "DLL loaded!" << std::endl;
_disconnect = (pdisconnect)GetProcAddress(DLL,disconnect);
if(_disconnect)
{
std::cout << "Successful link to function in DLL!" << std::endl;
}
else
{
std::cout<< "Unable to link to function in DLL!" << std::endl;
}
}
else
{
std::cout<< "DLL failed to load!" << std::endl;
}
FreeLibrary (DLL);
return 0;}
How do i call (for example) the connect member function which has the parameter datatype declared in the dll itself?
Edit
more info:
The DLL comes with an example implementation using Java. The Java example contains a Java wrapper generated using SWIG and a source code.
The documentation lists all the class, their member functions and also their datatypes. According to the doc, the list was generated from the C++ source codes.(??)
No other info was given (no info on what compiler was used to generate the DLL)
My colleague is implementing the interface using Java based on the Java example given, while I was asked to implement using C++. The DLL is from a third party company.
I'll ask them about the compiler. Any other info that i should get from them?
I had a quick read through about JNI but i dont understand how it's implemented in this case.
Update
i'm a little confused... (ok, ok... very confused)
Do i call(GetProcAddress) each public member function separately only when i want to use them?
Do i create a dummy class that imitates the class in the dll. Then inside the class definition, i call the equivalent function from the DLL? (Am i making sense here?) fnieto, is this what you're showing me at the end of your post?
Is it possible to instantiate the whole class from the DLL?
I was trying to use the connect function described in my first post. From the Depends.exe DLL output,
std::map // KeyValueMap has the following member functions: del, empty, get, has_1key,set
std::vector // StringArray has the following member functions: add, capacity, clear, get, isEMPTY, reserve, set, size
which is different from the member functions of map and vector in my compiler (VS 2005)...
Any idea? or am i getting the wrong picture here...
Unless you use a disassembler and try to figure out the paramater types from assemly code, you can't. These kind of information is not stored in the DLL but in a header file coming with the DLL. If you don't have it, the DLL is propably not meant to be used by you.
I would be very careful if I were you: the STL library was not designed to be used across compilation boundaries like that.
Not that it cannot be done, but you need to know what you are getting into.
This means that using STL classes across DLL boundaries can safely work only if you compile your EXE with the same exact compiler and version, and the same settings (especially DEBUG vs. RELEASE) as the original DLL. And I do mean "exact" match.
The C++ standard STL library is a specification of behavior, not implementation. Different compilers and even different revisions of the same compiler can, and will, differ on the code and data implementations. When your library returns you an std::map, it's giving you back the bits that work with the DLL's version of the STL, not necessarily the STL code compiled in your EXE.
(and I'm not even touching on the fact that name mangling can also differ from compiler to compiler)
Without more details on your circumstances, I can't be sure; but this can be a can of worms.
In order to link with a DLL, you need:
an import library (.LIB file), this describes the relation between C/C++ names and DLL exports.
the C/C++ signatures of the exported items (usually functions), describing the calling convention, arguments and return value. This usually comes in a header file (.H).
From your question it looks like you can guess the signatures (#2), but you really need the LIB file (#1).
The linker can help you generate a LIB from a DLL using an intermediate DEF.
Refer to this question for more details: How to generate an import library from a DLL?
Then you need to pass the .lib as an "additional library" to the linker. The DLL must be available on the PATH or in the target folder.

Calling DLL functions from VB6

I've got a Windows DLL that I wrote, written in C/C++ (all exported functions are 'C'). The DLL works fine for me in VC++. I've given the DLL to another company who do all their development in VB. They seem to be having a problem linking to the functions. I haven't used VB in ten years and I don't even have it installed. What could be the problem?
I've declared all my public functions as follows:
#define MYDCC_API __declspec(dllexport)
MYDCCL_API unsigned long MYDCC_GetVer( void);
.
.
.
Any ideas?
Finally got back to this today and have it working. The answers put me on the right track but I found this most helpful:
http://www.codeproject.com/KB/DLL/XDllPt2.aspx
Also, I had a few problems passing strings to the DLL functions, I found this helpful:
http://www.flipcode.com/archives/Interfacing_Visual_Basic_And_C.shtml
By using __declspec for export, the function name will get exported mangled, i.e. contain type information to help the C++ compiler resolve overloads.
VB6 cannot handle mangled names. As a workaround, you have to de-mangle the names. The easiest solution is to link the DLL file using an export definition file in VC++. The export definition file is very simple and just contains the name of the DLL and a list of exported functions:
LIBRARY mylibname
EXPORTS
myfirstfunction
secondfunction
Additionally, you have to specify the stdcall calling convention because that's the only calling convention VB6 can handle. There's a project using assembly injection to handle C calls but I guess you don't want to use this difficult and error-prone method.
Try adding __stdcall at the end
#define MYDCC_API __declspec(dllexport) __stdcall
We have some C++ dlls that interact with our old VB6 apps and they all have that at the end.
A VB6 DLL is always a COM dll. I shall describe an example in as few words as possible. Suppose you have a ActiveX DLL project in VB6 with a class called CTest which contains a method as shown below
Public Function vbConcat(ByVal a As String, ByVal b As String) As String
vbConcat = a & b
End Function
and you have set the project name as VBTestLib in VB6 project properties and
you have compiled the project as F:\proj\VB6\ActiveXDLL\VBTestDLL.dll
You need to register the dll using the Windows command
regsvr32 F:\proj\VB6\ActiveXDLL\VBTestDLL.dll
now your C++ code :
#import "F:\proj\VB6\ActiveXDLL\VBTestDLL.dll"
using namespace VBTestLib;
void CDialogTestDlg::OnButton1()
{
HRESULT hresult;
CLSID clsid;
_CTest *t; // a pointer to the CTest object
_bstr_t bstrA = L"hello";
_bstr_t bstrB = L" world";
_bstr_t bstrR;
::CoInitialize(NULL);
hresult=CLSIDFromProgID(OLESTR("VBTestLib.CTest"), &clsid);
hresult= CoCreateInstance(clsid,NULL,CLSCTX_INPROC_SERVER,
__uuidof(_CTest),(LPVOID*) &t);
if(hresult == S_OK)
{
bstrR = t->vbConcat(bstrA , bstrB);
AfxMessageBox((char*)bstrR);
}
}
That's all there is to it, to get started off.