I wrote this code in c++:
extern "C" __declspec(dllexport) int __stdcall sumx(int a, int b)
{
int result;
result = a + b;
return result;
}
I also tried:
int __stdcall sumx(int a, int b)
{
int result;
result = a + b;
return result;
}
and build win32 dll. then copy it in PB directory.
I define it external function.
And I call it:
when I run it:
Why do error occurs?
tnx
After some tests here I think that your problem may result from a name decoration of your exported function. I.E: instead of being named sumx in the dll, it is named _sumx#8 by the compiler.
You can check that by invoking dumpbin /exports keyadll.dll. With my test dll, it shows:
C:\dev\powerbuilder\dlltest>dumpbin.exe /exports keyadll.dll
Microsoft (R) COFF/PE Dumper Version 8.00.50727.762
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file keyadll.dll
File Type: DLL
Section contains the following exports for keyadll.dll
00000000 characteristics
5627876B time date stamp Wed Oct 21 14:39:07 2015
0.00 version
1 ordinal base
1 number of functions
1 number of names
ordinal hint RVA name
1 0 0000100A _sumx#8 = #ILT+5(_sumx#8)
^====================== HERE is the point!
Summary
1000 .data
1000 .idata
2000 .rdata
1000 .reloc
1000 .rsrc
2000 .text
BTW, the #8 in the name stands for the 8 bytes (2 x sizeof(int)) of parameters that are given to the function.
You have 2 options to fix that:
use the exact _sumx#8 name in the declaration of the external function in PB (you can use an alias for not changing your PB code):
function int sumx (int a, int b) library "keyadll.dll" alias for '_sumx#8'
I don't consider that solution being very elegant, though.
you can force VC to name the exported as YOU want (and not the reverse!) by using a module definition file (a .def).
in VS, choose to add a new item to the project / module definition file
simply put the names of the functions to export. It will contain
LIBRARY "keyadll.dll"
EXPORTS
sumx
Rebuild your dll and it should be OK for PB.
Related
I'm attempting to use GDB to debug a PowerPC ELF image compiled by the Green Hills GHS compiler from C++ source. The GHS MULTI debugger uses a proprietary debugging format, but the compiler provides a -dwarf2 option to produce native DWARF-2 debugging information as well. GDB is able to read at least some information from the DWARF-2, and can do things like map line numbers to addresses and find the addresses of symbols, but many things such printing local variables in member functions do not work.
I compiled this very simple program with g++ targeting x86 and GHS targeting PowerPC to compare the two. The -dwarf2 and -G flags were set in the top level .gpj for GHS to produce DWARF-2 debug information. I did a readelf --debug-dump and confirmed that GHS did generate what looks like reasonably correct DWARF-2.
class ClassA {
public:
int Method(bool arg) {
int local_1 = arg * 2;
member_var_ = local_1;
return local_1;
}
int member_var_;
};
int FuncA(int arg) {
int local_2 = arg * 2;
return local_2;
}
double global_a = 1;
namespace NamespaceA {
int FuncB(int arg) {
int local_3 = arg * 2;
return local_3;
}
}
int main(int argc, char *argv[]) {
ClassA a;
return a.Method(true);
}
GDB is able to list all the functions from the g++ compiled ELF:
gdb hello
...
Reading symbols from hello...done.
(gdb) info func
All defined functions:
File hello.cc:
int ClassA::Method(bool);
int FuncA(int);
int NamespaceA::FuncB(int);
int main(int, char**);
GDB does not list the member function or the function declared inside a namespace from the GHS compiled ELF:
gdb hello
...
Reading symbols from hello...done.
(gdb) info func
All defined functions:
File src/hello.cc:
int FuncA(int);
int main(int, char**);
Non-debugging symbols:
...
Is there an incompatibility between GHS generated DWARF-2 and GDB?
For namespaces support you need at least DWARF3 format. It looks like DWARF2 is unable to represent C++ namespaces because it was completed before C++ namespaces were even considered, see DWARF3 features:
3 Major New Features
3.1 C++ , including Namespaces
DWARF2 was completed before the C++ Standard and before C++ namespaces were even considered. DWARF3
provides a complete set of features using DW TAG namespace, DW TAG
imported declaration, DW AT import, and DW AT extension that enables
an implementation to represent the visible namespaces correctly in
every function. Implementations may choose to emit a single namespace
declaration showing the complete namespace at the end of the
compilation unit as this is simpler, though it loses some of the
details of some uses of C++ Namespaces.
I have written the following code (x64 VS 2015):
typedef void(__stdcall *foo)(void* v);
HMODULE hmod = GetModuleHandle(NULL);
foo f = (foo) GetProcAddress(hmod, "_foo0");
f(0);
foo0 is defined as:
extern "C" void __stdcall foo0(void* v){int a = 0;}
I have disabled all optimizations and security checks.
What I want the code to do is to find the address of the foo0 and then call it.
For some weird reason, calling GetLastError() after GetModuleHandle() returns 0x00000032 which means ERROR_NOT_SUPPORTED, but it does return some nonzero value which I assume is the handle to the executable. GetProcAddress() returns 0x0000000000000000 and a GetLastError() call after it returns 0x0000007f which means ERROR_PROC_NOT_FOUND, but I defined the proc!
Why is this happening? Is GetProcAddress() not supposed to be used with GetModuleHandle()?
The code fails because GetProcAddress requires the supplied symbol to have been exported from the module in question. That is, the symbol must have been listed in the PE module's export table. You do not export the symbol, and so GetProcAddress cannot find it. Hence GetProcAddress returns NULL. If you wish to use GetProcAddress then you must export the symbol. Either by naming it in a .def file, or by using __declspec(dllexport).
Some other comments:
You appear to have a mismatch of calling conventions, stdcall and cdecl.
You don't perform any error checking. For these particular function you need to check the return value. If that indicates that the function has failed, then call GetLastError for extended error information.
It should be:
extern "C" __declspec(dllexport) void foo0(void* v) { int a = 0; }
and:
foo f = (foo)GetProcAddress(hmod, "foo0");
^^~~~ no need for underline
as to your GetLastError issue, I am not sure about it - I suppose it might be some random value.
I have the Xsteam.dll file that works in all of my LABVIEW projects properly; but now I want use it (Xsteam.dll) in a simple visual C++ project (in visual studio 2013 or ...).
I dont have any other file related it (such as *.h , *.lib and etc).
I know that the Xsteam.dll written in c/c++ language and I know all of its functions and variable types of their inputs and outputs arg.
I usually use the Xsteam.dll in LABVIEW at this setting:
library name or path: c:\XSteam.dll
function name: h_pT
thread: run in UI thread
calling convention: stdcall(WINAPI)
function prototype : double h_pT#16(double arg1, double arg2);
return type : Numeric 8-byte double
arg1: Numeric 8-byte double Pass: Value
arg2: Numeric 8-byte double Pass: Value
prototype for these procedures:
MgErr Proc(InstanceDataPtr *instanceState);
How to use Xsteam.dll by a simple Vc++ program?
example:
HMODULE hModule = LoadLibrary("c:\\XSteam.dll");
typedef double (* FNPTR) (double , double );
FNPTR pfn = (FNPTR)hModule.GetProc("h_pT");
if ( NULL != pfn )
{
double result=pfn(arg1, arg2);
}
You'll need to make a header file and use dumpbin and lib to create an import library (*.lib). Look here or here.
I'm trying to get an DllExport from vb.net to unmanaged c++ working.
I'm using Robert Giesecke's Unmanaged Exports with Visual Studio 2012 and tried to follow this very helpful hints. I copy the dlls from the .Net project by an post build action in the directory where my *.cpp and *.h files reside.
I checked my dll with dumpbin /EXPORTS Nugget.Discovery.dll and it tells me that there are exports:
File Type: DLL
Section contains the following exports for \Nugget.Discovery.dll
00000000 characteristics
52554A05 time date stamp Wed Oct 09 14:20:21 2013
0.00 version
0 ordinal base
2 number of functions
2 number of names
ordinal hint RVA name
0 0 0000532E StartAnnouncing
1 1 0000533E StopAnnouncing
Summary
2000 .reloc
4000 .rsrc
2000 .sdata
4000 .text
But if I try to import it in the cpp file with
#import "Nugget.Discovery.dll"
void StartAnnouncing(int serial);
I get one IntelliSense error and one error after I try to compile:
IntelliSense: cannot open source file "Debug/Nugget.Discovery.tlh"
error C1083: Cannot open type library file: 'nugget.discovery.dll': Fehler beim Laden der Typbibliothek/DLL.
Any idea what I'm doing wrong?
Best regards!
Stefan
As part of DllExport, a .lib file is generated. You can use that to use the normal C++ linker instead of LoadLibrary/GetProcAddress.
Starting from the managed code you posted, on the native side:
extern CALLBACK void StartAnnouncingType(int serial);
extern CALLBACK int TestType(void);
int _tmain(int argc, _TCHAR* argv[])
{
int test = TestPtr();
StartAnnouncingPtr(1);
}
In the settings of you unmanaged project, add Nugget.Discovery.lib to the project properties: Configuration Properties->Linker->Input. And copy the Nugget.Discovery.dll to the output directory.
Ok, thanks to Hans Passant I came to this solution:
This is my code on the managed side:
Imports System.Runtime.InteropServices
Imports RGiesecke.DllExport
Public NotInheritable Class Beacon
Private Sub New()
End Sub
Private Shared _nuggetAnnouncement As NuggetAnnouncement
' ReSharper disable UnusedMember.Local
''' <remarks>Cannot be called from managed code!</remarks>
<DllExport("StartAnnouncing", CallingConvention.StdCall)>
Private Shared Sub StartAnnouncingNative(serial As Integer)
StartAnnouncing(serial)
End Sub
''' <remarks>Cannot be called from managed code!</remarks>
<DllExport("Test", CallingConvention.StdCall)>
Private Shared Function TestNative() As Integer
Return Test()
End Function
' ReSharper restore UnusedMember.Local
Public Shared Sub StartAnnouncing(serial As Integer)
'do something
End Sub
Public Shared Function Test() As Integer
Return 42
End Function
End Class
Interesting is, that I cannot call functions that are marked with <DllExport> from managed code (even if they are Public).
And this is the code on the native side:
typedef void (CALLBACK* StartAnnouncingType)(int);
typedef int (CALLBACK* TestType)(void);
int _tmain(int argc, _TCHAR* argv[])
{
HINSTANCE dllHandle = NULL;
StartAnnouncingType StartAnnouncingPtr = NULL;
TestType TestPtr = NULL;
wchar_t dllNameWide[64];
int size = mbstowcs(dllNameWide, "Nugget.Discovery.dll", sizeof(dllNameWide));
dllHandle = LoadLibrary(dllNameWide);
if (NULL != dllHandle)
{
//Get pointer to our function using GetProcAddress:
StartAnnouncingPtr = (StartAnnouncingType)GetProcAddress(dllHandle,"StartAnnouncing");
TestPtr = (TestType)GetProcAddress(dllHandle,"Test");
int test;
if (NULL != TestPtr) test = TestPtr();
int serial = 1;
if (NULL != StartAnnouncingPtr) StartAnnouncingPtr(1);
//Free the library:
FreeLibrary(dllHandle);
}
}
Are there any other better solutions?
Ciao!
Stefan
I'm trying to do a little test-plugin using NPAPI for firefox. This is my code so far:
/* File: npp_test.cpp
Copyright (c) 2012 by Niklas Rosenstein
Testing the NPAPI interface. */
// - Includes & Preprocessors --------------------------------------------------
// - -------- - ------------- --------------------------------------------------
#define DEBUG
#ifdef DEBUG
# include <iostream>
using namespace std;
# include <windows.h>
#endif // DEBUG
#include <stdint.h>
#include <npapi.h>
#include <npfunctions.h>
#include <npruntime.h>
#define DLLEXPORT extern __declspec(dllexport)
// - NPAPI Calls ---------------------------------------------------------------
// - ----- ----- ---------------------------------------------------------------
NPError NP_New(NPMIMEType pluginType, NPP npp, uint16_t mode, int16_t argc,
char* argn[], char* argv[], NPSavedData* saved);
// - Entrypoints ----------------------
// - ----------- ----------------------
NPError NP_GetEntryPoints(NPPluginFuncs* pFuncs) {
# ifdef DEBUG
cout << "NP_GetEntryPoints\n";
# endif // DEBUG
// Initialize plugin-functions
pFuncs->newp = NP_New;
return NPERR_NO_ERROR;
}
NPError NP_Initialize(NPNetscapeFuncs* npFuncs) {
# ifdef DEBUG
cout << "NP_Initialize\n";
MessageBox(NULL, "NP_Initialize", "Plugin-message", 0);
# endif // DEBUG
return NPERR_NO_ERROR;
}
NPError NP_Shutdown() {
# ifdef DEBUG
cout << "NP_Shutdown\n";
# endif // DEBUG
return NPERR_NO_ERROR;
}
// - Plugin Execution -----------------
// - ------ --------- -----------------
NPError NP_New(NPMIMEType pluginType,
NPP npp,
uint16_t mode,
int16_t argc,
char* argn[],
char* argv[],
NPSavedData* saved) {
# ifdef DEBUG
cout << "NP_New\n";
# endif
if (!npp)
return NPERR_INVALID_INSTANCE_ERROR;
return NPERR_NO_ERROR;
}
I'm compiling the code using g++ 4.4.1
g++ npp_test.cpp -I"D:\include\xulrunner" -shared -Wall -Wextra -o "npp_test.dll"
Compiles fine, but looking at the DLLs content using DLL Expat, the names are not as expected:
==================================================
Function Name : _get_output_format
Address : 0x6889c658
Relative Address : 0x0001c658
Ordinal : 5 (0x5)
Filename : npp_test.dll
Type : Exported Function
Full Path : C:\Users\niklas\Desktop\npp_test.dll
==================================================
==================================================
Function Name : _Z6NP_NewPcP4_NPPtsPS_S2_P12_NPSavedData
Address : 0x68881270
Relative Address : 0x00001270
Ordinal : 4 (0x4)
Filename : npp_test.dll
Type : Exported Function
Full Path : C:\Users\niklas\Desktop\npp_test.dll
==================================================
==================================================
Function Name : NP_GetEntryPoints#4
Address : 0x688811d8
Relative Address : 0x000011d8
Ordinal : 1 (0x1)
Filename : npp_test.dll
Type : Exported Function
Full Path : C:\Users\niklas\Desktop\npp_test.dll
==================================================
==================================================
Function Name : NP_Initialize#4
Address : 0x68881205
Relative Address : 0x00001205
Ordinal : 2 (0x2)
Filename : npp_test.dll
Type : Exported Function
Full Path : C:\Users\niklas\Desktop\npp_test.dll
==================================================
==================================================
Function Name : NP_Shutdown#0
Address : 0x6888124f
Relative Address : 0x0000124f
Ordinal : 3 (0x3)
Filename : npp_test.dll
Type : Exported Function
Full Path : C:\Users\niklas\Desktop\npp_test.dll
==================================================
Shouldn't they be called like in the source? When "expating" the java-dll for firefox, just for example, the names are fine. Using DLLEXPORT as
#define DLLEXPORT __declspec(dllexport)
doesn't work either. But this at least "removes" the functions _get_output_format and _Z6NP_NewPcP4_NPPtsPS_S2_P12_NPSavedData from being exported, whyever they are exported when not using DLLEXPORT.
Why are the exported functions names with an additional #4/#0 suffix ? I guess the number after the # specifies the number of bytes the function takes as arguments, but when exporting, this actually shouldn't be contained in the name, right ?
The #(stack_size_of_params) is a name decoration for stdcall extern "C" functions. I'm more familiar with Microsoft tools but my belief is that you will need to use a .def file to export undecorated names for functions that use stdcall.
Edit: Websearch suggests --kill-at command line option for the GNU tools could avoid need for irksome .def files.
This is C++ so names are mangled unless you declare them also with extern "C"
If you want control over exported function names, use an EXPORTS section in a linker definition file (*.def), not __declspec(dllexport).
With GCC NP_EXPORT already takes care of the symbol visibility, e.g.:
extern "C" NP_EXPORT(NPError) NP_GetEntryPoints(NPPluginFuncs* pFuncs);
That only works for Unixes though, so for GCC on Windows you'll have to set the visibilities yourself.
On Windows/VC++ you additionally have to specify the exports in a .def file as mentioned:
NP_GetEntryPoints #1
NP_Initialize #2
NP_Shutdown #3