Click here to Skip to main content
6,633,937 members and growing! (21,722 online)
Email Password   helpLost your password?
General Programming » DLLs & Assemblies » Beginners     Beginner License: The Code Project Open License (CPOL)

Step by Step: Calling C++ DLLs from VC++ and VB - Part 2

By Hans Dietrich

This series of articles is a step-by-step guide to constructing C++ DLLs that include C++ functions and C++ classes, and then calling the DLL functions and classes from VC++ and VB programs.
VC6, VB 6Win2K, WinXP, Win2003, Dev
Version:2 (See All)
Posted:28 Feb 2004
Updated:2 Oct 2009
Views:216,183
Bookmarked:95 times
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
47 votes for this article.
Popularity: 7.65 Rating: 4.57 out of 5

1
2 votes, 4.3%
2

3
3 votes, 6.4%
4
42 votes, 89.4%
5

Introduction

This series of articles discusses four common situations when working with DLLs:

Part 1 Calling a DLL C++ function from a VC++ application
Calling a DLL C++ class from a VC++ application
Part 2 Calling a DLL C++ function from a VB application
Part 3 Calling a DLL C++ class from a VB application
Part 4 Loading a C++ DLL dynamically from a VC++ application

Calling a DLL C++ function from a VB application

In Part 1, I talked about creating C++ DLLs and then using those DLLs in VC++ applications. Sometimes you would like to call a function in a C++ DLL from a VB application.

Step 1

Here is the code for DLL2, which is taken from Part 1's DLL1:

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

#include "stdafx.h"
#define DLL2_EXPORTS
#include "DLL2.h"

BOOL APIENTRY 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;
}


///////////////////////////////////////////////////////////////////////////////
// GetCycleCount - private function of DLL2.cpp.  The static keyword ensures
//                 that this function name is not visible outside DLL2.cpp.
static inline unsigned __int64 GetCycleCount()
{
    unsigned int timehi, timelo;

    // Use the assembly instruction rdtsc, which gets the current
    // cycle count (since the process started) and puts it in edx:eax.
    __asm
    {
        rdtsc
        mov timehi, edx;
        mov timelo, eax;
    }

    return ((unsigned __int64)timehi << 32) + (unsigned __int64)timelo;
}


///////////////////////////////////////////////////////////////////////////////
// Example of an exported function
///////////////////////////////////////////////////////////////////////////////
// GetCpuSpeed - returns CPU speed in MHz;  for example, ~2193 will be 
//               returned for a 2.2 GHz CPU.
DLL2_API int __stdcall GetCpuSpeed()
{
    const unsigned __int64 ui64StartCycle = GetCycleCount();
    Sleep(1000);
    return static_cast((GetCycleCount() - ui64StartCycle) / 1000000);
}

DLL2.h looks like:

#ifndef DLL2_H
#define DLL2_H

// The following ifdef block is the standard way of creating macros which 
// make exporting from a DLL simpler.  The DLL2.cpp file is compiled with 
// the symbol DLL2_EXPORTS defined at the top of DLL2.cpp.  This symbol 
// should *not* be defined in any project that uses DLL2.  This way any 
// other project whose source files include DLL2.h will see DLL2_API defined 
// as __declspec(dllimport), whereas within DLL2.cpp, DLL2_API is defined as
// __declspec(dllexport).

#ifdef DLL2_EXPORTS
    #define DLL2_API __declspec(dllexport)
#else
    #define DLL2_API __declspec(dllimport)
#endif

///////////////////////////////////////////////////////////////////////////////
// This function is exported from the DLL2.dll
DLL2_API int __stdcall GetCpuSpeed();

#endif //DLL2_H

One difference between the code for DLL2 and the code for DLL1 is that GetCpuSpeed() is declared using __stdcall. This is required for any C/C++ function that you want to use with VB. Here is what MSDN says about the __stdcall calling convention:

Element Implementation
Argument-passing order Right to left.
Argument-passing convention By value, unless a pointer or reference type is passed.
Stack-maintenance responsibility Called function pops its own arguments from the stack.
Name-decoration convention An underscore (_) is prefixed to the name. The name is followed by the at sign (@) followed by the number of bytes (in decimal) in the argument list. Therefore, the function declared as int func( int a, double b ) is decorated as follows: _func@12
Case-translation convention None

Step 2

To test DLL2.dll, I use this VB code:

Private Declare Function GetCpuSpeed Lib "DLL2.dll" () As Integer
Private Declare Sub InitCommonControls Lib "comctl32.dll" ()

Private Sub Form_Initialize()
    InitCommonControls
    ChDir App.Path

End Sub

Private Sub Command1_Click()

    Dim nSpeed As Integer
    Dim s As String
    
    Screen.MousePointer = vbHourglass
    nSpeed = GetCpuSpeed()
    Screen.MousePointer = 0
    
    s = nSpeed
    
    Form1.Text1.Text = "GetCpuSpeed() returned " + s

End Sub

Private Sub Form_Load()

    Form1.Text1.Text = ""
    
End Sub

After copying DLL2.dll to the VB directory, I run VB2.exe and this is what I see:

When I click the button, I get this:

So I know that VB can't find the function GetCpuSpeed() in the DLL. To look at what VB is seeing, I use dumpbin /exports dll2.dll from the command line:

Microsoft (R) COFF Binary File Dumper Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

Dump of file dll2.dll

File Type: DLL

  Section contains the following exports for DLL2.dll

           0 characteristics
    403FE342 time date stamp Fri Feb 27 08:21:30 2004
        0.00 version
           1 ordinal base
           1 number of functions
           1 number of names

    ordinal hint RVA      name

          1    0 00001010 ?GetCpuSpeed@@YGHXZ

  Summary

        4000 .data
        1000 .rdata
        1000 .reloc
        4000 .text

This is what you would expect from VC++ - it has "decorated" the name GetCpuSpeed and exports the new mangled name ?GetCpuSpeed@@YGHXZ, which VB doesn't understand. What does this mean? Here is what MSDN says:

The Microsoft C++ compilers encode the names of symbols in C++ programs to include type information in the name. This is called "name decoration", or "name mangling". The purpose of this is to ensure type-safe linking. The C++ language allows function overloading where functions with the same name are only distinguished from one another by the data types of the arguments to the functions. Name decoration enables the linker to distinguish between different versions of overloaded functions because the names of the functions are encoded or decorated differently.

Step 3

To get back to the problem that VB is having, I need to tell VB that the name associated with export #1 is GetCpuSpeed, not the VC++ decorated name. There is a simple way to do this: create a DLL2.def file, which looks like this:

; DLL2.def - defines the exports for DLL2.dll

LIBRARY DLL2
DESCRIPTION 'A C++ dll that can be called from VB'

EXPORTS
    GetCpuSpeed

Now I recompile DLL2. To check what change has been made, I run dumpbin again:

Microsoft (R) COFF Binary File Dumper Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

Dump of file dll2.dll

File Type: DLL

  Section contains the following exports for DLL2.dll

           0 characteristics
    403F2B8D time date stamp Fri Feb 27 08:35:41 2004
        0.00 version
           1 ordinal base
           1 number of functions
           1 number of names

    ordinal hint RVA      name

          1    0 00001010 GetCpuSpeed

  Summary

        4000 .data
        1000 .rdata
        1000 .reloc
        4000 .text

This shows that export #1 is now named GetCpuSpeed. So I copy the new Dll2.dll file to the VB directory, run the VB app, and click the button. This is what I get:

Success! I have a VB application calling a function that has been exported from a VC++ DLL. But what about VC++ applications? Can a VC++ application call the same DLL as a VB application?

Step 4

I copy the EXE code from Part 1, remove the code that tests the C++ class, compile it, and run it. Here is what I get when I press the button:

So I have one DLL that can be called by a VC++ application and a VB application. This was accomplished by use of a module definition (.DEF) file.

Step 5

Since the DLL now has a .DEF file, there is no need for the __declspec(dllexport) and __declspec(dllimport). I change DLL2.h to:

#ifndef DLL2_H
#define DLL2_H

///////////////////////////////////////////////////////////////////////////////
// This function is exported from the DLL2.dll
int __stdcall GetCpuSpeed();

#endif //DLL2_H

and also update DLL2.cpp.

Key Concepts

  • To avoid name-mangling problems and having to Alias function names in VB, use module definition (.DEF) files.
  • When using .DEF files, it is not necessary to use __declspec(dllexport) or __declspec(dllimport).
  • Use __stdcall for functions that are called by VB.
  • DLLs implemented with .DEF files can be called by both VC++ and VB programs (without needing to use Alias).

Demos

The EXE2.exe and VB2.exe demos test the GetCpuSpeed() function in DLL2.dll:

Revision History

Version 1.1 - 2009 October 3

  • Added string example to Part 2.

Version 1.0 - 2004 February 29

  • Initial public release

Usage

This software is released into the public domain. You are free to use it in any way you like, except that you may not sell this source code. If you modify it or extend it, please to consider posting new code here for everyone to share. This software is provided "as is" with no expressed or implied warranty. I accept no liability for any damage or loss of business that this software may cause.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Hans Dietrich


Member
I attended St. Michael's College of the University of Toronto, with the intention of becoming a priest. A friend in the University's Computer Science Department got me interested in programming, and I have been hooked ever since.

Recently, I have moved to Los Angeles where I am doing consulting and development work.
Occupation: Software Developer (Senior)
Company: Hans Dietrich Software
Location: United States United States

Other popular DLLs & Assemblies articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 24 of 24 (Total in Forum: 24) (Refresh)FirstPrevNext
GeneralCreate DLL in C and call from VB Pinmemberkarthickbabu_india1:05 2 Nov '07  
Questionhow can define function in .def file Pinmembermvnevis2:31 5 Jul '07  
GeneralCalling a C Builder DLL from a VB App Pinmemberluiyiperu6:04 19 Feb '07  
QuestionAnybody interested in VC++ Directory Utility ? Pinmemberavanish1236:48 1 Feb '07  
GeneralCalling C++ DLLs from Matlab Pinmembermaritkap23:34 5 Dec '06  
Questioncreating a DLL which holds info (array and parameters) for applications Pinmembershabya2:35 21 Apr '06  
Questionsome Extention dll questions? Pinmemberroseblood21:02 19 Apr '06  
Generalc++ globals behaviour Pinmemberjsep21:24 18 Feb '06  
GeneralKudos Pinmemberkshaff036:23 10 Jan '06  
GeneralLNK 4003 PinmemberAllwyn D'souza8:53 19 Sep '05  
GeneralProblem with calling a C++ DLL from VB Pinmembergjcsot9:19 5 Sep '05  
GeneralRe: Problem with calling a C++ DLL from VB Pinmembermanish rastogi3:03 26 Jun '08  
Generaldebugging c from vb Pinmemberdeodiaus15:59 10 May '05  
GeneralRe: debugging c from vb PinsussAnonymous6:58 3 Jun '05  
GeneralRe: debugging c from vb PinmemberCristian Amarie1:58 6 Jan '07  
GeneralUsing COMObject from Matlab to C# PinsussAnonymous12:06 30 Apr '05  
GeneralRe: Using COMObject from Matlab to C# PinmemberAsif Tamboli3:08 19 May '05  
GeneralBoth VB and C++ Friendly DLL Pinmemberjcapzz6:13 6 Apr '05  
GeneralVery Helpful but can you help me further? Pinmemberkezhu1:54 23 Mar '05  
GeneralNo help whatsoever Pinmembertwav18:01 30 May '04  
Generalreturn string from C++ DLL Pinmembersuphot inchaiya20:23 13 Apr '04  
GeneralRe: return string from C++ DLL PinmemberShrikant22:56 20 Apr '04  
GeneralRe: return string from C++ DLL PinsussAnonymous18:24 26 Jul '05  
GeneralOne Question. PinmemberMr.Prakash14:09 10 Mar '04  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 2 Oct 2009
Editor: Sean Ewington
Copyright 2004 by Hans Dietrich
Everything else Copyright © CodeProject, 1999-2009
Web21 | Advertise on the Code Project