Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

How to write a Super compact Super Fast C++ Dll for Visual Basic

0.00/5 (No votes)
3 Nov 2001 1  
Exporting functions for VB from a VC++ DLL using ATL

Introduction

Here in this project we will see how we can call a VC dll from VB. We will see how to use various VB Variables like byte, integer, long, single, double, string, currency. We will also see why to write in VC when VB is an native code compiler. Well sometimes when we need to call small fast routines C++ is best choice. But C++ has its own overhead. A typical Visual C++ dll not using MFC can be 40 KB or so (no msvcrt and mfc dll). For a small function this is a very big overhead. At least 75% is used by CRT (C run time).

I assume reader has comfortable knowledge with C++ and VB. No ATL/MFC knowledge is required.

Now we come to question. How to write super compact super fast DLL for VB. We will start with ATL. No! No COM!.

Why ATL?

ATL provides its own entry points for the DLL. ATL Entry point is fast and compact. And thats what we want. Secondly we will never call any CRT functions. We will always call Windows API functions to minimize the size and speed. Refer KB Article : Q99456 or see list below.

Eg. see below for string length. In c strlen but we can call lstrlen API function. see Here:

	void __stdcall ReverseString( BSTR a )
	{
		int i, iLen;
		BSTR b;
		LPSTR pA, pB;

	#ifdef _UNICODE		
		iLen = lstrlen( (LPCTSTR) a );
	#else
		iLen = lstrlen( (LPCSTR) a ); // wait for this

	#endif

// to use crt in place of api just call

//	_tcslen( (LPCTSTR) a);

	
	wow its so easy .

Benefits of Using ATL as a base for a DLL are

  1. It is compact.
  2. No CRT burden
  3. ATL Provides its own entry point so it is easy
  4. If we do not use ATL DLL then a normal DLL is two to three times big.

Now how to create ATL DLL? It is easy.

Follow these steps

  1. Select New Project from the file menu.
  2. Select ATL COM Wizard.
  3. I do not prefer CRT functions so here is what we see



  4. To use CRT select the "Support MFC" check box Like this


  5. Select "Allow merging of Proxy/Stub code"

ATL has many type of configurations but we are interested mainly in either win32 MIN dependency or win32 unicode min dependency. Note: Unicode is only for Windows NT/2000/XP and is not supported on Win 95/98/Me.

By using minimum dependency there is no or minimal dependency on any other dll.

If you have selected Use MFC then in properties select use MFC in static library. It will remove any dependency on MFC DLL's.

Now some small points for writing functions in C++ for use in VB.

  1. VB uses __stdcall so we will also use std calling convention.
  2. VB does not decorate names like C++ so we have to use extern "C"
  3. We have to export function names. __declspec(dllexport) is clumsy for VB. As it also decorate function name by using underscore. We will go with def file. Def file is easy. All we have to do is just enter a function name. For example if a function is like this
    extern "C" int __stdcall HelloVB( int a) {...}

    in the def file we have just write

    HelloVB

    and VB will recognize our function. If we have used declspec is could be _HelloVb

Here are VB types and their corresponding types in VC

In VB

In VC

Byte

unsinged char

Integer 

signed short

long

signed long

single

float

double 

double

currency

signed __int64

string

BSTR

So here we will start the DLL. We will use a function for each VB variable.

  1. First insert a C++ file in our project, then add the following code
  2. 	
    extern "c" BYTE __stdcall MakeTripByte( BYTE a, LPBYTE b )
    
    	{
    		*b = a + a;
    		return( *b + a );
    	}
    	
    extern "c" short __stdcall MakeTripInteger( short a, short  *b )
    	{
    		*b = a + a;
    		return( *b + a );
    	}
    	
    extern "c" LONG __stdcall MakeTripLong( long a, long *b )
    	{
    		*b = a + a;
    		return( *b + a );
    	}
    
    extern "c" float __stdcall MakeTripSingle( float a, float far * b )
    	{
    		*b = a + a;
    		return( *b + a );
    	}
    	
    extern "c" double __stdcall MakeTripDouble( double a, double far * b )
    	{
    		*b = a + a;
    		return( *b + a );
    	}
    extern "c" __int64 __stdcall MakeTripCurrency(__int64 a, __int64 *b)
    	{
    		*b = (a  + a) ;
    		return (*b + a);
    	}
    
    extern "c" void __stdcall ReverseString( BSTR a )
    	{
    		int i, iLen;
    		BSTR b;
    		LPSTR pA, pB;
    
    #ifdef _UNICODE		
    		iLen = lstrlen( (LPCTSTR) a );
    #else
    		iLen = lstrlen( (LPCSTR) a );
    #endif
    
    		b = SysAllocStringLen( NULL, iLen );
    		
    		pA = (LPSTR)a;
    		pB = (LPSTR)b + iLen -1;
    		
    		for ( i = 0; i < iLen; i++ )
    			*pB-- = *pA++;
    		
    		pA = (LPSTR)a;
    		pB = (LPSTR)b;
    		
    		for ( i = 0; i < iLen; i++ )
    			*pA++ = *pB++;
    		
    		SysFreeString( b );
    	}
    
    
  3. Save the file.

  4. Now select the file tab in the workspace. From there select Source files under name of your project. Then select a file with .def extension with name of project and in it add the following at the end.
    ReverseString		
    MakeTripByte			
    MakeTripDouble		
    MakeTripInteger		
    MakeTripLong		
    MakeTripSingle			
    MakeTripCurrency	
  5. Now select build ->set active configuration to Win32 release min size. Compile the DLL. Close VC.

  6. Now start vb

Before copy and pasting code lets see how we will declare our DLL functions in VB.

[Public | Private] Declare Function_name Lib "libname"  [([arglist])] [As type]

Public or Private defines scope of function. In forms it is private but in Module it is pub. generally. We will go with private.

Declare is used to tell vb we are importing a function from DLL.

Then follows name of the function. It is what we typed in our DLL. then follows lib with lib name in quotes. we have to specify the name of DLL in quotes. It is always better to specify full path. eg. c:\project\dll.dll.

Then follows the argument list. By default VB always passes arguments by reference. So we have to byref for pointer arguments and byval for normal arguments.

The last part determines what a function will return. Refer to the table above.

Now for out above C DLL function declaration will be like this in VB

'enter path for tlb .dll. IF no path given then it is assumed to be in the same folder

Private Declare Function MakeTripByte _
Lib "tvb.dll" ( _
    ByVal a As Byte, _
    ByRef b As Byte _
) As Byte

Private Declare Function MakeTripInteger _
Lib "tvb.dll" ( _
    ByVal a As Integer, _
    ByRef b As Integer _
) As Integer

Private Declare Function MakeTripCurrency _
Lib "tvb.dll" ( _
    ByVal a As Currency, _
    ByRef b As Currency _
) As Currency

Private Declare Function MakeTripLong _
Lib "tvb.dll" ( _
    ByVal a As Long, _
    ByRef b As Long _
) As Long

Private Declare Function MakeTripSingle _
Lib "tvb.dll" ( _
    ByVal a As Single, _
    ByRef b As Single _
) As Single

Private Declare Function MakeTripDouble _
Lib "tvb.dll" ( _
    ByVal a As Double, _
    ByRef b As Double _
) As Double

Private Declare Sub ReverseString _
Lib "tvb.dll" ( _
    ByVal a As String _
)

We have done it. All these functions only from a 20K VC DLL with no dependencies and no confusing COM. Please see the project for more details.

List of API functions compared to CRT

Here is list of API functions compared to CRT Win32 Equivalents for C Run-Time Functions (Q99456)

-------------------------------------------------------------
The information in this article applies to:

Microsoft Win32 Application Programming Interface (API), included with:
the operating system: Microsoft Windows NT, versions 3.1, 3.5, 3.51 
Microsoft Windows 95

-------------------------------------------------------------


SUMMARY
Many of the C Run-time functions have direct equivalents in the Win32 application
programming interface (API). This article lists the C Run-time functions by category
with their Win32 equivalents or the word "none" if no equivalent exists. 



MORE INFORMATION
NOTE: the functions that are followed by an asterisk (*) are part of the 16-bit C
Run-time only. Functions that are unique to the 32-bit C Run-time are listed separately
in the last section. All other functions are common to both C Run-times. 

Buffer Manipulation

   _memccpy                  none
    memchr                   none
    memcmp                   none
    memcpy                   CopyMemory
   _memicmp                  none
    memmove                  MoveMemory
    memset                   FillMemory, ZeroMemory
   _swab                     none 
Character Classification

     isalnum                 IsCharAlphaNumeric
     isalpha                 IsCharAlpha, GetStringTypeW (Unicode)
   __isascii                 none
     iscntrl                 none, GetStringTypeW (Unicode)
   __iscsym                  none
   __iscsymf                 none
     isdigit                 none, GetStringTypeW (Unicode)
     isgraph                 none
     islower                 IsCharLower, GetStringTypeW (Unicode)
     isprint                 none
     ispunct                 none, GetStringTypeW (Unicode)
     isspace                 none, GetStringTypeW (Unicode)
     isupper                 IsCharUpper, GetStringTypeW (Unicode)
     isxdigit                none, GetStringTypeW (Unicode)
   __toascii                 none
     tolower                 CharLower
    _tolower                 none
     toupper                 CharUpper
    _toupper                 none 
Directory Control

   _chdir                    SetCurrentDirectory
   _chdrive                  SetCurrentDirectory
   _getcwd                   GetCurrentDirectory
   _getdrive                 GetCurrentDirectory
   _mkdir                    CreateDirectory
   _rmdir                    RemoveDirectory
   _searchenv                SearchPath 
File Handling

   _access                   none
   _chmod                    SetFileAttributes
   _chsize                   SetEndOfFile
   _filelength               GetFileSize
   _fstat                    See Note 5
   _fullpath                 GetFullPathName
   _get_osfhandle            none
   _isatty                   GetFileType
   _locking                  LockFileEx
   _makepath                 none
   _mktemp                   GetTempFileName
   _open_osfhandle           none
    remove                   DeleteFile
    rename                   MoveFile
   _setmode                  none
   _splitpath                none
   _stat                     none
   _umask                    none
   _unlink                   DeleteFile 
Creating Text Output Routines

   _displaycursor*           SetConsoleCursorInfo
   _gettextcolor*            GetConsoleScreenBufferInfo
   _gettextcursor*           GetConsoleCursorInfo
   _gettextposition*         GetConsoleScreenBufferInfo
   _gettextwindow*           GetConsoleWindowInfo
   _outtext*                 WriteConsole
   _scrolltextwindow*        ScrollConsoleScreenBuffer
   _settextcolor*            SetConsoleTextAttribute
   _settextcursor*           SetConsoleCursorInfo
   _settextposition*         SetConsoleCursorPosition
   _settextwindow*           SetConsoleWindowInfo
   _wrapon*                  SetConsoleMode 
Stream Routines

    clearerr                 none
    fclose                   CloseHandle
   _fcloseall                none
   _fdopen                   none
    feof                     none
    ferror                   none
    fflush                   FlushFileBuffers
    fgetc                    none
   _fgetchar                 none
    fgetpos                  none
    fgets                    none
   _fileno                   none
   _flushall                 none
    fopen                    CreateFile
    fprintf                  none
    fputc                    none
   _fputchar                 none
    fputs                    none
    fread                    ReadFile
    freopen (std handles)    SetStdHandle
    fscanf                   none
    fseek                    SetFilePointer
    fsetpos                  SetFilePointer
   _fsopen                   CreateFile
    ftell                    SetFilePointer (check return value)
    fwrite                   WriteFile
    getc                     none
    getchar                  none
    gets                     none
   _getw                     none
    printf                   none
    putc                     none
    putchar                  none
    puts                     none
   _putw                     none
    rewind                   SetFilePointer
   _rmtmp                    none
    scanf                    none
    setbuf                   none
    setvbuf                  none
   _snprintf                 none
    sprintf                  wsprintf
    sscanf                   none
   _tempnam                  GetTempFileName
    tmpfile                  none
    tmpnam                   GetTempFileName
    ungetc                   none
    vfprintf                 none
    vprintf                  none
   _vsnprintf                none
    vsprintf                 wvsprintf 
Low-Level I/O

   _close                   _lclose, CloseHandle
   _commit                   FlushFileBuffers
   _creat                   _lcreat, CreateFile
   _dup                      DuplicateHandle
   _dup2                     none
   _eof                      none
   _lseek                   _llseek, SetFilePointer
   _open                    _lopen, CreateFile
   _read                    _lread, ReadFile
   _sopen                    CreateFile
   _tell                     SetFilePointer (check return value)
   _write                   _lread 
Console and Port I/O Routines

   _cgets                    none
   _cprintf                  none
   _cputs                    none
   _cscanf                   none
   _getch                    ReadConsoleInput
   _getche                   ReadConsoleInput
   _inp                      none
   _inpw                     none
   _kbhit                    PeekConsoleInput
   _outp                     none
   _outpw                    none
   _putch                    WriteConsoleInput
   _ungetch                  none 
Memory Allocation

   _alloca                   none
   _bfreeseg*                none
   _bheapseg*                none
    calloc                   GlobalAlloc
   _expand                   none
    free                     GlobalFree
   _freect*                  GlobalMemoryStatus
   _halloc*                  GlobalAlloc
   _heapadd                  none
   _heapchk                  none
   _heapmin                  none
   _heapset                  none
   _heapwalk                 none
   _hfree*                   GlobalFree
    malloc                   GlobalAlloc
   _memavl                   GlobalMemoryStatus
   _memmax                   GlobalMemoryStatus
   _msize*                   GlobalSize
    realloc                  GlobalReAlloc
   _set_new_handler          none
   _set_hnew_handler*        none
   _stackavail*              none 
Process and Environment Control Routines

    abort                    none
    assert                   none
    atexit                   none
   _cexit                    none
   _c_exit                   none
   _exec functions           none
    exit                     ExitProcess
   _exit                     ExitProcess
    getenv                   GetEnvironmentVariable
   _getpid                   GetCurrentProcessId
    longjmp                  none
   _onexit                   none
    perror                   FormatMessage
   _putenv                   SetEnvironmentVariable
    raise                    RaiseException
    setjmp                   none
    signal (ctrl-c only)     SetConsoleCtrlHandler
   _spawn functions          CreateProcess
    system                   CreateProcess 
String Manipulation

   strcat, wcscat            lstrcat
   strchr, wcschr            none
   strcmp, wcscmp            lstrcmp
   strcpy, wcscpy            lstrcpy
   strcspn, wcscspn          none
  _strdup, _wcsdup           none
   strerror                  FormatMessage
  _strerror                  FormatMessage
  _stricmp, _wcsicmp         lstrcmpi
   strlen, wcslen            lstrlen
  _strlwr, _wcslwr           CharLower, CharLowerBuffer
   strncat, wcsncat          none
   strncmp, wcsncmp          none
   strncpy, wcsncpy          none
  _strnicmp, _wcsnicmp       none
  _strnset, _wcsnset         FillMemory, ZeroMemory
   strpbrk, wcspbrk          none
   strrchr, wcsrchr          none
  _strrev, _wcsrev           none
  _strset, _wcsset           FillMemory, ZeroMemory
   strspn, wcsspn            none
   strstr, wcsstr            none
   strtok, wcstok            none
  _strupr, _wcsupr           CharUpper, CharUpperBuffer 
MS-DOS Interface

  _bdos*                     none
  _chain_intr*               none
  _disable*                  none
  _dos_allocmem*             GlobalAlloc
  _dos_close*                CloseHandle
  _dos_commit*               FlushFileBuffers
  _dos_creat*                CreateFile
  _dos_creatnew*             CreateFile
  _dos_findfirst*            FindFirstFile
  _dos_findnext*             FindNextFile
  _dos_freemem*              GlobalFree
  _dos_getdate*              GetSystemTime
  _dos_getdiskfree*          GetDiskFreeSpace
  _dos_getdrive*             GetCurrentDirectory
  _dos_getfileattr*          GetFileAttributes
  _dos_getftime*             GetFileTime
  _dos_gettime*              GetSystemTime
  _dos_getvect*              none
  _dos_keep*                 none
  _dos_open*                 OpenFile
  _dos_read*                 ReadFile
  _dos_setblock*             GlobalReAlloc
  _dos_setdate*              SetSystemTime
  _dos_setdrive*             SetCurrentDirectory
  _dos_setfileattr*          SetFileAttributes
  _dos_setftime*             SetFileTime
  _dos_settime*              SetSystemTime
  _dos_setvect*              none
  _dos_write*                WriteFile
  _dosexterr*                GetLastError
  _enable*                   none
  _FP_OFF*                   none
  _FP_SEG*                   none
  _harderr*                  See Note 1
  _hardresume*               See Note 1
  _hardretn*                 See Note 1
  _int86*                    none
  _int86x*                   none
  _intdos*                   none
  _intdosx*                  none
  _segread*                  none 
Time

   asctime                   See Note 2
   clock                     See Note 2
   ctime                     See Note 2
   difftime                  See Note 2
   _ftime                    See Note 2
   _getsystime               GetLocalTime
   gmtime                    See Note 2
   localtime                 See Note 2
   mktime                    See Note 2
   _strdate                  See Note 2
   _strtime                  See Note 2
   time                      See Note 2
   _tzset                    See Note 2
   _utime                    SetFileTime 
Virtual Memory Allocation

   _vfree*                   See Note 3
   _vheapinit*               See Note 3
   _vheapterm*               See Note 3
   _vload*                   See Note 3
   _vlock*                   See Note 3
   _vlockcnt*                See Note 3
   _vmalloc*                 See Note 3
   _vmsize*                  See Note 3
   _vrealloc*                See Note 3
   _vunlock*                 See Note 3 
32-Bit C Run Time

   _beginthread              CreateThread
   _cwait                    WaitForSingleObject w/ GetExitCodeProcess
   _endthread                ExitThread
   _findclose                FindClose
   _findfirst                FindFirstFile
   _findnext                 FindNextFile
   _futime                   SetFileTime
   _get_osfhandle            none
   _open_osfhandle           none
   _pclose                   See Note 4
   _pipe                     CreatePipe
   _popen                    See Note 4 


NOTE 1: The _harderr functions do not exist in the Win32 API. However, much of
their functionality is available through structured exception handling. 

NOTE 2: The time functions are based on a format that is not used in Win32. There
are specific Win32 time functions that are documented in the Help file. 

NOTE 3: The virtual memory functions listed in this document are specific to the
MS-DOS environment and were written to access memory beyond the 640K of RAM available
in MS-DOS. Because this limitation does not exist in Win32, the standard memory 
allocation functions should be used. 

NOTE 4: While _pclose() and _popen() do not have direct Win32 equivalents, you can 
(with some work) simulate them with the following calls: 

   _popen                     CreatePipe
                              CreateProcess

   _pclose                    WaitForSingleObject
                              CloseHandle 

NOTE 5: GetFileInformationByHandle() is the Win32 equivalent for the _fstat() 
C Run-time function. However, GetFileInformationByHandle() is not supported by 
Win32s version 1.1. It is supported in Win32s 1.2. GetFileSize(), 
GetFileAttributes(), GetFileTime(), and GetFileTitle() are supported by
Win32s 1.1 and 1.2. 

Additional query words: 3.10 3.50 4.00 

Keywords : kbOSWinNT310 kbOSWinNT350 kbOSWinNT351 kbOSWin95 
Issue type : 
Technology : kbOSWinNT kbOSWinSearch 


Last Reviewed: December 14, 2000
� 2001 Microsoft Corporation. All rights reserved. Terms of Use.

Please visit My Web Site for more tutorials, tweaks, reference.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here