1. jorge gonzalez
  2. PowerBuilder
  3. Sunday, 15 October 2023 14:32 PM UTC

The error message:

error r0042

Error: specifield argument type differs from required argument type at runtime in dll <dll name>

(invalid stack pointer on return from function call) at line 20
in open event of object w_genapp1_sheet1.

Environment:

PB 2022 R2 (Build 2819)

Windows 11 running in Parallels on a Apple Mac M1 processor.

Visual studio 2022 (arm 64).

 

Note. I build the dll as an x86 application

 

Problem:

I finally narrowed the problem down to me passing any parameter from a simple PB local external function call:

function long rettext( int text) library "testdllforpb.dll" alias for "rettext"

 

To this simple c++ dll:

extern "C" __declspec(dllexport) int rettext(int text);  // This comes from the header (h) file

// Here's the c++ dll code (cpp)

extern "C" int rettext(int text)

{

    return 3;

}

// Local external PB call:

function long rettext( int text) library "testdllforpb.dll" alias for "rettext"

 

I've tried __stdcall in the dll and PB does not like that at all. 

If I change the dll so it doesn't have any parameters it works in PB.

Note. I found this old article , which is the exact problem I am having:

"https://codeverge.com/forum/sybase.powerbuilder.general_calling-custom-c++-dll-s-in-power_1037457"

Unfortunately the links mentioned in the article no longer exist.

 

 

 

 

jorge gonzalez Accepted Answer Pending Moderation
  1. Monday, 16 October 2023 22:34 PM UTC
  2. PowerBuilder
  3. # 1

Here's my final solution to pass a string to a c++ dll from a PB app via a local external function call. If twcspeechdll's parm was defined as char * argv instead of LPCWSTR argv  I'd only get the first letter of the text I passed in when calling from the PB app.

Note. This dll calls the Windows speech functionality api so text passed into it is translated into speech on a computers speaker. The text passed in comes from a PB app.

 

PB local external function call:

function int twcspeechdll( string text) library "twcappealsspeechdll.dll" alias for "_twcspeechdll@4"

 

c++ Header file (H):

extern "C" __declspec(dllexport) int __stdcall twcspeechdll(LPCWSTR argv);

 

C++ Code file (cpp):

extern "C" int __stdcall twcspeechdll(LPCWSTR argv)

{

    ISpVoice* pVoice = NULL;

    string temp;

    string space = " ";

    LPCWSTR text;

    std::wstring stemp;

 

//======================

 

    if (FAILED(::CoInitialize(NULL)))

        return -1;

 

    stemp = argv;

   string lstr(stemp.begin(), stemp.end() );

 

// trimstring is a function I wrote to trim the passed in string

   trimString(lstr, space);

 

   if (lstr.length() <= 0)

       return -2;

 

   text = stemp.c_str() ;

 

   HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void**)&pVoice);

   if (SUCCEEDED(hr))

   {

       hr = pVoice->Speak(text, 0, NULL);

...

Comment
  1. jorge gonzalez
  2. Tuesday, 17 October 2023 12:49 PM UTC
This article would have really helped me but none of my searches turned it up. Thanks Arnd
  1. Helpful
  1. Roland Smith
  2. Tuesday, 17 October 2023 14:39 PM UTC
The W in LPCWSTR indicates Unicode strings. You have to remember that in PowerBuilder, string and char variables are Unicode (two bytes per character). In C++ a char is Ansi (one byte per character). An encoding mismatch is why you only got the first character. If your C++ DLL is Ansi, you must add ;Ansi to the Alias clause so that the PB Runtime will convert the between the two encodings.
  1. Helpful 1
There are no comments made yet.
Ronnie Po Accepted Answer Pending Moderation
  1. Monday, 16 October 2023 16:34 PM UTC
  2. PowerBuilder
  3. # 2

Hi Jorge,

I have an unrelated question regarding your development environment. Are you using the PB IDE successfully on Windows 11 ARM? (I assume yes, since you are using an M1 Mac.) I didn't think that was possible...

Environment:

PB 2022 R2 (Build 2819)

Windows 11 running in Parallels on a Apple Mac M1 processor.

Visual studio 2022 (arm 64)

 

Comment
  1. Ronnie Po
  2. Monday, 16 October 2023 17:34 PM UTC
Good to know. Thanks...
  1. Helpful
  1. jorge gonzalez
  2. Monday, 16 October 2023 17:41 PM UTC
The new Apple Mac M3 processors are coming out soon. I'd hold off on buying a new Mac until this processor comes out. Bye
  1. Helpful
  1. Ronnie Po
  2. Monday, 16 October 2023 18:16 PM UTC
Agreed. Thank you, Jorge.
  1. Helpful
There are no comments made yet.
Bruce Armstrong Accepted Answer Pending Moderation
  1. Monday, 16 October 2023 09:16 AM UTC
  2. PowerBuilder
  3. # 3

You can use a DEF file to prevent the name mangling on the exported functions

 

https://learn.microsoft.com/en-us/cpp/build/exporting-from-a-dll-using-def-files?view=msvc-170

Comment
  1. Miguel Leeuwe
  2. Monday, 16 October 2023 13:56 PM UTC
lol,

Hi John,

Yes, that's exactly the problem I have with C++.

I'm not sure, but I think that C# for anyone who knows C++ would be a piece of cake?

regards
  1. Helpful
  1. jorge gonzalez
  2. Monday, 16 October 2023 16:06 PM UTC
I found c++ app that will allow me to interface with the built in Windows speech api. My c++ skills are very rusty and I never called a c++ dll from Powerbuilder. That's what most of this was about. Now that my PB app can interface with the c++ dll I will create a new dll calling the speech api code. I need this code to run fast so will stick with the c++ dll. I actually found a c# app but it was too slow. The c++ app was almost instantaneous.
  1. Helpful
  1. Chris Pollach @Appeon
  2. Monday, 16 October 2023 16:21 PM UTC
Hi Jorge;

Kool!

That's the problem with C# ... It's a more bloated language that carries a significant DotNet overhead. This can also be a PIA to deploy as your client machines need the correct .Net runtime. Whereas C++ is super fast with no bloat. Just my $02. ;-)

Regards ... Chris
  1. Helpful 1
There are no comments made yet.
John Fauss Accepted Answer Pending Moderation
  1. Sunday, 15 October 2023 19:21 PM UTC
  2. PowerBuilder
  3. # 4

Hi, Jorge - 

An "int" data type in PB is a two-byte signed integer. An "int" in C/C++ is a four-byte signed integer.

Either change the PB data type to Long, or change the C/C++ data type to short.

Oh, and PB requires the use of the _stdcall calling convention.

    https://docs.appeon.com/pb2022/application_techniques/Using_external_functions.html

Best regards, John

Comment
  1. jorge gonzalez
  2. Monday, 16 October 2023 12:56 PM UTC
John I figured out how to pass a string from PB to the c++ app:



// Local external call function

function string rettext( string text) library "testdllforpb.dll" alias for "_rettext@4"



// C++ function



extern "C" char * __stdcall rettext(char* text)

{

//text = text * 199;

return (char*)text;

}
  1. Helpful
  1. Roland Smith
  2. Monday, 16 October 2023 13:36 PM UTC
In C++ a char variable is Ansi and PowerBuilder strings are Unicode. You'll have to add ;Ansi to the alias.
  1. Helpful
  1. Roland Smith
  2. Monday, 16 October 2023 13:49 PM UTC
I always declare my C++ functions like 'datatype WINAPI function_name ( args )' and then put the function names in a DEF file.

WINAPI is a macro that expands to __stdcall.
  1. Helpful 2
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.
We use cookies which are necessary for the proper functioning of our websites. We also use cookies to analyze our traffic, improve your experience and provide social media features. If you continue to use this site, you consent to our use of cookies.