Thread: DLL: Port Issue from VS6 to VS2010

  1. #1
    Registered User
    Join Date
    Aug 2008
    Posts
    12

    DLL: Port Issue from VS6 to VS2010

    Greetings Experts!

    I have been banging my head against the wall for three days with an issue and no amount of googling (days worth!) has yet to turn up an answer.

    A vendor tool that I use exposes its API via some C static libraries (.lib).

    I have a DLL written in VS6 wherein I expose functions I have written that leverage some of these libraries functions. I export these functions using the stdcall convention. It builds and works fine.

    I was attempting to migrate to VS2010 Express, but here's where I'm stuck:

    • If I build a console executable out of the same VS6 code described above, everything compiles and works fine.
    • If I build a cdecl DLL out of the same VS6 code described above, it compiles without errors.
    • If I build a stdcall DLL out of the same VS6 code described above, I get linker errors for any function from the vendor API library saying: "error LNK2019: unresolved external symbol _<vendor_function>@N"


    I'm at a loss as to why I can easily build an stdcall DLL with VC6 but cannot do so with the same code in VS2010.

    I would be grateful for smarter people to kick some ideas around with.

    Thanks!!

    Mike

  2. #2
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    So you have vender static .lib's (and headers) but no source, correct?

    >> I export these functions using the stdcall convention.
    Did you create wrapper functions with the appropriate calling convention? Or did you modify the vender's header file to try and force the calling convention you wanted?

    gg

  3. #3
    Registered User
    Join Date
    Aug 2008
    Posts
    12
    Quote Originally Posted by Codeplug View Post
    So you have vender static .lib's (and headers) but no source, correct?
    Correct.

    Did you create wrapper functions with the appropriate calling convention? Or did you modify the vender's header file to try and force the calling convention you wanted?
    Yes, that's basically what I'm doing. I created functions with the correct calling convention and the API functions are then called inside my wrapper function.

    This approach works fine with VS6. But with VS2010, the linker acts like it is applying the calling convention to the whole API and this is mangling the names?

  4. #4
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    So you haven't modified the vendor's header, and you're wrapper functions are using a different function name than the vendors.

    >> _<vendor_function>@N
    This is the format for extern "C"/__stdcall, linkage/calling-convention.

    In the vendor's header file, are the functions declared as __stdcall (or WINAPI)?
    If not, are you using the /Gz compiler option? (Properties -> C/C++ -> Advanced -> Calling Convention)

    gg

  5. #5
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Sounds like an extern "C" problem where the names are getting mangled and thus not exporting correctly.

    I'm assuming you are statically linking with the vendor library and clients dynamically link to your DLL to interface with the vendor library.

    Make sure you are using __declspec(export) and __declspec(import) correctly.
    Make sure that if you are using a C++ compiler your functions are declared using extern "C".

  6. #6
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    If you change the calling convention via compiler switch, the consumers of the DLL will have no way of knowing that. You need to indicate the precise calling convention in the header file that the consumer will be using. Remember that the DEFAULT in Visual Studio is __cdecl not __stdcall, so if you don't have __stdcall in the prototypes, it's not going to automatically work when somebody tries to link with your DLL and they have not also selected __stdcall.

    It's not really good practice to use the compiler switch to select the calling convention. If you want __stdcall, say __stdcall explicitly. Don't fiddle with switches.

    Code:
    // MyDll.h
    
    extern "C" void __stdcall Foo(int a, int b);
    
    // MyDll.cpp
    
    #include "MyDll.h"
    
    void Foo(int a, int b)
    {
    }
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  7. #7
    Registered User
    Join Date
    Aug 2008
    Posts
    12
    Sorry for the delayed response. I got hit with a truck load of support cases and am just digging my way out!

    Quote Originally Posted by Codeplug View Post
    So you haven't modified the vendor's header, and you're wrapper functions are using a different function name than the vendors.
    Correct.

    In the vendor's header file, are the functions declared as __stdcall (or WINAPI)?
    No, there are no calling conventions in the vendor's header files.

    If not, are you using the /Gz compiler option? (Properties -> C/C++ -> Advanced -> Calling Convention)
    Yes, I have set this as you describe.

    Just to reiterate -- this already works with VSC++6.0.

    Someone suggested there might be a pragma statement to get it to stop mangling the linked library functions, but I have yet to trip across anything.

  8. #8
    Registered User
    Join Date
    Aug 2008
    Posts
    12
    Quote Originally Posted by VirtualAce View Post
    I'm assuming you are statically linking with the vendor library and clients dynamically link to your DLL to interface with the vendor library.
    Correct.

    Make sure you are using __declspec(export) and __declspec(import) correctly.
    Make sure that if you are using a C++ compiler your functions are declared using extern "C".
    I've tried every convolution of export/import, extern "C", etc I could think of. I can get it to compile with __cdecl and I can get the exact same function to work if compiled into an EXE, but I can get __stdcall to work to save my life.

  9. #9
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    The real source of this problem is that although the vendor's functions are __cdecl, they are not declared as such in their header files. When you switch the compiler to use __stdcall by default, it will assume that the vendor's functions are also __stdcall because of the lack of an explicit __cdecl. This simply isn't going to work! You need to either change the vendor's header files to have __cdecl on the prototypes (horrible) or manually apply __stdcall to each of your functions, and switch the compiler's calling convention back to __cdecl.

    It was the vendor who committed the mistake by not specifying their calling convention explicitly. The way this is normally done is like so:

    Code:
    // VendorAPI.h
    
    #if (compiling with Visual Studio)
    #define VENDORAPI __cdecl
    #else
    #define VENDORAPI /*nothing*/
    #endif
    
    void VENDORAPI VendorFunction1();
    void VENDORAPI VendorFunction2();
    It's the vendor's fault. Now your life is pain. You ought to complain to them, really.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  10. #10
    Registered User
    Join Date
    Aug 2008
    Posts
    12
    Here is a small test bit of code using one simple alert box from the static libs. Perhaps you can spot what I'm doing wrong. At least we can have some code as a basis of further discussion --

    Code:
    ========================
    first.h
    ========================
    #define DONT_REDEFINE
    
    #include <windows.h>
    Code:
    ========================
    cdll.h
    ========================
    
    #define DONT_REDEFINE
    
    #define DLL extern "C" __declspec(dllexport)
    #define DLL_C extern __declspec(dllexport)
    #define DLL_IN extern "C" __declspec(dllimport)
    #define CALLCONV __stdcall
    //#define CALLCONV __cdecl
    
    #include "fapi.h"
    #include "fdetypes.h"
    
    // API function for alert from fapi.h
    // It is in a block of code that also has the requisite 
    // #if define __cplusplus extern "C" preprocessor.
    
    extern IntT F_ApiAlert FARGS((ConStringT message, IntT type));
    
    //exported function
    int CALLCONV StartAPI(int);
    Code:
    ========================
    startAPI
    ========================
    // startapi.cpp : Used to connect to the API (once FM is started).
    
    #include "first.h"
    #include "c_dll.h"
    
    int CALLCONV StartAPI(int init)
    {
    	IntT status = init;
    	ConStringT s = "Greetings from inside StartAPI";
    	
    	F_ApiAlert(greeting, FF_ALERT_CONTINUE_NOTE);
    
    	return status;
    
    }
    Code:
    ========================
    cdll.def
    ========================
    
    LIBRARY c_dll
    
    EXPORTS
    	StartAPI @1
    When compiler and above code set to __cdecl = compiles.
    When compiler and above code set to __stdcall = fails with:

    Code:
    StartAPI.cpp
      Generating Code...
    StartAPI.obj : error LNK2019: unresolved external symbol _F_ApiAlert@8 referenced in function "int __stdcall StartAPI(int)" (?StartAPI@@YGHH@Z)
    C:\Users\mikesmi.CISCO\Desktop\Local Working Folder\c_dll\c_dll\Debug\c_dll.dll : fatal error LNK1120: 1 unresolved externals

  11. #11
    Registered User
    Join Date
    Aug 2008
    Posts
    12
    Quote Originally Posted by brewbuck View Post
    The real source of this problem is that although the vendor's functions are __cdecl, they are not declared as such in their header files. When you switch the compiler to use __stdcall by default, it will assume that the vendor's functions are also __stdcall because of the lack of an explicit __cdecl. This simply isn't going to work! You need to either change the vendor's header files to have __cdecl on the prototypes (horrible) or manually apply __stdcall to each of your functions, and switch the compiler's calling convention back to __cdecl.
    This makes perfect sense. Thanks!

  12. #12
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    >> If not, are you using the /Gz compiler option?
    ...
    >> It's not really good practice to use the compiler switch to select the calling convention
    Exactly. Using /Gz causes these types of problems - which is why I asked if it was being used.

    I could of mentioned that to begin with

    gg

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Losing reference between dlls
    By g4j31a5 in forum Windows Programming
    Replies: 7
    Last Post: 05-19-2010, 02:28 AM
  2. Comodo Firewall Vulnerability (Port 0)
    By Mario F. in forum Tech Board
    Replies: 0
    Last Post: 11-11-2009, 08:56 AM
  3. FTP program
    By jakemott in forum Linux Programming
    Replies: 14
    Last Post: 10-06-2008, 01:58 PM
  4. DLL Load issue
    By George2 in forum Windows Programming
    Replies: 2
    Last Post: 09-01-2007, 03:42 PM
  5. brace-enclosed error
    By jdc18 in forum C++ Programming
    Replies: 53
    Last Post: 05-03-2007, 05:49 PM