banner.png (6088 bytes) Don't Click This

Home
Back


Header file updates

v1.39 Header File Update
2011 April 9th

For LIB file and original header file, download the main distribution ZIP

PLEASE VIRUS-SCAN ALL DOWNLOADS BEFORE USE

VBToolbox Online Manual (HTML)
v1.33 Converted using PDFToHTML

VBToolbox Online Manual (HTML)
v1.32 Converted using PDFToHTML

VBToolbox Online Manual (HTML)
v1.31 Converted using PDFToHTML

* Previous versions should be discarded


Retired Versions

None


Other Links

Suggestions and Updates

I have limited time to dedicate to this project but I am open to suggestions or source code for routines to add to the library. Ideally the library needs to be completely rewritten.

Virus Warning

You are responsible for scanning these downloads for viruses. They have been scanned by Avast! on upload but there is always the possibility they could get infected before you use them.

Requirements

You will also need to have msvcrt.dll installed in your \windows\system32\ folder. You can get this as a free runtime for MS visual C++. This provides access to C++ functions for Windows programs.

Compatibility

Visual BASIC 5/6 or higher. 32-bit 9x, NT, 2k XP, Vista, Windows 7
ReactOS/WINE

Warranty and Licence

This program is provided royalty-free and free of charge for educational and personal use only (freeware) with absolutely NO WARRANTY WHATSOEVER. It is released for personal and educational use only with strictly no permission whatsoever for commercial use.

By using the software you are deemed to have agreed to the licence conditions and agree use it at your own risk with no liability to the author for direct or consequential losses arising from it's use.

Copyright

The library, code and documentation is Copyright (c) to M Shaw 2003-2012. You may include and distribute this DLL royalty-free in non-commercial applications you write as long as you adhere to the licensing conditions. Due to potential legal liabilities, the DLL should not, under any circumstances, be used by or distributed with commercial applications without express written permission from the author.

Disclaimer

The program does not knowingly contain any malicious or dangerous functions but should, nevertheless, be thoroughly tested before use. Careless calls to DLL functions can inherently be dangerous to calling applications or your Windows system.


 

Calling VBToolbox from C and C++ Code

VBToolbox may be called statically from C, C++ or any language which supports the standard Microsoft MSVC "LIB" file format. This would include the Microsoft Visual C++ family of compilers and many other compilers which can use this type of library. The LIB file (mslib145.lib) will be included in distributions or made available via a direct download link complete with a header file which declares the relevant exported function prototypes.

Unicode or ANSI?

The standard distribution is ANSI. A Unicode version is also available both for LIB and TLB formats. The Unicode version of VBToolbox is named MSLIB146.*


How To Use

First, either #include the supplied header file (MSLIB145.H) or selectively cut/paste the required function prototypes into your source code.
Secondly, you need to add the LIB file (ANSI:mslib145.lib or Unicode:mslib146.lib) to the linker settings of your compiler. You will usually need to go to your project settings area and find the required page or tab for linker settings and then append the path the above files so the linker knows how to find the file. Instructions will vary depending on which compiler you are using. The compiler must support the MSVC5 LIB format.

After this has been done you can just use the functions as you would any other C/C++ function. You will, of course, need to check the function prototypes carefully in order to pass the correct parameters to each function call.

C/C++ Header File

The LIB, TLB and ANSI header file is included with the main distribution ZIP file.

2011 April 9th - v1.39 ANSI Header File Update

Page top


Using the VBToolbox CallDLL Functions to Call External DLLs

The CallDLL* series of functions may be used by C/C++ programmers in order to call any compatible __stdcall DLL function to call dynamically on-the-fly without the need to use LoadLibrary and complex function declaration prototypes. For CallDLL* prototypes see below. Any type of parameter may be passed via CallDLL if it can be coerced to some value held within a VARIANT field.

Advantages

Flexibility. Calls don't need to be "hard-wired" and declared in advance or use complex, hard-to-fathom function prototypes. DLL function calls can be made conditionally or on-the-fly from code logic. If code is generated carefully then the code will be stable. Can call just about any DLL including Windows API/system DLLs.

Disadvantages

Fragility. Far less error-checking. Requires an understanding of coercing data types into VARIANT structures. Requires careful adherence to the function prototype and generation of variant arrays used to pass data. Sloppy call-generation may make your code unstable. CallDLL is designed to handle ANSI data but might be coerced to use Unicode (this has not been tested). Called DLL exported functions must support the __stdcall interface unless CallDLLCDecl is used (v1.40+)

Function Return Type(s)
DLLParamInit Non-DLL function (not present for VB) which is included in the C/C++ header
Used to clear/initialise/wipe VARIANT structures
CallDLL Any 32-bit, 16-bit or 8-bit types (DWORD/WORD), also LPSTR (char*), BSTR, short, byte/char, void* and struct* e.. VARIANT*.
Values narrower than 32 bit will need to be coerced (cast) on return to preserve sign-bit values.
Values wider than 32 bit cannot be handled (e.g. int64) although pointers to such types may be passed via a cast
CallDLLSingle Returns 4 byte float type (VB style Single)
CallDLLDouble Returns an 8 byte double type (VB style Double)
CallDLLVariant Returns an allocated 16-byte VARIANT type
CallDLLCDecl __cdecl declared DLLs *only* such as msvcrt40.dll - C/C++ and similar languages only, not for use with Visual BASIC
This function cleans up the stack according to the
__cdecl calling convention rather than relying on the called function (VBToolbox v1.40+)
Any
32-bit, 16-bit or 8-bit types (DWORD/WORD), also LPSTR (char*), BSTR, short, byte/char, void* and struct* e.. VARIANT*.
Values narrower than 32 bit will need to be coerced (cast) on return to preserve sign-bit values.
Values wider than 32 bit cannot be handled (e.g. int64) although pointers to such types may be passed via a cast
Strings (LPSTR) may be cast to (long) and passed as such if convenient
This function permits the calling of functions with varying numbers of arguments such as printf()
CallDLLCDeclSingle As CallDLLSingle but calls using the __cdecl calling convention
This function permits the calling of functions with varying numbers of arguments such as printf()
CallDLLCDeclDouble As CallDLLDouble but calls using the __cdecl calling convention
This function permits the calling of functions with varying numbers of arguments such as printf()
CallDLLCDeclVariant Not implemented as few cases are anticipated for the use of VARIANT objects with Cdecl calling conventions

CallDLL Examples

Parameters are passed by means of a VARIANT array. This must be suitably dimensioned and declared according to the number of parameters the DLL function call requires. You must specify both the variable type and value for each variant in the array. Additionally, you should call DLLParamInit() to ensure that variants are cleared to zero (wiped) - particularly if they are re-used within a program. The number of parameters being passed must be specified in the call and the particular casting required to pass the variant array must be adhered to - (VARIANT*)&varname. This variant array must be an actual array and not an array of pointers unless these have been declared to point to a valid variant array and any necessary casts adjusted.

Only external functions which are compliant with the __stdcall convention may be called using the CallDLL* functions
The exception is that __cdecl (C calling convention) functions may be called by non VB programs using CallDLLCDecl

Once the above rules are adhered to, calling the CallDLL* family is quite straightforward.
Standard C/C++ lib functions and Win32 API are highlighted in magenta, VBToolbox functions are highlighted in orange

// Prototype: 
// BSTR _stdcall MTRandomStr(long len, const short style=RANDOM_STYLE_MIXED)
VARIANT v[2];
DLLParamInit((VARIANT*)&v,howbig(v)); // Ensure variant array zeroed out
v[0].vt=VT_I4;    // long (4 byte) data type
v[0].lVal=60;     // string length - 60 chars
v[1].vt=VT_I2;    // short (2 byte) data type
for(int i=0; i<15; i++)
{
    v[1].iVal=i;  // Call with each type of string format
    printf("Randomstr(%i)=[%s]\n",v[1].iVal,
	(LPSTR)CallDLL("mslib145.dll","MTRandomStr",&errcode,2,(VARIANT*)&v));
}

Another example. Wordlist() creates a SAFEARRAY string which is returned in a VARIANT

// Wordlist ////////////////
// Prototype: VARIANT _stdcall WordList(LPCSTR s, long base=0)
VARIANT v[2];
VARIANT vt;	     // Return variant
DLLParamInit((VARIANT*)&v,howbig(v));        
v[0].vt=VT_BSTR;
v[0].bstrVal=(BSTR)"Now is the time for all good men to come to the aid of the party";
v[1].vt=VT_I2;       // short (2 byte) data type
v[1].iVal=0;
vt=CallDLLVariant("mslib145.dll","WordList",&errcode,2,(VARIANT*)&v);
printf("Done WordList. Calling PrintR()\n");
// Prototype: VARIANT _stdcall QSort(VARIANT* v, 
//	const short reverse_sort=0, const short ignore_case=0)
QSort(&vt,0,1);      // Call VBToolbox LIB function directly
// Prototype: long _stdcall PrintR(const VARIANT* v, 
//	const short show_empty=0, const short show_address=0);
PrintR(&vt,0);       // Call VBToolbox LIB function directly
VariantClear(&vt);   // Release dynamic memory

And another...

// CSVSplit and ElementCount 
// Prototype: VARIANT _stdcall CSVSplit(LPCSTR s, 
//	const long inbase=0, char separator=',')
// Prototype: long _stdcall ElementCount(VARIANT* v)
DLLParamInit((VARIANT*)&v,howbig(v));
VARIANT v[3];
VARIANT vt;	    // Return variant
v[0].vt=VT_BSTR;
v[0].bstrVal=(BSTR)"One,two,three four,five,six seven, eight";
v[1].vt=VT_I4;	    // long (4 byte) data type
v[1].lVal=1;
v[2].vt=VT_I1; 	    // char (1 byte) data type
v[2].bVal=',';
vt=CallDLLVariant("mslib145.dll","CSVSplit",&errcode,3,(VARIANT*)&v);
printf("Finished CSVSplit - calling PrintR...\n");
PrintR(&vt,0);      // Call VBToolbox function

// Now call ElementCount with variant vt
v[0].vt=vt.vt;      // Copy original variant flag type
v[0].pvarVal=&vt;   // pointer to variant
printf("Element count=%i\n",CallDLL("mslib145.dll","ElementCount",&errcode,1,(VARIANT*)&v));
VariantClear(&vt);  // Release dynamic memory

Example calling the Win32 API using _stdcall...

// Win32 API Prototype: int WINAPI MessageBox(HWND hWnd, 
//	LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);
DLLParamInit((VARIANT*)&v,howbig(v));        
v[0].vt=VT_NULL;        // Use this for NULL parameters
v[1].vt=VT_BSTR;
v[1].bstrVal=(BSTR) "Now is the time for all good men to vote against the party";
v[2].vt=VT_BSTR;
v[2].bstrVal=(BSTR) "Hello world";
v[3].vt=VT_UI4; 
v[3].ulVal=MB_ICONINFORMATION | MB_ICONQUESTION | MB_OKCANCEL;
ret=CallDLL("User32.dll","MessageBoxA",&errcode,4,(VARIANT*)&v);
printf("Check: MessageBox=[%i] (0==FAIL) (errcode=%i)\n",ret,errcode);

Calling a Microsoft Visual C++ Runtime DLL function (__cdecl)

// Prototype: char* asctime( const struct tm* timeptr );
// Calling a __cdecl DLL which takes a struct 
struct tm when;
time_t now;
time(&now);			// Get current time as c time
when = *localtime(&now);	// Convert from c time to struct
DLLParamInit((VARIANT*)&v,howbig(v));
v[0].vt=VT_I4;
v[0].lVal=(long)&when;		// Cast struct address to long
LPSTR ptr=(LPSTR)CallDLLCDecl("msvcrt40.dll","asctime",&errcode,1,(VARIANT*)&v);
printf("asctime() returned %s errcode=%i\n",ptr,errcode);
// asctime() returned [Mon Apr 23 00:45:33 2012

Calling a Microsoft Visual C++ Runtime DLL function (__cdecl)

// Test calling variable-arg C function
// int printf( const char *format [, argument]... );
DLLParamInit((VARIANT*)&v,howbig(v));
v[0].vt=VT_I4;
v[0].lVal=(long)"* Hello from %s short=%i long=%i double=%f *\n";
v[1].vt=VT_I4;
v[1].lVal=(long)"printf()";
v[2].vt=VT_I2;
v[2].iVal=1234;
v[3].vt=VT_I4;
v[3].lVal=123456790;
v[4].vt=VT_R8;
v[4].dblVal=1234.56789;
long ret=CallDLLCDecl("msvcrt40.dll","printf",&errcode,5,(VARIANT*)&v);
printf("printf() returned: %i char(s) errcode=%i\n",ret,errcode);
// Console echo from printf...
// * Hello from printf() short=1234 long=123456790 double=1234.567890 *

Calling a Microsoft Visual C++ Runtime DLL function (__cdecl) from Visual BASIC

Dim v(5) As Variant
Dim i As Integer
v(0) = VBStrToCStr("c:\windows\system32\drivers\hosts.txt")
v(1) = VBStrToCStr(String$(255, " "))	' Create C ANSI buffers using malloc()
v(2) = VBStrToCStr(String$(255, " "))	' VBStrToCStr returns a 32-bit long
v(3) = VBStrToCStr(String$(255, " "))
v(4) = VBStrToCStr(String$(255, " "))
CallDLLCDecl "msvcrt40.dll", "_splitpath", ErrCode, 5, v(0)
Debug.Print "_splitpath: Errcode="; ErrCode
CStrFree v(0)		' Release memory using free()
For i = 1 To 4
	Debug.Print i; "=["; CStrToVBStr(v(i)); "]"
	CStrFree v(i)	' Release memory using free()
Next
_splitpath: Errcode= 0 
1 =[c:]
2 =[\windows\system32\drivers\]
3 =[hosts]
4 =[.txt]

Calling a Microsoft Visual C++ Runtime DLL function (__cdecl) from C++ (as above code)
C strings may be coerced into longs without ill effect on Win32

DLLParamInit((VARIANT*)&v,howbig(v));
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
v[0].vt=VT_I4;
v[0].lVal=(long)"c:\windows\system32\drivers\etc\fred.txt";
v[1].vt=VT_I4;
v[1].lVal=(long)&drive;
v[2].vt=VT_I4;
v[2].lVal=(long)&dir;
v[3].vt=VT_I4;
v[3].lVal=(long)&fname;
v[4].vt=VT_I4;
v[4].lVal=(long)&ext;
CallDLLCDecl("msvcrt40.dll","_splitpath",&errcode,5,(VARIANT*)&v);
printf("_splitpath returned drive [%s]\n",drive);    
printf("_splitpath returned dir [%s]\n",dir);
printf("_splitpath returned fname [%s]\n",fname);    
printf("_splitpath returned ext [%s]\n",ext);    
printf("_splitpath() returned void errcode=%li\n",errcode);

Code highlighted statically using CGI-Highlight

Page top

Troubleshooting

If crashes occur this will usually be due to the following

  • Improperly declaring/setting the variant element type (VT_*_)
  • NULL values should normally be passed using VT_NULL with no value set
  • Setting the wrong variant field with passed data data
  • Specifying the wrong number of parameters in the CallDLL* call
    These must match the function prototype even if default parameters are present in the declared library function
  • Using the wrong function cast when passing the variant array (VARIANT*) - pass &VARIANT or (VARIANT*)&varname if an array
  • Calling an external DLL which does not support the __stdcall   interface
  • CDECL DLLs such as MSVCRT40.DLL require the use of CallDLLCdecl() (v1.40+)

Page top


CallDLL Function Prototypes

These are the export prototypes of relevant VBToolbox CallDLL* functions. These will be required for C/C++ programs and their declaration may be adapted for use with other languages which can use the import LIB file.

The CallDLL* routines are intended primarily to support calling external DLLs using the __stdcall calling convention via Visual BASIC, but additional functions are offered which support the __cdecl calling convention to support C/C++ programs calling C DLLs

Calling C routines from Visual BASIC may be problematic since VB handles Win32 API strings via handles. Also it holds these internally as Unicode although function parameter calls to declared DLLs are automatically converted to/from ANSI. Extra VBToolbox functions are available from v1.40+ which allocate/deallocate strings using malloc/free - these being CStrToVBStr, VBStrToCStr and CStrFree.

DWORD _stdcall CallDLL(LPCSTR dllname, LPCSTR funct, 
	long* errcode=NULL, long paramcount=0, VARIANT* data=NULL);
float _stdcall CallDLLSingle(LPCSTR dllname, LPCSTR funct, 
	long* errcode=NULL, long paramcount=0, VARIANT* data=NULL);
double _stdcall CallDLLDouble(LPCSTR dllname, LPCSTR funct, 
	long* errcode=NULL, long paramcount=0, VARIANT* data=NULL);
VARIANT CallDLLVariant(LPCSTR dllname, LPCSTR funct, 
	long* errcode=NULL, long paramcount=0, VARIANT* data=NULL);
// Cdecl variants... (v1.40+).
DWORD _stdcall CallDLLCDecl(LPCSTR dllname, LPCSTR funct, 
	long* errcode=NULL, long paramcount=0, VARIANT* data=NULL);
float _stdcall CallDLLCDeclSingle(LPCSTR dllname, LPCSTR funct, 
	long* errcode=NULL, long paramcount=0, VARIANT* data=NULL);
double _stdcall CallDLLCDeclDouble(LPCSTR dllname, LPCSTR funct, 
	long* errcode=NULL, long paramcount=0, VARIANT* data=NULL);
// CallDLLCDeclVariant is not implemented

Page top


Calling Sub()-routines Instead of Functions

VBToolbox Visual BASIC Sub(routines) - i.e. C/C++ functions which take no arguments, may be called in an abbreviated manner. These don't require a valid VARIANT structure and NULL may be passed along with an argument count of Zero

printf("IsNetworked=%i\n",CallDLL("mslib145.dll","IsNetworked",&errcode,0,NULL));

Page top


Calling Sub()-routines Instead of Functions

For C/C++ and other non-VB use the CallDLLCDecl* range of functions provided with VBToolbox v1.40+. The standard DLL interface is __stdcall but some DLLs export using the __cdecl convention. Care must be taken to use the correct calling convention otherwise the stack will become corrupted and your program will behave unpredictably. The Cdecl convention passes parameters in right-to-left order as with __stdcall, but the calling routine cleans up the allocated stack pointer

// Prototype: msvcrt40.dll - long atol(const char *string);
DLLParamInit((VARIANT*)&v,howbig(v));    
long errcode=0;
v[0].vt=VT_I4;
v[0].lVal=(long) "1234567890";
long ret=CallDLLCDecl("msvcrt40.dll","atol",&errcode,1,(VARIANT*)&v);
printf("atol=[%i] errcode=%i\n",ret,errcode);

Note that the Microsoft Visual C++ runtime is given as an example, there would usually be no practical reason to call the DLL from C/C++ programs

Page top


Releasing Returned String Memory

Many VBToolbox functions will return strings which have been dynamically-allocated by the Win32 API family of routines such as SysAllocString.
In all cases the result of these function, if not NULL, must be released using SysFreeString(). Visual BASIC would normally take care of such memory housekeeping.

//Prototype: LPSTR _stdcall CreateGUID(const short formatted=TRUE)
v[0].vt=VT_I4;		// 32-bit integer.
v[0].lVal=1;            // 1L (TRUE)
LPSTR ptr=(LPSTR)CallDLL("mslib145.dll","CreateGUID",&errcode,1,(VARIANT*)&v);
printf("CreateGUID=%s\n",ptr);
SysFreeString((BSTR)ptr);

Page top


VBToolbox Functions Not Recommended for C/C++ Use

The following VBToolbox library functions are not recommended for C/C++ use as they are designed specifically to accommodate the VB interface(s)

VBToolbox Function Name Notes
CString Designed for use with VB memory management
The input parameter must be a string allocated using SysAlloc* API calls
Cannot be called with stack or heap based strings
The input string is freed (this behaviour may be altered)
The return string is identical to the new input string
May be called with care from C/C++

  Page top


Interfacing VBToolbox CallDLL* Functions With C#.Net

Can be done but is possibly not recommended as this relies on blocks of code which are marked as "unsafe" in order to access pointers in C#. Marshalling of raw structures and low-level bit-manipulation is necessarily limited in C# for security reasons. Most VBToolbox functions can be called via a suitable pinvoke declaration with a suitable attribute block. Using pointers means that code is less portable. Research is continuing.

Strings may also be Marshalled instead of using VBStrToCStr etc using (int)Marshal.StringToHGlobalAnsi("Hello World"); .

// Partial (incomplete) C# example code calling VBToolbox via CallDLL interface
namespace ConsoleApplication1
{
  // VT_* Enums for interfacing with VARAIANT routines 
  public enum Vnt: ushort // (enum definition omitted) ... 

  unsafe class Program
  {
    // Struct definition (incomplete) - emulates a C union
    [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 16)]
    public unsafe struct Variant // (code omitted) ...

    [DLLImport("mslib145.dll")]
    private static extern int CallDLL(string dllName, string funct, 
                   int* errcode, int paramcount = 0, Variant* v = null);
    // Other DLL definitions omitted ....

    static unsafe void main(string[] args)
    {
      double d;
      Variant[] vt = new Variant[10];
      // General service lib routine calls 
      Console.WriteLine("LibVersion=" + (LibVersion() / 100.0).ToString("0.00")); 
      Console.WriteLine("LibUnicode=" + LibUnicode());
      Console.WriteLine("LibName=" + LibName());
      Console.WriteLine("LibName=" + LibDate());
      
      // Test short-form call 
      d = CallDLLDouble("mslib145.dll", "VBNow", &errcode);
      Console.WriteLine("errcode=" + errcode);
      Console.WriteLine("VBNow=" + d);
      
      // Long form call with CC++ malloc() memory allocation  
      //  char *__stdcall MKTempName(const char * path,const char * ftype,
      //	const short pathlen,const short style);
      vt[0].vt = (ushort)Vnt.VT_BSTR;
      vt[0].bstrVal = 0;  // Path (NULL)
      vt[1].vt = (ushort)Vnt.VT_BSTR;
      ptr = VBStrToCStr(".tmp"); // Allocate a C string using malloc() 
      vt[1].bstrVal = ptr;
      vt[2].vt = (ushort)Vnt.VT_I2;
      vt[2].iVal = 8;
      vt[3].vt = (ushort)Vnt.VT_I2;
      vt[3].iVal = 0;     // RANDOM_STYLE_MIXED==0
      fixed (Variant* v = &vt[0])  // This wrapper sucks but appears necessary
      {             	           // ... or a variable-scoping error may occur
        ptr2 = CallDLL("mslib145.dll", "MKTempName", &errcode, 4, v); 
      }
      CStrFree(ptr);      // Call to CC++ free() for malloc()ed string
      Console.WriteLine("MKTempName: " + StrCast(ptr2));
    }
  }
}

References

Page top


This page and software, unless otherwise stated, is Copyright (c) M Shaw
This page was developed using "Dinosaurwear" (FrontPage 98)
Last updated 26 February, 2021

Last updated on 26 February 2021 - This page is designed for Mozilla Seamonkey and 1024 x760 resolution displays