Decorations on C++ DLL function declarations really needed?

Frage Decorations on C++ DLL function declarations really needed?

  • Monday, December 11, 2006 3:55 PM
     
     

    I used the _stdcall decorators on the Visual C++ function definitions and declarations, but I couldn't get communication between the DLL and the Visual Basic application that was trying to call the functions of the DLL.. When I removed the declarations from the VC code almost completely (all but for the DLL_Main function definition), it worked fine.  Is there any disadvantage to using this approach?  Everyone I communicated with about it , including my boss and people that answered the MIcrosoft help posting that I put up, stated that you have to use those decorations.  Why is that?  It works fine without it so far.  My boss will be back from travel tommorrow.  I was hoping to find out today so I can make changes if necessary.  Thanks.

     

    George

All Replies

  • Monday, December 11, 2006 5:02 PM
    Moderator
     
     
    Well, it's not 100% required but most of Windows uses this calling convention and managed/native interop also defaults to this convention. It's strange that it works without stdcall. Rather that trying to get rid of stdcall you should post here the signature of C/C++ function and the way you declare it in Visual Basic maybe we can find out why it does not work.
  • Monday, December 11, 2006 6:53 PM
     
     

    Thanks Mike, here is the code:

    VB declaration:

    Private Declare Function summer Lib "C:\Program Files\Microsoft Visual Studio\MyProjects\geob\Debug\geob.dll" (ByVal num1&, ByVal num2&) As Long

     

    Cpp file:

    // geob.cpp : Defines the entry point for the DLL application.
    //

    #include "stdafx.h"
    #include "stdio.h"
    #include "geob.h"

    BOOL APIENTRY _stdcall DllMain( HANDLE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
          )
    {
        switch (ul_reason_for_call)
     {
      case DLL_PROCESS_ATTACH:
      case DLL_THREAD_ATTACH:
      case DLL_THREAD_DETACH:
      case DLL_PROCESS_DETACH:
       break;
        }
        return TRUE;
    }


    // This is an example of an exported variable
    GEOB_API int nGeob=0;
    GEOB_API long sum;
    GEOB_API long num1;
    GEOB_API long num2;
    // This is an example of an exported function.
    GEOB_API int fnGeob(void)
    {
     return 42;
    }

     


    // This is the constructor of a class that has been exported.
    // see geob.h for the class definition
    CGeob::CGeob()
    {
     return;
    }

    long _stdcall CGeob::summer(long num1, long num2)
    {
    long sum;
    printf("got there");
    sum = num1 + num2;
    return sum;
    }

     

     

    .h file:

    // The following ifdef block is the standard way of creating macros which make exporting
    // from a DLL simpler. All files within this DLL are compiled with the GEOB_EXPORTS
    // symbol defined on the command line. this symbol should not be defined on any project
    // that uses this DLL. This way any other project whose source files include this file see
    // GEOB_API functions as being imported from a DLL, wheras this DLL sees symbols
    // defined with this macro as being exported.
    #ifdef GEOB_EXPORTS
    #define GEOB_API __declspec(dllexport)
    #else
    #define GEOB_API __declspec(dllimport)
    #endif

    // This class is exported from the geob.dll
    class GEOB_API CGeob {
    public:
     CGeob(void);
    long sum;
    long num1;
    long num2;
    //CGeob(void);

    long _stdcall summer(long num1, long num2);

     // TODO: add your methods here.
    };

    extern GEOB_API int nGeob;
    extern GEOB_API long sum;
    extern GEOB_API long num1;
    extern GEOB_API long num2;

    GEOB_API int fnGeob(void);

    GEOB_API long _stdcall summer(long, long);

     

  • Monday, December 11, 2006 7:16 PM
    Moderator
     
     

    Just a small common mistake . You are using long in C/C++ and long in VB. The problem is that long in C/C++ is 32 bit and long in VB (and other .NET languages like C#) is 64 bit.

    Depending on your need you must do one of the following:

    1) use Integer in VB if you need 32 bit values

    Private Declare Function summer Lib "C:\Program Files\Microsoft Visual Studio\MyProjects\geob\Debug\geob.dll" (ByVal num1%, ByVal num2%) As Integer

    2) use long long instead of long in C/C++ if you need 64 bit values

    GEOB_API long long _stdcall summer(long long, long long);

     

    Not matching the size of the parameters results in an unbalanced stack when using stdcall but "works" with cdecl (you'll most probably get strange values for the function parameters and return value)

  • Monday, December 11, 2006 7:40 PM
     
     

    Thanks for the attempt Mike, but I'm still not there yet.  The DLL won't compile with the long long type definitions and I tried just changing th VB declaration, also, but it still gave me the same error.

     

    Any more thoughts?

     

    George

  • Monday, December 11, 2006 7:44 PM
     
     

    Your code does not compile.

    geob.cpp

    First

    long _stdcall CGeob::summer(long num1, long num2) //Its a CGeob class member.
    {
    long sum;
    printf("got there");
    sum = num1 + num2;
    return sum;
    }

    Second,

    // This class is exported from the geob.dll
    class GEOB_API CGeob {
    public:
     CGeob(void);
    long sum;
    long num1;
    long num2;
    //CGeob(void);

    long _stdcall summer(long num1, long num2); //this member cannot be accessed from VB

     // TODO: add your methods here.
    };

    GEOB_API long _stdcall summer(long, long); //Only this can be accessed.

     

    Private Declare Function summer Lib "geob.dll" (ByVal num1 As Integer, ByVal num2 As Integer) As Integer

    This is mine diffenition of summer function in VB.

     

  • Monday, December 11, 2006 7:52 PM
     
     

    So mine code is

    Module Module1
        Private Declare Function summer Lib "geob.dll" (ByVal num1 As Integer, ByVal num2 As Integer) As Integer

        Sub Main()
            Dim s As Integer
            s = summer(1, 2)
            Console.Write(": ")
            Console.WriteLine(s)
            Console.ReadLine()
        End Sub

    End Module

    geob.h

    // The following ifdef block is the standard way of creating macros which make exporting
    // from a DLL simpler. All files within this DLL are compiled with the GEOB_EXPORTS
    // symbol defined on the command line. this symbol should not be defined on any project
    // that uses this DLL. This way any other project whose source files include this file see
    // GEOB_API functions as being imported from a DLL, wheras this DLL sees symbols
    // defined with this macro as being exported.
    #ifdef GEOB_EXPORTS
    #define GEOB_API __declspec(dllexport)
    #else
    #define GEOB_API __declspec(dllimport)
    #endif

    // This class is exported from the geob.dll
    class GEOB_API CGeob {
    public:
     CGeob(void);
    long sum;
    long num1;
    long num2;
    //CGeob(void);

    long _stdcall summer(long num1, long num2);

     // TODO: add your methods here.
    };

    extern GEOB_API int nGeob;
    extern GEOB_API long sum;
    extern GEOB_API long num1;
    extern GEOB_API long num2;

    GEOB_API int fnGeob(void);

    extern "C" GEOB_API long _stdcall summer(long, long);

    geob.cpp

     

    // geob.cpp : Defines the entry point for the DLL application.
    //

    #include "stdafx.h"
    #include "stdio.h"
    #include "geob.h"

    BOOL APIENTRY _stdcall DllMain( HANDLE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
          )
    {
        switch (ul_reason_for_call)
     {
      case DLL_PROCESS_ATTACH:
      case DLL_THREAD_ATTACH:
      case DLL_THREAD_DETACH:
      case DLL_PROCESS_DETACH:
       break;
        }
        return TRUE;
    }


    // This is an example of an exported variable
    GEOB_API int nGeob=0;
    GEOB_API long sum;
    GEOB_API long num1;
    GEOB_API long num2;
    // This is an example of an exported function.
    GEOB_API int fnGeob(void)
    {
     return 42;
    }

     


    // This is the constructor of a class that has been exported.
    // see geob.h for the class definition
    CGeob::CGeob()
    {
     return;
    }

    long _stdcall /*CGeob::*/summer(long num1, long num2)
    {
     long sum;
     printf("got there");
     sum = num1 + num2;
     return sum;
    }

     

    geob.def - requried, otherwise entry point not found

     

    LIBRARY "geob"
    EXPORTS
     summer

    Output:

    got there: 3

     

  • Monday, December 11, 2006 7:59 PM
     
     

    Thanks,

    I got to compile but I get the same error when I try running the VB function, even when I use the declaration that you recommended.  Any more thoughts?

  • Monday, December 11, 2006 8:12 PM
     
     

    Thanks Aleksandr,

     

    I tried the code you sent, and it does compile but it gives me the same error, even with the declaration you sent.  I am open to any further ideas.  Thanks for the effort.

     

    George

  • Monday, December 11, 2006 8:19 PM
     
     

    Can you send:

    IDE version,

    error in VB.

    Did you add a .def file?

    Show me options of C++ - compiler and C++ - linker command line.

     

  • Monday, December 11, 2006 8:20 PM
     
     
    And show your result files. Both for VB and C++.
  • Monday, December 11, 2006 9:04 PM
     
     

    Aleksandr,

     

    I'm not sure what you mean by the IDE file and the result files and the options of the compiler and linker command line.  Do you mean you want to see the errors that I get?  The error I get in VB is "XL2000 Bad DLL Calling convention".  Does that shed any light on the situation?  Maybe if you explain what you mean by the other items I can send more info.

     

    Thanks,

     

    George

  • Monday, December 11, 2006 10:03 PM
     
     

    Did you add a .def file to your C++ project?

    How do you compile your C++ project?

  • Monday, December 11, 2006 10:27 PM
     
     

    Unfortuntly I cannot check it under XL2000,

    But my code works under XL2003.

    Private Declare Function summer Lib "c:\Documents and Settings\buz.HQ\Desktop\geob.dll" (ByVal num1 As Integer, ByVal num2 As Integer) As Integer

    Sub Main()
        Dim s As Integer
        s = summer(1, 2)
        ActiveSheet.Range("A1").Value = s
    End Sub

    And cell A1 containes 3.

  • Tuesday, December 12, 2006 1:54 PM
     
     
    yes, I added a def file.  I compiled the STDAX file first, then the cpp file then built the dll from the cpp file.
  • Tuesday, December 12, 2006 1:57 PM
     
     
    Does your dll source code use the _stdcall decorations or any other decorations to make it work with later versions of C++?  Mine seems to work well without it, which is why I am wondering if it's necessary.
  • Tuesday, December 12, 2006 2:14 PM
     
     

    Mine sources in that post. It uses _stdcall. Its very strange but I could not compile your code at all, without correction.

    See my comments above.

    How did you check with othe calling converstion I don't know.

    In VS2005 and XL 2003. It doesn't work without _stdcall.

     

  • Tuesday, December 12, 2006 4:38 PM
     
     

    I can't get your code to compile either.  Mine works as long as I don't add _stdcall to the function definition or declaration.  I'm not sure why.  Maybe it is due to the version of microsoft visual studio, ot the operating system that I am using.  Thanks for trying anyway.  My boss didn't come in today.  Maybe he will be satisfied with it, the way it is.

     

    George