CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 11 of 11
  1. #1
    Join Date
    Apr 1999
    Location
    VA BEACH
    Posts
    467

    DLL Calling conventions

    I have a DLL that will be used by Visual Basic and Visual C++.
    The dll is written in C++ and does not have MFC support.
    What would be the best ( in terms of easiest to implement for both platforms )
    calling convention to use. Currently I have no problems running in C++ using _cdecl calling convention but I keep getting Bad dll calling convention errors in VB.

    thanks


  2. #2
    Join Date
    Apr 1999
    Posts
    27,449

    Re: DLL Calling conventions

    You must use the __stdcall convention. This is the convention used by VB, Delphi, Powerbuilder, etc. and 99% of all the Windows API functions. If you need any other info concerning non-MFC DLL's used in other languages, let me know and I can help.

    Regards,

    Paul McKenzie


  3. #3
    Join Date
    Apr 1999
    Location
    VA BEACH
    Posts
    467

    Re: DLL Calling conventions

    If you have any idea on this I could use help most definately. How can I convert this function declaration into a STDAPI call.

    extern "C" __declspec( dllexport ) bool GetStringFromRegistry( long lHKey, LPCTSTR lpszKeyName, LPCTSTR lpszKeyVal, LPSTR lpVal, ULONG& lSize);



    I need to make sure that the name is not mangled and I don't really want to maintain a .def file if it isn't neccessary.

    thanks for the help


    Jim Hewitt
    Software Developer
    Liberty Tax Service
    www.LibertyTax.com

  4. #4
    Join Date
    Apr 1999
    Posts
    27,449

    Re: DLL Calling conventions

    There are 3 issues in the one line you have (believe it or not).

    1) Don't use references, use pointers (the last parameter lSize). VB and other languages do not know what a reference is. This even includes 'C'. The reference syntax is solely used for C++. If you take a look at the Windows API functions, none of them use the reference syntax. Also I would use BOOL instead of bool. The bottom line is that you are trying to make your function as "Windows API-like" as possible. Any deviation from this leads to more trouble than it's worth.

    2) All you need to make this callable in VB is to add the __stdcall to the definition. I usually use a typedef to simplify things:

    // In "myheader.h"
    #ifdef BUILDDLL
    #define FUNCDEF __declspec( dllexport ) __stdcall
    #else
    #define FUNCDEF __stdcall
    #endif
    //..
    #ifdef __cplusplus
    extern "C"
    #endif
    BOOL FUNCDEF GetStringFromRegistry( long lHKey, LPCTSTR lpszKeyName, LPCTSTR lpszKeyVal,
    LPSTR lpVal, ULONG* plSize);
    //.. Other exported functions
    //..
    #ifdef __cplusplus
    }
    #endif
    ..
    // Now in your implementation in the DLL (some .CPP file)
    #include <myheader.h>
    BOOL FUNCDEF GetStringFromRegistry( long lHKey, LPCTSTR lpszKeyName, LPCTSTR lpszKeyVal,
    LPSTR lpVal, ULONG* plSize)
    {
    //.. whatever:
    }



    Now you can use the same header in your C++ (or C) application and DLL, without having to change the __declspec. If you're building the DLL, just define BUILDLL in your compile options.

    3) If you want to have clean function names, you have no choice but to use the .DEF file. If you can live with adding the "@x" (where "x" is the number of bytes in the parameter list) to the end of your VB functions, then you don't need a DEF file. The reason why I use a DEF file is that a VB programmer reads the same documentation for the function as the C++ programmer. Instead of confusing the matter and giving two sets of names (one with the "@" and without), the documentation is consistent. Also, you may get lucky and a Powerbuilder user might want to use your library. A .DEF file is a little more that you have to keep track of, but it's worth it.

    You can also use the "Alias" keyword in VB and alias the "@" to a clean function name, but it's up to you how you want to do this.

    Regards,

    Paul McKenzie


  5. #5
    Join Date
    Apr 1999
    Location
    VA BEACH
    Posts
    467

    Re: DLL Calling conventions

    First Let me say thank you for all your help; you definately helped me clear up some confusion on this.
    One more question I hope.
    How do I use a .def file?
    I edit with a text editor, input the names I want
    for my functions then their ordinal value ( is this arbitrary or does it matter? ). How does the linker/VB etc... get this info? Do I need to distribute the .def file?

    thanks again.



    Jim Hewitt
    Software Developer
    Liberty Tax Service
    www.LibertyTax.com

  6. #6
    Join Date
    Apr 1999
    Posts
    27,449

    Re: DLL Calling conventions

    The .DEF file is added to your DLL project, just like you would add a .CPP file. Do a rebuild of your DLL, and you're done. You don't need the .DEF file for any other purpose except when you are building the DLL.

    In the on-line help, there are some samples of a DEF file. It is nothing more than a text file with library information (name, load types, exported functions, etc.). I'll just concentrate on the exported functions: In the .DEF file, you specify your DLL functions like this:

    EXPORTS
    DLLFunc @2
    DLLFunc2 @3
    (Possibly more exports)



    This attaches an ordinal to each of your function names, as well as gives you clean names. If you want fixed ordinals, you must use a .DEF file. For languages or masochists who call DLL functions by ordinal, that's how you guarantee that a function has a specific ordinal for those programmers. If you didn't use a DEF file, Windows assigns the ordinals and you don't have any control over the numbers that it assigns, so those few who call by ordinal have to change their code if you rebuild your DLL (the moral of the story is "don't call by ordinal"!).

    I didn't use the ordinal @1 because of habit from 16-bit DLLs (the @1 ordinal was used for the WEP() function in 16-bit DLL's)

    Remember to add your exported name to the .DEF file each time you create a new exported function. I don't think VC++ warns you if you forgot to add an exported function to the .DEF file. One way to determine that everything was built correctly is to use the "Quick View" option of Windows Explorer. You right click on your DLL file in Windows Explorer, and depending on your version of Windows, a "Quick View" option should appear in the menu. If you choose this, a program opens with an inside look at the DLL. Here you will be able to see the exported functions, the ordinals, etc. If you exported the names correctly, you should see clean names with the correct ordinals. If you forgot to add a function to the .DEF file, the Quick View will show the exported function, but with the "@" decoration and a really strange ordinal number.

    I hope this has helped.

    Regards,

    Paul McKenzie


  7. #7
    Join Date
    Apr 1999
    Location
    VA BEACH
    Posts
    467

    Re: DLL Calling conventions

    I hate to keep bugging you but I have one more question for you. Thanks a lot by the way.

    I can grab functions out of my dll without a problem running in debug mode and calling theh function through a dummy program. When I run the dummy program by itself the program seems like it is having a problem loading the dll and finding the function. Do you have any idea why something like this would happen? thanks again.



    Jim Hewitt
    Software Developer
    Liberty Tax Service
    www.LibertyTax.com

  8. #8
    Join Date
    Apr 1999
    Posts
    27,449

    Re: DLL Calling conventions

    Is the release version of the program in a different directory than the debug version? Usually these problems are caused by the DLL being in the wrong path, or the DLL relies on other DLLs that are located in the wrong path.

    Regards,

    Paul McKenzie


  9. #9
    Join Date
    Apr 1999
    Location
    VA BEACH
    Posts
    467

    Re: DLL Calling conventions

    The problem seems to be that one of my API calls works in Debug build of my DLL and it Fails in the Release build.
    here is the code for it

    BOOL FUNCDEF GetStringFromRegistry( long lHKey, LPCTSTR lpszKeyName, LPCTSTR lpszKeyVal, LPSTR lpVal, ULONG lSize)
    {
    HKEY hOpenKey;//store open key value in here
    OpenRegistryKey( lHKey, lpszKeyName, &hOpenKey );

    UCHAR* lpuStr = new UCHAR[lSize];//to copy value into
    ULONG* pSize = new ULONG();//size of value
    ULONG lType = REG_SZ;//type of value

    if( RegQueryValueEx( hOpenKey, lpszKeyVal, NULL, &lType, lpuStr, pSize ) != ERROR_SUCCESS )
    {
    RegCloseKey( hOpenKey );
    delete [] lpuStr;
    delete pSize;
    return false;
    }
    RegCloseKey(hOpenKey);//close the key we opened
    if( *pSize > lSize )
    {
    delete [] lpuStr;
    delete pSize;
    return false;
    }
    strncpy( lpVal, (char*) lpuStr, (*pSize) +1 );
    delete [] lpuStr;
    delete pSize;
    return true;
    }




    I have put this same code into a regular appwizard progject and it works in both debug and release modes. Could it be possible I need to set some specific compiliar options for Release mode that I didn't need to set for Debug?
    Again thanks for all your help.



    Jim Hewitt
    Software Developer
    Liberty Tax Service
    www.LibertyTax.com

  10. #10
    Join Date
    Apr 1999
    Posts
    27,449

    Re: DLL Calling conventions

    It looks OK to me. How does it fail in the release build? One thing that you could do is generate the debug symbols for a release build and use the debugger to find the problem (go to the Project Settings for the release build of the DLL, choose C++ and choose "Program Database" for the Debug Info. Then go to the Link Tab and select "Generate Debug Info". Rebuild the DLL).

    Also, one thing that you didn't need to do was the extra "new ULONG":

    ULONG ThisSize; // instead of ULONG *pSize;
    //..
    // Use the address of the ULONG.
    if( RegQueryValueEx( hOpenKey, lpszKeyVal, NULL, &lType, lpuStr, &ThisSize ) != ERROR_SUCCESS )
    //...



    Then there is no need to do the extra "delete pSize", since all you needed was the address of a ULONG.

    Regards,

    Paul McKenzie


  11. #11
    Join Date
    Apr 1999
    Location
    VA BEACH
    Posts
    467

    Re: DLL Calling conventions

    Well I think I got it fixed. Apparently the non-initilization of pSize to a number caused a problem. I had already changed pSize to just a regular var not a pointer, and the initilization of it to the lSize param coming in aparantly fixed this problem, though I do not know why.
    thanks for you help



    Jim Hewitt
    Software Developer
    Liberty Tax Service
    www.LibertyTax.com

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured