1. Chris Wallace
  2. PowerBuilder
  3. Thursday, 4 August 2022 21:12 PM UTC

I am using eclipse, not Visual Studio, to create a .dll file in C++. I have simplified the code down to this:

My header file tagsigs.h

#include <iostream>
#include "windows.h"

#ifndef TAGSIG_H_
#define TAGSIG_H_

extern "C" {
   int __deckspec(dllexport) WINAPI testFunc(void);
}

#endif

 

My tagsigs.cpp file

#include "tagsigs.h"
using namespace std;

int __deckspec(dllexport) WINAPI testFunc(void){
   return (26);
}

 

I compile as a shared library using MinGW. I get my .dll file using the Release, not Debug, build configuration. I tested my libTS.dll file using
dumpbin /EXPORTS libTS.dll

ordinal hint RVA Name
1 0 00001380 testFunc

This showed that the function name was not mangled and that it was exported.

I put libTS.dll into my PowerBuilder source directory where all the .pbl's and .dll's for the libraries I have created in Powerbuilder reside.

Here is my Global External Function declaration:
FUNCTION int testFunc() LIBRARY "libTS.dll" alias for "testFunc"

I did a Full Build.

But when I call testFunc from a powerbuilder script I get the error "Bad runtime function reference".
int xx
xx = testFunc()
MessageBox("Did It Work?", string(xx))

I have used global external functions before from the kernel32.dll and user32.dll libraries, but I've never provided my own .dll before. I don't know how to compile any differently for my .dll and I don't know how to declare or call any differently inside of PowerBuilder. Has anyone had success with shared library .dll files created through Eclipse and used inside PowerBuilder as external functions?

Chris Wallace Accepted Answer Pending Moderation
  1. Friday, 5 August 2022 23:00 PM UTC
  2. PowerBuilder
  3. # 1

So, I got my simple function compiled into a .dll file and successfully called the function from PowerBuilder. Here are the two things I was missing:

I am using the Mingw toolchain. I was using
x86_64-w64-mingw32.   Then I read that if you want to produce code for 32 bit binaries it is recommended to use:
i686-w64-mingw32. So I switched to the i686-w64-mingw32 toolchain. I made sure my PATH variable contained the path to the right bin directory (C:\msys64\mingw32\bin  instead of C:\msys64\mingw64\bin).

That didn't completely solve the problem. Turns out that I had to add the gcc flag -m32 to the compiler and to the linker as well. In eclipse that is under a project's Properties --> C/C++ Build --> Settings --> GCC C++ Compiler --> Miscellaneous    (Make sure that the Position Independent Code box is checked a.k.a. flag -fPIC)      AND      C/C++ Build --> Settings --> MinGW C++ Linker --> Miscellaneous 

Eclipse created a new shared library and PowerBuilder could talk to it. :)

In retrospect I could have noticed more details from the output of dumpbin. Dumpbin is a utility that lets you look inside a .dll file.
dumpbin /HEADERS nameofdll
clearly shows that my first attempts at creating a .dll were producing 64 bit binaries. PowerBuilder requires a 32 bit binary.
Running dumpbin /HEADERS on my final .dll file showed that it was a 32 bit binary. Hindsight is so clear!

Cheers and thanks for the replies / advice,
Chris

Comment
  1. John Fauss
  2. Saturday, 6 August 2022 02:22 AM UTC
Great news, Chris! I'm glad to hear you are over this hurdle. Thanks for the update!
  1. Helpful
There are no comments made yet.
Brad Mettee Accepted Answer Pending Moderation
  1. Friday, 5 August 2022 14:03 PM UTC
  2. PowerBuilder
  3. # 2

This has been working for us for a long while.

#include "stdio.h"
#indlude "windows.h"

ULONG WINAPI BitOR(ULONG a, ULONG b)
	{
#pragma EXPORT

	return(a | b);
	}

You only need the declaration in the header if other functions in the DLL will be calling the function internally. Otherwise, it's just overhead that's not going to get used during the compile.

The "#pragma EXPORT" tells the compiler to expose the the function in the DLL to the outside world. It removes the need to define the function in a .DEF file.

 

Comment
There are no comments made yet.
Chris Wallace Accepted Answer Pending Moderation
  1. Friday, 5 August 2022 00:35 AM UTC
  2. PowerBuilder
  3. # 3

Thanks Bruce and John for the replies!

I have tried explicitly using the __stdcall calling convention early on in this quest. It yielded the same error as WINAPI does. I moved to WINAPI because the Appeon Powerscript Reference Declarations page says, "... requires external functions to be exported using the WINAPI (__stdcall) format." And it gives an example.

LONG WINAPI myFunc() { ... };

So, I think I am using the expected calling convention.

I reduced my problem to the simplest function: no parameters and simply returning an int. I can't get it to work. Eventually I want to generate a GUID (globally unique identifier). I have written the C++ code to do this using the crossguid library. The code works when compiled to an .exe file. I need to get it into a .dll file compatible with PowerBuilder. But if I can't get the simplest function that just returns an int to work in a .dll file I am in trouble.

I am not familiar with Visual Basic in the least. I have, however, used Eclipse a lot (but in Java development). I believe I am exporting the function correctly by using __declspec(dllexport). (that was a typo in my question).

I believe I am keeping the name from being mangled by the cpp compiler with the use of 

extern "C" 

When I look inside the .dll file with the dumpbin utility it shows that the file is indeed being exported and that its name is not mangled.

I will certainly spend some time with the tutorial you mentioned. Thanks.

Chris

Comment
  1. John Fauss
  2. Friday, 5 August 2022 03:53 AM UTC
You're welcome! FYI, an "int" in C is a 32-bit signed integer, equivalent to a PB Long datatype. Different from a PB Integer datatype.
  1. Helpful
  1. Andreas Mykonios
  2. Friday, 5 August 2022 07:17 AM UTC
I wonder if this wouldn't be easier to accomplish in c# and using .NET DLL Importer. Just a thought...

Andreas.
  1. Helpful 2
  1. Miguel Leeuwe
  2. Friday, 5 August 2022 10:45 AM UTC
Totally agree with Andreas. So much easier and probably (almost) just as fast execution times.
  1. Helpful
There are no comments made yet.
Bruce Armstrong Accepted Answer Pending Moderation
  1. Friday, 5 August 2022 00:03 AM UTC
  2. PowerBuilder
  3. # 4

What John said, you need to specify the the DLL used the __STDCALL calling converntion.  With Visual Studio, the typical way would be to include a .DEF file.  That also allows you to call the function without the name mangling that C++ uses by default on the export.

 

Comment
There are no comments made yet.
John Fauss Accepted Answer Pending Moderation
  1. Thursday, 4 August 2022 23:40 PM UTC
  2. PowerBuilder
  3. # 5

Hi, Chris -

PB is designed to interface with Windows API functions. This is not to say that it cannot interface with non-Windows DLL's, only that a DLL must use the _stdcall calling convention and when passing arguments, you may only pass those WinAPI datatypes that have a PB equivalent.

I don't know what Eclipse is, so I cannot advise as to what you must do, or if it is possible. Possibly others in the Community can address that aspect.

If you're interested in more information about interfacing PB to Windows API (or equivalent type) functions in external DLL's, I've written a four-part tutorial that is available in the Community's Tech Articles section. Part 1 covers some basics I think you will find helpful. It includes a discussion of calling conventions:

   https://community.appeon.com/index.php/articles-blogs/tutorials-articles/2-powerbuilder/302-interfacing-pb-applications-with-the-windows-api-part-1

Part 4 of the tutorial includes tables that map WinAPI datatypes to PB datatypes and PB datatypes to WinAPI datatypes, which you may also find helpful:

   https://community.appeon.com/index.php/articles-blogs/tutorials-articles/2-powerbuilder/305-interfacing-pb-applications-with-the-windows-api-part-4

If you will be passing structure between PB and your DLL, you should carefully read the entire tutorial. I wrote this with people in your situation in mind, so please utilize it.

You did not state your overall goal for creating an external DLL that PB can interface to. However, if you're familiar with Visual Studio, I would suggest you use it to create your DLL, if that's feasible, since it can easily create WinAPI-compatible DLL's. Microsoft provides a free "community" edition.

Best regards, John

Comment
There are no comments made yet.
  • Page :
  • 1


There are no replies made for this question yet.
However, you are not allowed to reply to this question.