I am looking for the most fool-safe way to pass a VB6 boolean variable to a function (written in C++, stdcall).
The C++ function will set the "bool" variable of a struct using this VB6 variable.
I have tried declaring it like this in C++:
extern "C" __declspec(dllexport) int SetParameter( BOOL bErrorView)
{
DLL_sSettings nSet;
nSet.bErrorView =(bErrorView != FALSE);
int ret = stSetParameter(sizeof(DLL_sSettings), nSet);
return (ret);
}
stSetParameter is declared as
extern "C" int ST_COMDLL_API stSetParameter(int DataLen, DLL_sSettings Settings);
The DLL_sSetting is declared as
typedef struct
{
bool bErrorView; // true: Show
// false: Don't show
(...)
} DLL_sSettings;
However, I am unable to get it to work.
I call it in VB6 using
Private Declare Function SetParameter Lib "MyDLL.dll" Alias "_SetParameter#4" (ByVal bErrorView As Boolean) As Long
But it does not work as expected, I guess somewhere the VB6 Boolean gets lost or is being incorrectly converted.
I am currently using VB6 Boolean, C++ BOOL and C++ bool.
I know that is not so nice, but I don't see any other way.
Does anybody spot something wrong in my code?
VB6 uses the StdCall calling convention by default (cdecl convention is supported if you create a type library with a module section describing your imports, instead of using Declare Function). And C++ supports a whole host of calling conventions: stdcall, fastcall, cdecl, thiscall.
It is important to note that calling functions using stdcall in another library is not enough to change your functions to stdcall. You can use a command-line switch to the compiler, but the most robust is to include the __stdcall keyword in your source code. It gets applied to the name of the function, like so:
int __stdcall functionname(int args);
Since you will also want to export those functions for VB6 to find them, you'll want extern "C" to reduce name mangling, and __declspec(dllexport) to place them in the exports table.
It's pretty common to use a macro to do all of the above at once. It looks like the library you are wrapping does this with ST_COMDLL_API. Inside the library, that will expand to __declspec(dllexport) __stdcall. For consumers, it will use dllimport instead.
Any time you are defining an API to be used across different compilers (or even different languages), it's a good idea to be very explicit about calling convention and structure packing (#pragma pack). Otherwise you are at the mercy of options specified in the project file and other headers files. Even if you are happy with the defaults the compiler uses, your public headers should be explicit, because eventually someone will try to use two libraries in the same program, and the other library may demand changes to the compile options.
BOOL is type definition for int.
it declared in windef.h as follows:
typedef int BOOL;
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
bool is C++ type, which can't be used in function prototype if you declare function with extern "C".
so VB should treat BOOL as Long (32 bit integer), not as Bolean. 0 means false otherwise (usually 1) it is true.
Related
I have a DLL and I want to call a function in it. I check the DLL using Dependency Walker and the result I got is:
void U2U_Test(void)
This is the code that I wrote, but GetProcAddress() returns NULL:
typedef void(*U2U_Test_pointer)();
void check() {
HINSTANCE hGetProcIDDLL1 = LoadLibrary(_T("my_dll.dll"));
if (hGetProcIDDLL1 == NULL)
return;
U2U_Test_pointer addr = (U2U_Test_pointer)GetProcAddress(hGetProcIDDLL1, "U2U_Test");
if (addr == NULL)
return;
return addr();
}
Depending on conventions and compiler used, the actual name exported in the DLL might not be exactly the same as the one you wrote in your source code.
This phenomenon is commonly called name decoration or name mangling.
In fact you are guaranteed to have exactly the same name only if
Your compiler conforms to C conventions (probably it does)
The function is exported in C and not C++. Use extern "C" to specify it.
The calling convention is _cdecl (specify __cdecl in function declaration)
For example, when call convention is __stdcall instead of __cdecl, which is common for many windows DLLs (they often write WINAPI or CALLBACK instead of __sstdcall), the name of the exported function is often suffixed by #n where n is the number of bytes expected on the stack for parameters.
In your case, it could be U2U_Test#0.
Indications like __declspec(dllimport) and __declspec(dllexport) tell the compiler to automatically take care of that kind of thing when DLLs are imported/linked at compile time.
IN C++, complex name decoration is used in order to support methods, function overloading, templates and other features, and each compiler invented crazy naming schemes to make sure there won't ever be any clash.
Because at DLL level, there's no template, no classes, only a list of exported symbols indexed by their name or an ID.
That's the reason why most DLLs are exported in C and why most header files declare functions coming from DLL inside a extern "C" { ... } block.
I'm new to, and learning C++ (know a lot of Java) and the following code confuses me...
I know this code fragment is dealing with a pointer-to-function (it's a callback, that makes sense) but what is throwing me off is the argument between the return type and the function name. What the bloody hell is that?
It looks like a type of function, but I have never heard of that and even after searching and reading about pointer-to-functions I was not able to find anything mentioning that functions could have a type.
If this is true, how does one define a function type?
Thanks, -Cody
GLFWCALL is not a type, it's a macro which is expanded to a calling convention specific to the platform, or an empty string. Here's a trimmed fragment of glfw.h:
#if defined(_WIN32) && defined(GLFW_BUILD_DLL)
#define GLFWCALL __stdcall
#elif defined(_WIN32) && defined(GLFW_DLL)
#define GLFWCALL __stdcall
#else
/* We are either building/calling a static lib or we are non-win32 */
#define GLFWCALL
#endif
Using a correct calling convention is important on x86/win32, since some of them expect the stack to be cleaned by callee and others by the caller. There can also be differences in the order of passing the arguments.
On Windows, GLFWCALL is a macro for __stdcall, and on other platforms, it's a macro for nothing.
__stdcall implements a particular calling convention, and is a compiler extension on top of normal C or C++.
Macros are pieces of code that do replacements on your code before the lexer and parser of your compiler interact with them.
The GLFWCALL is a macro that can expand to a calling convention if one is needed. Because this function will be called by external code, it has to use the calling convention that external code expects. For example, if the function puts its return value on the stack and the external code expects it in a register, boom.
The question marked part of the function signature is a preprocessor macro that is defined somewhere else in the header. Certain features on certain platforms have extra requirements.
For example functions in DLL files on the Windows platform often make use of the __declspec(dllexport) modifier but when the same header is included in a user's project they need to use __declspec(dllimport). Using a preprocessor macro for that purpose means they can just use that macro on all relevant functions and simply define the macro differently when compiling their own DLL or a user's DLL and on platforms where __declspec is irrelevant it can be defined to nothing. There are many other reasons for macros like that one.
In this particular case you can effectively pretend that macro is blank and ignore it entirely.
I was trying to export a simple test function for a dll to work with an application (fyi: mIRC) that specifies the calling convention as:
int __stdcall test_func(HWND mWnd, HWND aWnd, char *data, char *parms, BOOL show, BOOL nopause)
Now, to call this from the application, I'd be using test_func but I have noticed due to name mangling it is not as simple as I'd thought.
Through similar topics here I have come to the understanding that using extern "C" in combination with __declspec(dllexport) is an equivelant (somewhat) method of removing mangling to module definitions (.def). However, when using the extern/dllexport method my function (as an example) is always _test_func#numbers whereas the .def removed all mangling as required for use with the application i needed to export to.
Could someone please explain why this is? I'm just curious about the two methods. Thanks!
extern "C" has nothing to do with stdcall: it only declares that C++ name mangling (aka type-safe linkage; inclusion of type information in symbol name) is disable. You need to use it independent of whether you use C calling convention or stdcall calling convention.
In stdcall calling convention, the callee removes the parameters from the stack. To make that safe, the exported name contains the number of bytes that the callee will remove from the stack.
If the application you are exporting to requires that no #number suffix is added to the name, it probably means that it expects C calling convention. So you should stop declaring the function as __stdcall. When you the declare it as declspec(dllexport), you should get an undecorated name in the DLL.
In the DEF file, you can call the function whatever you want; no additional checking is performed.
dllexport/import are designed to be loaded back by themselves, not an old C library using GetProcAddress. The mangling you have seen is what all Microsoft compilers have done for a long time for __stdcall functions. Most likely, your target either expects a __cdecl function, not __stdcall, but if not, you will need to use a .def file to specifically un-mangle the name.
As we know that we can use c functions directly in c++, when is extern "C" necessary then?
If your function is implemented in a .c file, the .cpp files will need the extern "C" reference, or else they'd reference a mangled C++-style function name, and the link would fail.
It's also handy for exporting functions from DLLs so that they are exported with a non-mangled name.
It's necessary when a C++ function must be called by C code rather than C++ code.
Basically, when you want your C++ library to be backwards compatible.
There are two rather different uses for extern "C". One is to define a function in C++ that you should be able to call from C. I.e., you're writing code in C++, but it needs to interface with C code. In this case, you define the function as extern "C":
extern "C" {
int c_callable_func1() {}
int c_callable_func2() {}
}
When you do this, the interface of those functions must follow pretty much the same rules as they would in C as well (e.g., you can't overload the functions or use default values for any parameters).
The other (considerably more common) situation is that you have code written in C that you want to be able to call from C++. In this case, the function definitions remain exactly as before, but the functions need to be declared/prototyped as extern "C". In a typical case, you want to use a single header that can be #included in either a C or C++ file, so the structure looks something like this:
// myheader.h
#ifndef MY_HEADER_H_INCLUDED_
#define MY_HEADER_H_INCLUDED_
#ifdef __cplusplus
extern "C" {
#endif
int func1(void);
void func2(int);
#ifdef __cplusplus
}
#endif
#endif
So, a C++ compiler will see function declarations (and typedefs, etc.) surrounded by an extern "C" block, while a C compiler will see prototypes, not surrounded by something it doesn't recognize.
In the first case (C++ functions callable from C), you'll normally structure the header roughly the same way, so you can also call those functions from C++ if necessary (but at the interface, you still lose all extra features of C++ like function overloading).
As you know that c++ support function overloading, which define the same function or method many times with different parameters. To do this, the compiler has to add some part of symbols for each one ... for example, the compiler will change the function name foo in the following declaration
from
void foo(int f,char c);
to
foo#i&c
Unfortunately, C doesn't support this. All function names remain the same after compiling it. So, to call a c++ function from c, you have to know the exact name after the modification and I think it's hard and different from a compiler to another.
to work around this and be able call c++ function from c and stop the compiler from changing the names you have to use this keyword like
extern "C" {
void foo(int f,char c);
}
that's it !!!
Because the function signatures generated by C and C++ compilers differ -- this sets up the C convention for C function even when using C++.
I am just trying to further understand extern C functions.
According to my knowledge, an extern C function is always a function you are trying call from an application that has already been compiled. Either a executable, static or dynamic library.
extern "C"
{
HRESULT CreateDevice();
typedef HRESULT (*CREATEDEVICE)();
HRESULT ReleaseDevice();
typedef HRESULT (*RELEASEDEVICE)();
}
So my question is...
Is my understanding correct ??
Does it always have to be a C function pointer ??'
Why must you use a typedef for each function ??
I presume that when you use the GetProcAddress(). You are allocating memory on that particulars applications HEAP and not the one you are calling it from. Therefore you must release it from that heap as well ??
extern "C" has 2 implications. First, it declares that the symbolic names of the functions are not "name mangled" to support C++. Second, it tells the compiler that the function is called using the C calling convention rather than the PASCAL calling convention. The difference has to do with when the return address is pushed on the stack. Using the wrong calling convention will crash your app.
This declaration is for the compiler, not the linker. So the extern C function could exist in your own modules or in a binary library: the source of actual bytes for the function implementation are resolved by the linker. If the function signature is declared as a regular C++ function and not extern C, the compiler will mangle the symbolic name to encode type information from the function signature. This will make it incompatible with object code generated by other C++ compilers. Therefore creating an extern C function allows you to share code between compilers in binary form. Note that you can't expose member functions this way, only old-style C functions.
It doesn't have to be a function pointer. You can specify the function declaration normally and prefix it with extern "C", as shown in some Microsoft examples.
If you use GetProcAddress() you are not allocating any memory. You simply get the memory address of the function inside the DLL that has already been loaded into memory (with LoadLibrary(), presumably).
Even when using function pointers (such as those returned by GetProcAddress) you don't have to use typedef, it's just that the code looks pretty ugly without it. It's always hard to figure out what to write as well. I think it would be something like:
void (*pReleaseDevice)() = (void (__cdecl *)(void))GetProcAddress(hInstance, "ReleaseDevice");
extern "C" {} is a C++ convention to declare that the enclosed functions are C functions -- not C++ functions. C++ has a slightly different naming convention which conflicts with C. If you have a library written in C and want to use it in a C++ program, you have to use extern "C" {} to let the compiler know these are C functions. If the library was written in C++ I believe the extern "C" {} will cause an error.
Note that extern has multiple meanings -- this specific case is a C++ convention and is unrelated to different uses of extern. For example,
extern int count;
has a completely different meaning than extern "C" {}.
The typedef is separate from the extern "C" {} issue. typedefs let you create aliases for common types that make more sense. For example, declaring structs is often a verbose process. I can use a typedef to shorten it:
struct mystruct {int a; int b};
typedef struct mystruct returncode;
// I can now declare a variable as type 'returncode'
returncode a;
Thus, in your example the HRESULT is really an alias for (*CREATEDEVICE)() although I believe you have to put it before the function (and not after).
One important aspect of specifying extern "C" linkage is that the function names do not get mangled, which is the default for C++ names.
In order for your library's functions to be able to be loaded using GetProcAddress, you need to either add the function to the .def file, use __declspec(dllexport) or use extern "C".
To answer, in order:
extern "C" functions are used for interop with C from C++. Using them has the consequence that C code can call the function. As the windows API is a C API all functions are extern "C" to ensure that C and C++ code can make use of the API.
In order for c++ programs to interoperate with other languages, including C, as a convention , functions are exported using extern "C". Which is why a lot of dll code does this. It is not a technical requirement however.
So no, it does NOT have to be a C function pointer.
You don't have to use typedef's either.
The example code provided is from a header file that is publishing the exports of a DLL twice - Once as the set of extern "C" methods that are exported so that the dll can be statically linked. the other as a set of function pointer types, so that the dll can be dynamically loaded, and the function pointer types used with GetProcAddress.