I have a main application EXE "main.EXE". I've created a global pointer in a header file globalf.h with extern like:
globalf.h
extern SomeClass* cPtr;
Now in Main.EXE code
#include globalf.h
INitialize()
{
cPtr = new SomeClass(); // works fine.
D.DLL:
#include "globalf.h"
void DllFunc()
{
cPtr->someFunction1(); // link error unreslved external symbol.
I'm not able to access the global pointer variable in DLL code, even
though I had declared inMain.EXE code.
I know this declaration in main.EXE's Initialize() isn't visible to
DLL. But how do I achieve this? Is there a way in C++ for handling
such globals across DLL & EXEs.
Instead of exporting a global pointer variable, I'd pack it and other variables you need to share between the EXE and the DLL in a structure, and then pass a pointer to that structure as a function parameter for example to a DLL initialization function.
// Function exported from the DLL.
// Called by the EXE during initialization.
//
// The DLL receives a pointer to the global state structure,
// shared between the EXE and the DLL.
//
BOOL YourDllInit(GlobalStuff* pGlobal);
Related
I have a simple program that exports a DLL, this DLL exports functions from another DLL:
// SDK_DLL.cpp :
#include "functions.h"
#include "functions_advanced.h"
#include "stdafx.h"
#include <stdio.h>
using namespace std;
extern "C"
{
__declspec(dllexport) void DisplayHelloFromDLL()
{
printf("Hello from DLL...");
}
__declspec(dllexport) function_config FuncInit = appd_config_init();
__declspec(dllexport) function_config * FuncInit2()
{
function_config* cfg = function_config_init();
return cfg;
}
}
The function_config_init() returns a pointer, I cannot seem to find a way of making this proper export declaration.
I am loading a simple function to Delphi this way:
procedure DisplayHelloFromDLL; external 'C:\Users\Administrator\Documents\Visual Studio 2017\Projects\SDK_DLL\Debug\SDK_DLL.dll';
Will I need to change the way I am loading this pointer returning function?
Thanks a lot for your help.
FuncInit is an exported variable. Delphi does not support importing of variables via external, only of functions. If you need to import FuncInit, you will have to use GetProcAddress() directly to get a pointer to the variable at runtime:
type
// you did not show the C/C++ declaration
// of function_config, so I can't provide
// a translation here, but it is likely to
// be a struct, which is a record in Delphi ...
function_config = ...;
pfunction_config = ^function_config;
function GetFuncInit: pfunction_config;
begin
Result := pfunction_config(GetProcAddress(GetModuleHandle('SDK_DLL.dll'), 'FuncInit'));
end;
var
FuncInit: pfunction_config;
FuncInit := GetFuncInit;
For purposes of interop across languages/compilers, the only portable calling conventions are cdecl and stdcall. When no calling convention is specified in code, the default used by most C and C++ compilers is __cdecl (but can usually be specified in compiler settings), while the default used by Delphi is register instead (__fastcall in C++Builder).
When no parameters or return value are used, like in DisplayHelloFromDLL(), then declaring the wrong calling convention does not really matter. But when parameters and/or a return value are used, like in FuncInit2(), then declaring the correct calling convention matters. See Pitfalls of converting for more details.
So, the two DLL functions in question would likely need to be declared like the following in Delphi:
type
function_config = ...;
pfunction_config = ^function_config;
procedure DisplayHelloFromDLL; cdecl; external 'SDK_DLL.dll' name '_DisplayHelloFromDLL';
function FuncInit2: pfunction_config; cdecl; external 'SDK_DLL.dll' name '_FuncInit2';
If the DLL uses a .def file to remove name mangling from the exported names, you can omit the name attribute:
type
function_config = ...;
pfunction_config = ^function_config;
procedure DisplayHelloFromDLL; cdecl; external 'SDK_DLL.dll';
function FuncInit2: pfunction_config; cdecl; external 'SDK_DLL.dll';
I've a .h file that declare 3 different/similar class:
#ifndef _ICUSTOMCONTROLS_
#define _ICUSTOMCONTROLS_
class ICustomKnob1 : public IKnobControl
{
private:
// ..
public:
// ..
};
class ICustomKnob2 : public IControl
{
private:
// ..
public:
// ..
};
class ICustomButton : public IButtonControl
{
private:
// ..
public:
// ..
};
#endif // !_ICUSTOMCONTROLS_
I've a cpp file that define these class. I include the .h in the cpp and also in other .h/.cpp files within the project (which is a DLL).
At this point, in the CPP, I'd like to use a common/global struct (IText) for all the 3 classes. If I add the declaration in the .h:
IText gTextCustomControl;
in fact it "define" it, so I got a LNK1169 one or more multiply defined symbols found error message on compiling (as I said, I add this .h many times).
I could add it (with real definition) in the .cpp file:
IText gTextCustomControl = IText(12, &COLOR_WHITE, "Arial", IText::kStyleBold, IText::kAlignCenter, 0, IText::kQualityDefault);
But I will never sure in the DLL when this will be "processed" (maybe later the CTOR of the classes? maybe more times, wasting resources?). I don't think is a good way.
I could add extern as well on .h and define it as above, but for security reason is even worse (someone could access from the "extern" to it).
How would you manage this situation? Or its not possible share a common struct across objects?
"Bt I will never sure in the DLL when this will be "processed" (maybe later the CTOR of the classes?"
This is indeed the correct concern. DLL globals will be constructed from DllMain, and DllMain is heavily restricted in what it can do. You can't load other DLL's from there (loader lock), or do anything that would force Windows to load other DLL's. So using functions from other DLL's is generally also banned (exception: if your A.DLL causes your B.DLL to be loaded, then B.DLL may call functions from A.DLL. ).
Correct solution:
IText& getTextCustomControl();
...
IText& getTextCustomControl() {
static IText retval (12, &COLOR_WHITE, "Arial", IText::kStyleBold,
IText::kAlignCenter, 0, IText::kQualityDefault);
return retval;
}
This initializes the object on the first call to getTextCustomControl, which in general will happen way after all DllMain() functions have finished.
If you create the global variable inside the .cpp, there is no guarantee that it will be initialized prior to other global variables (see ยง3.6.3/2 [basic.start.dynamic]), in particular:
// dll.cpp
IText gTextCustomControl = ...;
ICustomKnob2::ICustomKnob2 () {
gTextCustomControl.doSomething();
}
// main.cpp
ICustomKnob2 knob2; // Oops! gTextCustomControl may be initialized after this.
If you want to be sure that gTextCustomControl initialized when you need it, you could put its declaration inside a function or some kind of singleton class, e.g.:
IText& get_gTextCustomControl () {
static IText ins(12, &COLOR_WHITE, "Arial", IText::kStyleBold,
IText::kAlignCenter, 0, IText::kQualityDefault);
return ins;
}
Then you use it instead of the global variable, this will ensure that the instance is constructed before any use of it.
ICustomKnob2::ICustomKnob2 () {
get_gTextCustomControl().doSomething();
}
Obviously, this will delay the construction of gTextCustomControl to its first use, which may not be what you want.
I am new to the DLL world. I have been given a Win32 DLL which has a lot of functions. Need to call these DLL functions from C++
I want to call CreateNewScanner which creates a new scanner object and get the results in C++.
Function mentioned in the DLL is:
BOOL CreateNewScanner(NewScanner *newScan);
and NewScanner is a struct, as below,
// Structure NewScanner is defined in "common.h" .
typedef struct{
BYTE host_no; // <- host_no =0
LONG time; // <- command timeout (in seconds)
BYTE status; // -> Host adapter status
HANDLE obj; // -> Object handle for the scanner
}NewScanner;
How will I call this function? Started with C++ and here is what I managed,
#include <iostream>
#include <windows.h>
using namespace std;
int main(){
HINSTANCE hInstance;
if(!(hInstance=LoadLibrary("WinScanner.dll"))){
cout << "could not load library" << endl;
}
/* get pointer to the function in the dll*/
FARPROC handle = GetProcAddress(HMODULE(hInstance), "CreateNewScanner");
if(!handle){
// Handle the error
FreeLibrary(hInstance);
return "-1";
}else{
// Call the function
//How to call here??
}
}
First of all, return "-1" is no good. You are expected to return an integer. So you surely mean return -1.
Now to the question. Instead of declaring the function pointer as FARPROC, it's easier to declare it as a function pointer type.
typedef BOOL (*CreateNewScannerProc)(NewScanner*);
Then call GetProcAddress like this:
HMODULE hlib = LoadLibrary(...);
// LoadLibrary returns HMODULE and not HINSTANCE
// check hlib for NULL
CreateNewScannerProc CreateNewScanner =
(CreateNewScannerProc) GetProcAddress(hlib, "CreateNewScanner");
if (CreateNewScanner == NULL)
// handle error
// now we can call the function
NewScanner newScan;
BOOL retval = CreateNewScanner(&newScan);
Having said all of that, usually a library will come with a header file (yours clearly does so you should include it) and a .lib file for load-time linking. Make sure that you pass the .lib file to your linker and you can simply do this:
#include "NameOfTheHeaderFileGoesHere.h"
....
NewScanner newScan;
BOOL retval = CreateNewScanner(&newScan);
No need to mess around with LoadLibrary, GetProcAddress and so on.
If you want to follow the LoadLibrary/GetProcAddress/FreeLibrary approach, consider the following "code path" (note that if you have the DLL public header file and the corresponding .lib file, just #include the public DLL header, and link with the .lib file, and just use the function whose prototype is defined in the DLL header as you would do with an ordinary C function called from C++ code).
Define a typedef for a pointer to the function exported from the DLL.
Note that the calling convention is specified (usually, Win32 DLLs with pure-C interfaces use __stdcall calling convention):
//
// Prototype of the DLL function, with *calling convention* specified
// (usually it's __stdcall for DLL with pure-C interface).
//
typedef BOOL (__stdcall *CreateNewScannerPtr)(NewScanner *);
Then you try loading the DLL using LoadLibrary:
//
// Try loading the DLL.
//
HMODULE hDll = LoadLibrary(L"WinScanner.dll"); // <--- Note the use of L"..." for Unicode
if (! hDll)
{
.... error
}
Note that the file name of the DLL is a Unicode string (note the L"..." decoration). In general, you should use Unicode in modern C++/Win32 code.
Then you can try getting the function pointer using GetProcAddress:
//
// Try getting the pointer to CreateNewScanner DLL function.
//
auto pCreateNewScanner = reinterpret_cast<CreateNewScannerPtr>
(
GetProcAddress
(
hDll, // DLL handle
"CreateNewScanner" // Function name
)
);
if (! pCreateNewScanner)
{
.... error
// Release the DLL
FreeLibrary(hDll);
// Avoid dangling references
hDll = nullptr;
}
Note that since you are using C++, it's better using C++-style casts (like reinterpret_cast<> in this case), instead of old C-style casts.
Moreover, since the type of the function pointer is specified in reinterpret_cast, it's useless to repeat it at the beginning of the statement, so the new C++11's keyword auto can be used.
You can use the returned function pointer to call the DLL function:
BOOL retCode = pCreateNewScanner( .... );
// Note: some other common prefix used in this case is "pfn"
// as "pointer to function" (e.g. pfnCreateNewScanner).
Once you have finished using the DLL, you can release it, calling FreeLibrary:
//
// Release the DLL
//
FreeLibrary(hDll);
hDll = nullptr;
In addition, note that you can use the C++ RAII pattern, and define a class with a destructor that automatically frees the DLL (this simplifies the code that manages the library loading/releasing parts).
e.g.
class RaiiDll
{
public:
// Load the DLL.
explicit RaiiDll(const std::wstring& filename) // may also provide an overload
// with (const wchar_t*)
{
m_hDll = ::LoadLibrary(filename.c_str());
if (! m_hDll)
{
// Error
throw std::runtime_error("Can't load the DLL - LoadLibrary() failed.");
// .... or use some other exception...
}
}
// Safely and automatically release the DLL.
~RaiiDll()
{
if (m_hDll)
{
::FreeLibrary(m_hDll);
m_hDll = nullptr;
}
}
// Get DLL module handle.
HMODULE Get() const
{
return m_hDll;
}
private:
HMODULE m_hDll; // DLL instance handle
//
// Ban copy (if compiler supports new C++11 =delete, use it)
//
private:
RaiiDll( RaiiDll & );
RaiiDll & operator=( RaiiDll & );
};
Then, in some code block, you can have:
{
// Load the library (throws on error).
RaiiDll scannerDll(L"WinScanner.dll");
// Get DLL function pointer
auto pCreateNewScanner = reinterpret_cast<CreateNewScannerPtr>(
GetProcAddress(scannerDll.Get(), "CreateNewScanner"));
if (! pCreateNewScanner)
{
.... error.
}
.... use the function
} // <--- DLL automatically released thanks to RaiiDll destructor!!!
Note how code is simplified thanks to automatic invocation of RaiiDll destrutor (and so of FreeLibrary), also in the error path case.
I have to use an ugly C-library inside my c++ application. In the following explanation I will call it UglyLib. I successfully compiled UglyLib as a statically linked library.
In the file ugly.h UglyLib uses an extern variable:
file ugly.h:
extern SomeStruct_type somestruct;
the variable is defined (and also used) in another file. I will call it anotherugly.c.
file anotherugly.c:
SomeStruct_type somestruct;
My c++ application is based on a generic template library (TemplateLib) and the application itself is composed by the main window GUI code and on an application library statically linked with the main window code. I will call this statically linked library ApplicationLib.
TemplateLib contains a templatelibfile.h, that exports a function foo using somestruct, the extern variable exposed by UglyLib.
file templatelibfile.h:
#include<ugly.h>
...
void foo()
{
...
do something with somestruct
...
}
foo function is used by appllibfile.h contained in the statically linked ApplicationLib.
file appllibfile.h:
#include<templatelibfile.h>
...
void applfoo()
{
...
foo();
...
}
Main Window application includes appllibfile.h
file main.cpp:
#include<appllibfile.h>
...
int main()
{
...
applfoo();
...
return 0;
}
In VS2008 when I try to compile the main window application, the microsoft linker give me this error
error LNK2001: unresolved external symbol "struct SomeStruct_type somestruct" (?somestruct##3USomeStruct_type##A)
If I add in templatefile.h a new definition of the extern variable the compiler stops to complain.
file templatelibfile.h:
#include<ugly.h>
SomeStruct_type somestruct
...
void foo()
{
...
do something with somestruct;
...
}
BUT I would wish to avoid it because I don't know if it is the correct thing to do (I don't want to risk to alter the semantic of UglyLib redefining a different instance of somestruct variable).
Have you some suggestions in order to avoid the linking problem without redefining the somestruct extern variable?
Thanks a lot!
It's probably because of the name-mangling that the C++ compiler does. Since anotherugly.c is a C source (presumably compiled with a C compiler), the symbol somestruct will be exposed without being mangled. When you compile the rest of the files with a C++ compiler, the linker then looks for a mangled name which does not exist.
I think surrounding the declaration in ugly.h in extern "C" might solve the problem.
My main program would load a simple dynamic library called hello.so
In main
void* handle = dlopen("./hello.so", RTLD_LAZY);
In main , pass a callback function called testing (defined somewhere in main.h) and invoke the hello() from the dynamic library
typedef void (*callback)();
typedef void (*hello_t)( callback);
/* do something */
hello_t hello = (hello_t) dlsym(handle, "hello");
hello(testing);
In dynamic library,
#include
#include "main.h"
extern "C" void hello( void (*fn)() ) {
/*do something and then invoke callback function from main */ fn();
}
Are there other ways to allow functions/data of main to be called/used from dynamic library apart from using callbacks?
No, this is the preferred way of doing it, in my opinion. Any other way that I can think of involves making the DLL aware of the objects in the program it's linked with, which is most likely bad practice.
Regarding data, just a reminder though you didn't ask, it's usually best practice to copy any data that needs to be stored, if it's passed across library/program boundaries. You can get into a complete mess if you have the library using data whose lifetime is controlled by the program, and vice versa.