LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

require function prototypes with external DLL

Solved!
Go to solution

Greetings,

 

in the CVI Build Options I have checked 'require function protoypes' because I consider this a useful safety measure. The project includes some 30 files which all work well except one which relies on functions provided by an external DLL.

 

Accordingly, these function calls are not prototyped and I receive the 'missing prototype' error.

 

I could imagine two solutions:

 

- find a way to protype external functions

- exclude one file from this build option

 

I would prefer the first version and doubt that the second option is possible.

 

So here is how I use the DLL:

 

a typical function call looks like this:     ( *ext_dll_Continue ) ( instrument );

 

where the address is obtained via   ext_dll_Continue = GetProcAddress ( ext_dll, "Continue" );

 

and ext_dll_Continue has been defined as

 

FARPROC ext_dll_Continue = NULL;

Assistance of how to prototype such a function call would be most welcome - Thanks!

 

Wolfgang 

 

 

0 Kudos
Message 1 of 11
(7,739 Views)

Wolfgang -

 

Doesn't this beg the question - how can you be using a function in a DLL if you don't know its prototype?  Just because you are dynamically loading it (and not using an export header file or import library) that doesn't mean you don't have to know the function prototype.   Whoever created the external DLL needs to tell you how to call the functions in it.

 

You indicated you sortof know how to call the Continue function:  If you in fact know the return type, and the function name, and the order, number, and type of paramters, then you can create your own prototype obviously.

 

You might try looking inside the DLL with a tool to see if you can glean info on the included functions.  Depends.exe will tell you the names of all the included functions, and can undecorate C++ functions that have been mangled to encode the order, number, and type of parameters.  But the DLL does not have (except maybe indirectly through C++ mangling) the order, number, and type of parameters visible in any way that can be inspected. 

 

Menchar

 

 

 

 

Message Edited by menchar on 12-15-2009 01:38 PM
0 Kudos
Message 2 of 11
(7,723 Views)

Dear Menchar,

 

Thank you for addressing this question!

 

My question probably is more basic than you might have thought: Indeed I do have an include file for the functions provided by the external DLL, e.g.

 

void APIENTRY Continue ( int System );

 

Now, in order to use this function in my program, first I get the address of this function using  ext_dll = LoadLibrary ( "xxx" ) and dll_Continue = GetProcAddress ( ext_dll, "Continue" );

 

Now I do have the address and know how to call the function ( ( *ext_dll_Continue ) ( instrument )  with instrument being an integer ) but the line

 

( *ext_dll_Continue ) ( instrument ) 

 

has not been prototyped yet and accordingly CVI may complain.

 

GetProcAddress returns a function pointer of type FARPROC, therefore I have initialized this pointer to FARPROC ext_dll_Continue = NULL;

 

I cannot use something like

 

void ext_dll_Continue ( int );

 

in analogy to the provided DLL include file because then operands of GetProcAddress won't match.

 

So I would rephrase my question: I do not know how to prototype this function call...

 

Thanks,

 

Wolfgang 

 

 

 

 

 
0 Kudos
Message 3 of 11
(7,709 Views)
Solution
Accepted by Wolfgang

I do this kind of thing all the time in CVI. I use the following general approach:

 

    typedef __declspec (dllexport) int (*pfint1) (int); // This definition matches the one in the .h file

 

    pfint1 Continue;                                    // This will be our reference to the external function

 

    Continue = (pfint1) GetProcAddress (dllHan, "Continue"); // dllHan presumed valid here

 

    val = Continue (param);                             // Call the function in the dll

 

This all works without warnings. (Prototypes required box ticked.) Obviously you can introduce different typdefs for the various different prototype patterns you plan to use.

 

JR

Message 4 of 11
(7,704 Views)

Thank you! I wasn't aware of the keyword __declspec(dllexport)

 

Wolfgang

0 Kudos
Message 5 of 11
(7,702 Views)

JR,

 

there is a small but basic question left - where do I put the typedef __declspec (dllexport) int (*pfint1) (int);?

 

    Warning: Import/export modifier in type definintion is ignored.

 

Thanks, Wolfgang

 

BTW, if NI reads this post: there is a typo in the warning message... >> definintion <<

 

 

0 Kudos
Message 6 of 11
(7,698 Views)

The __declspec (dllexport) component that I used was simply copied from the header file that my particular dll had. You should start with the definition in your header file and work from there. The key is to make the definitions the same and thus avoid compiler complaints!

 

JR

 

EDIT: forgot to answer the question! I usually put all my typedefs at the beginning of the c file, after the #includes and #defines but before any variables. In larger programs I put them in a separate header file.

Message Edited by jr_2005 on 12-16-2009 10:22 AM
0 Kudos
Message 7 of 11
(7,696 Views)

Hi Wolfgang,

 

an example for calling a DLL in CVI dynamically you can find here:

http://zone.ni.com/devzone/cda/epd/p/id/6151

Regards
DianaS
Message 8 of 11
(7,672 Views)

At the risk of belaboring this any further, I would just like to add a couple things.  The warning you are receiving Wolfgang is new to CVI 2009, and is an indication that the __declspec(dllexport) decoration is unnecessary in the typedef statement.  That decoration is used to mark the function as exported from the dll, however, has no impact in your module that is calling the function in the dll.  Thanks for pointing out the typo in our warning though - we'll get that fixed.  

 

You can prototype a function in the following three ways (you'll have to use GetProcAddress with the first two), considering a function with this prototype:

 

int __cdecl Continue (int);

 

As stated by JR, just minus the __declspec(dllexport):

 

typedef int (__cdecl* pfContinue)(int);
pfContinue Continue;

 

Without creating a typedef, thus creating a global (if declared globally) pointer to a function that takes an int and returns an int:

 

int (__cdecl* Continue)(int);

 

Or, if you have access to the lib of the dll, you can simply prototype it as extern, and then call it as usual, as the function will be picked up in the link:

 

extern int __cdecl Continue (int);

 

Finally - if you have a header file for the dll, you should try opening the header file in CVI, and then selecting the Options»Create DLL Import Source menu item.  You will then browse to the dll of interest, and all of this dynamic loading will be done for you in a new source file.  It can also be helpful to see how some more complex functions would be prototyped.

 

NickB

National Instruments 

Message 9 of 11
(7,666 Views)

ey, so many nice and helpful feedbacks, thanks a lot!

 

Wolfgang

0 Kudos
Message 10 of 11
(7,663 Views)