Interfacing C functions

VB, VBA, VBScript, JavaScript, are programming languages and scripting languages to write and automate tasks in Office and Windows operating systems. They are easy to implement and good for rapid development. These have API support for doing all sorts of works provided by Windows and Office. Some APIs that are not available in the built-in libraries or some APIs which are custom needed by a user cannot be fulfilled. These types of situations call for a custom-made library file. C programming language does not have any restrictions to access low-layer system calls and utility functions. Thus user requires to implement the required function in C programming and that function can be called from Visual Besic.

VB calls DLL

Visual Basic compiler /linker generates the same type of output binary as of C compiler. Both compilers push arguments from right to left and call the function. Low level machine instructions are the same. So applications written in Visual Basic can access C functions. Functions have to reside inside a dynamic link library(dll). Program loader loads dynamic link library either from current path or from absolute location or searchs all locations given in PATH variable.

VB vs C function prototypes

Apart from dll function address, Visual Basic also need function prototype so that it can push input variables in stack before calling the function. Calling C Functions should be of type stdcall. Stdcall cleans its own stack or callee cleans the stack. So all cleanups are done in Dll side. All Windows DLL works like this. We have below example showing how VB can call a function using call by value and call by reference.

C function prototypes

int extern "C" __stdcall __declspec(dllexport) 
  
CallCByVal
( 
  char c,
  short s,
  long l,
  float f,
  double d,
  LPCSTR  str
);

int extern "C" __stdcall __declspec(dllexport)

CallCByRef
(
  char *c,
  short *s,
  long *l,
  float *f,
  double *d,
  LPSTR  *str
)

VB function prototypes

Public Declare Function CallCByVal Lib "VBDLL.dll"
(
  ByVal c As Byte, _
  ByVal s As Integer, _
  ByVal l As Long, _
  ByVal f As Single, _
  ByVal d As Double, _
  ByVal str As String
) As Integer
                                                     
Public Declare Function CallCByRef Lib "VBDLL.dll"
(
  ByRef c As Byte, _
  ByRef s As Integer, _
  ByRef l As Long, _
  ByRef f As Single, _
  ByRef d As Double, _
  ByRef str As String
) As Integer

C DLL project

We are creating a Win32 Dynamic Link Library VC++ project. We are selecting this project as Simple Dynamic Link Library Project. VC++ editor will create the necessary project files including header and C/C++ implementation file. DllMain() function will be implemented by default by the editor. We need to add CallCByVal, CallCByRef prototypes and the body of the functions.

win32 DLL C project

win32 DLL C project simple DLL

/* C Windows DLL (VBDLL.dll) Source code */
#include <windows.h>
#include <stdio.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;
}

int extern "C" __stdcall __declspec(dllexport) 
CallCByVal
(
  char c,
  short s,
  long l,
  float f,
  double d,
  LPCSTR  str
)
{
  char str_m [100];
  sprintf ( str_m,
            "Char %c, Short 0x%X, Long %ld, Float %f, Double %lf, String \"%s\"",
            c, (int)s, l, f, d, str);
  MessageBoxA(NULL, (const char *)str_m, "Message from C",  MB_OK);
  return 0;
}

int extern "C" __stdcall __declspec(dllexport)
CallCByRef
(
  char *c,
  short *s,
  long *l,
  float *f,
  double *d,
  LPSTR  *str
)
{
  char str_m[100];
  sprintf ( str_m,
            "Char %c, Short 0x%X, Long %ld, Float %f, Double %lf, String \"%s\"",
            *c, (int)*s, *l, *f, *d, *str);
  MessageBoxA(NULL, (const char *)str_m, "Values from VB",  MB_OK);
  *= *c + 1;
  *= *s + 1;
  *= *l + 1;
  *= *f + 1;
  *= *d + 1;
  strcpy(*str,"String from C");

  return 0;
}

C exported fucntions

VB Project

We are creating a simple VB application project to call the C function. We have added a button in the main form and added the calling code inside the click event of the button. This is however not limited to VB. VBA, VB script and Javascript can call the function in the same way as VB does.

Public Declare Function CallCByVal Lib "VBDLL.dll"
(
  ByVal c As Byte, _
  ByVal s As Integer, _
  ByVal l As Long, _
  ByVal f As Single, _
  ByVal d As Double, _
  ByVal str As String
) As Integer


Dim c As Byte
Dim i As Integer
Dim l As Long
Dim f As Single
Dim d As Double
Dim s As String

Private Sub Command1_Click()
  c = CByte(65)
  i = CInt(12)
  l = CLng(200)
  f = CSng(1.2)
  d = CDbl(4.8)
  s = CStr("VB String")
  Label1.Caption = "Char " + CStr(Chr(c)) + _
                   ", Short " + CStr(i) + _
                   ", Long " + CStr(l) + vbCrLf
  Label1.Caption = Label1.Caption + _
                   "Float " + CStr(f) + _
                   ", Double " + CStr(d) + _
                   ", String " + s

  r = CallCByVal(c, i, l, f, f, s)
  Label2.Caption = "Char " + CStr(Chr(c)) + _
                   ", Short " + CStr(i) + _
                   ", Long " + CStr(l) + vbCrLf
  Label2.Caption = Label2.Caption + _
                   "Float " + CStr(f) + _
                   ", Double " + CStr(d) + _
                   ", String " + s
End Sub

VB Call By Value

VB MessageBox

Public Declare Function CallCByRef Lib "VBDLL.dll"
(
  ByRef c As Byte, _
  ByRef s As Integer, _
  ByRef l As Long, _
  ByRef f As Single, _
  ByRef d As Double, _
  ByRef str As String
) As Integer

Dim c As Byte
Dim i As Integer
Dim l As Long
Dim f As Single
Dim d As Double
Dim s As String

Private Sub Command2_Click()

  c = CByte(65)
  i = CInt(12)
  l = CLng(200)
  f = CSng(1.2)
  d = CDbl(4.8)
  s = CStr("String from VB")
  Label1.Caption = "Char " + CStr(Chr(c)) + _
                 ", Short " + CStr(i) + _
                 ", Long " + CStr(l) + vbCrLf
  Label1.Caption = Label1.Caption + "Float " + CStr(f) + _
                                 ", Double " + CStr(d) + _
                                 ", String " + s

  r = CallCByRef(c, i, l, f, d, s)
  Label2.Caption = "Char " + CStr(Chr(c)) + _
                 ", Short " + CStr(i) + _
                 ", Long " + CStr(l) + vbCrLf
  Label2.Caption = Label2.Caption + _
                "Float " + CStr(f) + _
                ", Double " + CStr(d) + _
                ", String " + s
End Sub

VB Call By Reference

VB MessageBox

About our authors: Team EQA

You have viewed 1 page out of 27. Your DLL learning is 0.00% complete. Login to check your learning progress.

#