Make a VB-dll and load it in C++ application

Sara H picture Sara H · Jun 8, 2012 · Viewed 8.2k times · Source

I have a problem I've been struggeling with for a full week now, and I'm not able to solve it by myself. I've been googeling, and searching in all kind of forums... I have found lots of "this might work", tried it, but no, no success. If anyone have any clue, please, please, help me!

I'v got, from an external source, lots of classes and functions written in VB that I need to be able to use from a C++ application. My first though was: no problem, I turn the VB code into a dll, and load it from my C++-program. This was though harder than I ever could imagine. My C++-program is not written in Visual Studio, but for simplicity I started with trying to load my VB dll (written in Visual Studio 2010) from a Visual Studio C++ application. This is my code so far:

VB-code : DllModule : Class-library project

DllModule.vb

Namespace DllModule
  Public Module DllModule

    Public Const DLL_PROCESS_DETACH = 0
    Public Const DLL_PROCESS_ATTACH = 1
    Public Const DLL_THREAD_ATTACH = 2
    Public Const DLL_THREAD_DETACH = 3

    Public Function DllMain(ByVal hInst As Long, ByVal fdwReason As Long,
      ByVal lpvReserved As Long) As Boolean
        Select Case fdwReason
            Case DLL_PROCESS_DETACH
                ' No per-process cleanup needed
            Case DLL_PROCESS_ATTACH
                DllMain = True
            Case DLL_THREAD_ATTACH
                ' No per-thread initialization needed
            Case DLL_THREAD_DETACH
                ' No per-thread cleanup needed
        End Select

        Return True
    End Function

    'Simple function
    Public Function Add(ByVal first As Integer, ByVal sec As Integer) As Integer
        Dim abc As Integer
        abc = first + sec
        Return abc
    End Function
  End Module
End Namespace

DllModule.def

NAME DllModule
LIBRARY DllModule
DESCRIPTION "My dll"
EXPORTS DllMain @1
        Add @2

C++-code : TryVbDllLoad : Console application

TryVbDllLoad.cpp

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <strsafe.h>

extern "C" {
 __declspec(dllimport) int __stdcall Add(int, int);
}

typedef int (__stdcall *ptf_test_func_1_type)(int, int);

int __cdecl _tmain(int argc, _TCHAR* argv[])
{
    HINSTANCE hdll = NULL;

    hdll = LoadLibrary("DllModule.dll");        // load the dll
    if(hdll) {
        ptf_test_func_1_type p_func1=(ptf_test_func_1_type)GetProcAddress(hdll,"Add");

        if(p_func1) {
           int ret_val = (*p_func1)(1, 2);
        } else {
        DWORD dw = GetLastError();
        }

        FreeLibrary(hdll);              // free the dll
    } else {
        DWORD dw = GetLastError();
    }

    return 0;
}

I can load the dll, but GetProcAddess returns NULL with error code 127 (the specified procedure could not be found).

I have tried to load the dll from a VB-application. This works (even without the .def-file). But I'm guessing there is no proper entry point created that the C++ application can use (when I open the dll in Dependency Walker I see no entry point or functions). I've tried compiling the VB-code both with and without "Register for COM interop".

1) What am I doing wrong?

2) If there isn't any nice way to solve this properly, what can I do instead of creating a dll? Is there any other way I can use the VB-classes and functions in my C++ application?

Kind Regards

Sara



Thanks for your answer Mare!

There must be some kind of error in my dll though, cause when I try to register is using regsvr32 I get: "The module C:/tmp/DllModule.dll was loaded, but the start address for DllRegisterServer was not found. Check that C:/tmp/DllModule.dll is a valid DLL- or OCX-file and try again."

Also, when I use

#import "C\tmp\DllModule.dll"

I get

fatal error C1083: Cannot open type library file: 'c:\tmp\dllmodule.dll'


I looked at the link with the tutorial, but there is a small problem: there are no such thing as "ActiveX DLL" to choose among all the project types. And yes, I do have Visual Studio 2010 Professional (a trial version, but still).

-- Sara

Answer

Sara H picture Sara H · Jun 12, 2012

Thanks for all the input. I've come across another way to solve my problem, using a multifile assembly rather than my first dll approach.

I followed this HowTo-section: http://msdn.microsoft.com/en-us/library/226t7yxe.aspx#Y749

VB-code : DllModule : Class-library project

DllModule.vb

Imports System.Runtime.InteropServices

Namespace DllModuleNS
    Public Class Class1

        Public Function ClassAdd(ByRef first As Integer, ByRef sec As Integer) As Integer
            Dim abc As Integer
            abc = first + sec
            Return abc
        End Function

    End Class
End Namespace

This file I compiled using both visual studio (to produce DllModule.dll-file) and cmd-line:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\Vbc.exe /t:module DllModule.vb

(to produce DllModule.netmodule-file).

C++-code : TryVbDllLoad : Console application

TryVbDllLoad.cpp

#using <mscorlib.dll>

#using ".\..\ClassLibrary1\DllModule.netmodule"
using namespace DllModule::DllModuleNS;

int _tmain(int argc, _TCHAR* argv[])
{
    Class1^ me = gcnew Class1();
    int a = 1, b = 2;
    int xx = me->ClassAdd(a, b);
    return 0;
}

In the TryVBDllLoad-project properties I changed:

  • Common Properties -> Framework and References : added DllModule-project as reference
  • Configuration Properties -> C/C++ -> General : /clr flag set
  • Configuration Properties -> Linker -> Input : Add Module To Assembly set to path to DllModule.netmodule (/ASSEMBLYMODULE:"DllModule.netmodule")

This resulted in that I could use the VB-class Class1 in VC++ code!

PROBLEM SOLVED!


I now took it one step further, and changed the TryVBDllLoad-project to a dll:

  • Configuration Properties -> General : Configurationtype Dynamic Library (.dll)
  • Configuration Properties -> Linker -> System : SubSystem Windows (/SUBSYSTEM:WINDOWS)

TryVbDllLoadClass.h

#ifndef TryVbDllLoadClass_H
#define TryVbDllLoadClass_H

class TryVbDllLoadClass
{
public:
    TryVbDllLoadClass();
    int Add(int a, int b);
};

#endif  // TryVbDllLoadClass_H

TryVbDllLoadClass.cpp

#include "TryVbDllLoadClass.h"
#using <mscorlib.dll>

#using ".\..\ClassLibrary1\DllModule.netmodule"
using namespace DllModule::DllModuleNS;


TryVbDllLoadClass::TryVbDllLoadClass() {}

int TryVbDllLoadClass::Add(int a, int b)
{
Class1^ me = gcnew Class1();
int xx = me->ClassAdd(a, b);
return xx;
}

DllExport.h

#ifndef DLLEXPORT_H
#define DLLEXPORT_H

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>

#ifdef __dll__
#define IMPEXP __declspec(dllexport)
#else
#define IMPEXP __declspec(dllimport)
#endif  // __dll__

extern "C" {
    IMPEXP int __stdcall AddFunction(int);
}

#endif  // DLLEXPORT_H

DllMain.h

#define __dll__
#include "dllExport.h"
#include " TryVbDllLoadClass.h"

int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
{
    return 1;
}

TryVbDllLoadClass * my;

IMPEXP int __stdcall AddFunction(int first, int second)
{
    my = new TryVbDllLoadClass();
    int res = my->Add(first, second);
    delete my;
    return res;
}

This dll I could then add to a non-visual-studio project just like a normal dll:

C++-code : LoadDll : Non-Visual-Studio-project (CodeBlocks in this case)

main.cpp

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#include "dllExport.h"

typedef int( * LPFNDLL_CREATE)(int, int);
HINSTANCE hDLL;
LPFNDLL_CREATE func;

using namespace std;

int main()
{
    cout << "Hello world!" << endl;
    int key = 35;

    hDLL = LoadLibrary("TryVbDllLoadClass.dll");

    if(hDLL)
    {
        cout << "Loaded: " << hDLL << endl;

        func = (LPFNDLL_CREATE) (GetProcAddress(hDLL, "_AddFunction@4"));
        if(func != NULL)
        {
            cout << "Connected: " << func << endl;
            cout << "Function returns: " << func(key, key) << endl;
        }
        else cout << " ::: fail: " << GetLastError() << endl;

        FreeLibrary(hDLL);
        cout << "Freed" << endl;
    }
    else cout << " ::: fail: " << GetLastError() << endl;

    printf("-> Goodbye world!\n");
    return 0;
}

This way I can use the VB-classes given to me in my existing C++-project created outside Visuabl Studio. Finally...:)