Cleware has asked for the wisdom of the Perl Monks concerning the following question:

Hello Perl Monks,

I tried to call a function from an external DLL which written in C++ but actually I got always Errors.

-The C++ header :
USBACCESS_API CUSBaccess * _stdcall FCWInitObject(void) + ; USBACCESS_API void _stdcall FCWUnInitObject(CUSBaccess +*obj) ; USBACCESS_API int _stdcall FCWOpenCleware(CUSBaccess *o +bj) ; USBACCESS_API int _stdcall FCWCloseCleware(CUSBaccess * +obj) ;
===================================================

-What I wrote:

#!usr/bin/perl use Win32::API; my $function1=Win32::API->Import( 'D:\Cleware\USBaccess.dll', 'int FCWInitObject()', ); my $return = $function1; Print($return);
===================================================

- What I got:

Undefined subroutine &main::Print called at script.pl line 8.

===================================================

Does anyone have any idea?

thanks in advance...

*I just new in Perl and have no idea before.

Replies are listed 'Best First'.
Re: Call a function from DLL
by Discipulus (Canon) on Jul 15, 2019 at 06:51 UTC
    Hello Cleware and welcome to the monstery and to the wonderful world of perl!

    I suspect nothing is wrong with your import: the error Undefined subroutine &main::Print refers to your statement Print($return); infact in perl you have print not Print and no parens are needed (or you'll get another error like print interpreted as function at.. ).

    Also do not never forget to use strict; use warnings; at the top of your perl programs.

    As per the Win32::API docs is good to check if the import was done (the two die in the below code):

    use Win32::API; $function = Win32::API::More->new( 'mydll', 'int sum_integers(int a, int b)' ); #### $^E is non-Cygwin only die "Error: $^E" if ! $function; #### or on Cygwin and non-Cygwin die "Error: ".(Win32::FormatMessage(Win32::GetLastError())) if ! $func +tion;

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

      Dear Discipulus,

      Thank you very much for offering to help,

      Actually the I have another question:

      the idea is , I want to call the function FCWIntiObject() and the return value must be as object.

      then I want to call the second function int FCWOpenCleware(object*) which it takes the return value from the previous function as an argument.

      could you help me?

      thanks in advance.

        Dealing with C++ (as opposed to C) function calls is something of a problem because the C++ compiler mangles function names to allow for function overloading and such C++ magic. Name mangling tends to be rather specific to individual C++ compilers as are calling conventions. You need some very specific information about the compiler you are using to even call the functions. Passing objects back and forth may either be easy (if you treat them as completely opaque objects) or potentially very complicated if you need to get involved in memory management and accessing parts of the object.

        Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
        Your best bet is probably to nest calls, as in
        $FCWOpenCleware->Call( $FCWIntiObject->Call() )


        holli

        You can lead your users to water, but alas, you cannot drown them.
Re: Call a function from DLL
by holli (Abbot) on Jul 15, 2019 at 08:35 UTC
    my $return = $function1;

    This doesn't work. $function1 is a Win32::API-Object. If you want to execute the actual function you need to use

    my $return = $function1->Call();


    holli

    You can lead your users to water, but alas, you cannot drown them.

      Thank you for your suggestion

      I just tried to use it but I got

      "Can't call method "Call" without a package or object reference at script.pl line 9."

      #!usr/bin/perl use strict; use warnings; use Win32::API; my $function=Win32::API->Import( 'D:\Cleware\USBaccess.dll', 'int FCWInitObject()', ); my $return = $function->Call();
        I just downloaded the DLL from here and the following code works for me now. I noticed there are 32 and 64-Bit versions of the DLL. Make sure you are using the one that matches your Perl (64 bit most likely, find out by perl -v).
        use strict; use warnings; use Win32::API; my $FCWInitObject = Win32::API->Import( 'D:\ENV\USBaccess.dll', 'int FCWInitObject()', ); die "Error: ".( Win32::FormatMessage( Win32::GetLastError() ) ) if !$F +CWInitObject; my $FCWOpenCleware = Win32::API->Import( 'D:\ENV\USBaccess.dll', 'int FCWOpenCleware(int a)', ); die "Error: ".( Win32::FormatMessage( Win32::GetLastError() ) ) if !$F +CWOpenCleware; my $pointer = $FCWInitObject->Call(); print "Pointer $pointer\n"; my $success = $FCWOpenCleware->Call( $pointer ); print "Success $success\n";
        Works in the sense that it outputs the following and does not throw an error:
        Pointer 8350080 Success 0
        That makes kinda sense since I don't have a device connected that could be "opened" but why does it then return a pointer in the first place?


        holli

        You can lead your users to water, but alas, you cannot drown them.
        That's because your call to Import doesn't work. Apparently it returns an empty string. You should check for errors as Discipulus said above.


        holli

        You can lead your users to water, but alas, you cannot drown them.