Library tutorials & articles
Calling a C++ DLL from Visual Basic
- Introduction
- Adding the files
- The VB Code
Adding the files
You will now have to add three files to your project, the first being an implementation (.CPP) file, the second an interface/header (.H) file and the third a DEF (allows VB to be able to read the C++ dll function name) file.
Now lets add to the include files the function definitions for the header file. I called the header file for this demonstration c_dll_4_vb.h.
c_dll_4_vb.h
#include <windows.h>
#include <winsock.h>
// Function is used to resolve a domain name to an IP address.
// The return values are: -100 = Incorrect version of Winsock
// -200 = Cant resolve domain.
long __stdcall Resolve_Name_To_Ip
(char *pcDomainToResolve, char szReturnIP[500], int &iSize);
The function defined above will take three parameters:
- pcDomainToResolve - The name of the domain you are inquiring about.
- szReturnIP -The variable the IP address will be returned to you in.
- iSize - The length of IP address being returned without the padding.
Next you will need to add the implementation of the header file to the .CPP file. Remember that when you add the code to the .CPP file make sure you include the header file name (c_dll_4_vb.h).
c_dll_4_vb.cpp
#include "c_dll_4_vb.h"
long __stdcall Resolve_Name_To_Ip
(char *pcDomainToResolve, char szReturnIP[500], int &iSize)
{
WSADATA wsaData;
LPTSTR CompName = new char[255];
LPDWORD CompSize = new unsigned long(255);
struct sockaddr_in dest;
struct hostent *hp;
char *dest_ip;
unsigned int addr = 0;
strcpy(CompName,pcDomainToResolve);
if(WSAStartup(MAKEWORD(2,1), &wsaData) != 0)
{ WSACleanup();
return -100;
}
hp = gethostbyname(CompName);
if(!hp)
{ addr = inet_addr(CompName);
}
if((!hp) && (addr == INADDR_NONE))
{// Unable to resolve domain ip.
WSACleanup();
return -200;
}
hp = gethostbyname(CompName);
if(hp != NULL)
memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length);
else
dest.sin_addr.s_addr = addr;
if(hp)
dest.sin_family = hp->h_addrtype;
else
dest.sin_family = AF_INET;
dest_ip = inet_ntoa(dest.sin_addr);
iSize = strlen(dest_ip);
// Allow the string to return to the proper size.
strncpy(szReturnIP, dest_ip, strlen(dest_ip));
dest_ip = NULL;
hp = NULL;
addr = 0;
dest.sin_family = NULL;
dest.sin_addr.s_addr = NULL;
dest.sin_addr.S_un.S_addr = NULL;
dest.sin_port = NULL;
delete [] CompName;
delete [] CompSize;
WSACleanup();
return 0;
}
Shew! Now that wasn't so bad. Ok, we have one more file to add data to but this one I swear is a breeze, this is the .DEF file. This file will let VB read the function names from the C++ dll. This is the most important file when working with C++ and VB because without it you will run into all kinds of errors.
So rather than just talking about it let see what this file looks like.
c_dll_4_vb.defLIBRARY c_dll_4_vb DESCRIPTION 'A C++ dll that can be called from VB' EXPORTS Resolve_Name_To_Ip @1
You have just completed the C++ dll. All that is left for you to do is compile the dll and it will be ready for use with VB.
So what are we waiting for lets get onto the VB stuff!
Related articles
Related discussion
-
Run-time error '91'
by crazyidane (0 replies)
-
Problem handling Redirects with MSXML2.XMLHTTP
by brandoncampbell (2 replies)
-
vbinputbox pauses code while it waits on response. How can I reproduce that?
by brandoncampbell (1 replies)
-
Sending SMS in VB 6
by sirobnole (6 replies)
-
Comboxbox listindex in ActiveX Control
by brandoncampbell (1 replies)
Check out this article:
http://blog.rednael.com/2008/08/29/MarshallingUsingNativeDLLsInNET.aspx
It's an in-depth article that shows you how to marshal any native (or C++) DLL. It shows which types are interoperable, how to import a DLL, how to pass strings and how to de-reference pointers.
It's quite easy.
thank you very much for this code. It resolves all my problems and errors. khalil from france.
This program is very useful for me, you are very terrific. Thanks
Hi Caripito,
I guess what you need is to see if there's some VBA function to return the location of the current workbook. I don't use Excel/VBA hardly at all, so I'm not familiar with any such function.
You say there is a "ThisWorkbook.Path" in Excel VBA? Seems like it would do what you need - what does it return? When you say it doesn't work for you, what is the error?
Cheers,
- Chuck Somerville
Hey Chuck, thank you very much for answering me... I already know haow to add a DLL in Visual Basic, in fact I guess it is hte same as stand alone VB... I do this:
Public Declare Convert Lib "Blue.dll" (ByVal a as Byte) as Bool
---- where Convert is the function and Blue.dll is the DLL that have to be in System32 folder in Windows...
The problem is that I need to place the DLL in the same folder as the Workbook to make easy the installation and use, but I don't know how to write the sentence... In other situations I have used App.path or ThisWorkBook.path but in this declaration isn't work...
The program works perfectly when the DLL is in the Windows System32 folder... And if I write the whole path it works too, but the problem is that this path is not going to be always the same, because it depends on where the user place the folder...
So, if you happen to get the problem and have any clue, please write me as soon as possible...
Thanks again
Caripito
Hello... I have some similar troubles.. I need to declare a DLL in a MACRO in EXCEL using Visual Basic, and I need to set the default path in the same path the WORKBOOK is... Can you please help to do that?... I have tried everything but Visual Basic always pop up an ERROR...
Thanks a lot...
Caripito
Well, VBA within Excel is not the same as a stand-alone VB program with an installer. My previous comments relate to having the installer install the app and the DLL.
There is one way to "hook up" your VBA app to some DLLs (ones that provide "object libraries" to "Automation Controllers" like Visual Basic, having been registered as such with Windows). Search the VBA help for the topic called "Check or Add an Object Library Reference" to see how to add a reference to a DLL which has had an "object library" or a "type library" registered with Windows.
I believe you can also use a "Declare" statement to name a DLL which has been written to be callable from VB, but the location is going to have to be one of the places I mentioned earlier, and the location of the workbook is not in the DLL search path. (The workbook is not "executing" - Excel, including VBA within Excel, is executing from the directory where Excel.EXE lives.) Look in VBA help for the "Declare Statement" topic.
Both the above topics can be found in the help if you go to the "Index" tab and enter "DLL" in the "Keywords" area.
- Chuck Somerville
Hello... I have some similar troubles.. I need to declare a DLL in a MACRO in EXCEL using Visual Basic, and I need to set the default path in the same path the WORKBOOK is... Can you please help to do that?... I have tried everything but Visual Basic always pop up an ERROR...
Thanks a lot...
Caripito
I found this article extremely helpful. It was exactly the right level of detail. However, is it necessary to put the path to the dll in your vb code? Isn't it more common to put the dll in a folder that windows knows about (for example on my Widnows 2000 machine, there's hundreds of dll's in my Windows\System32 folder). This way we could just have vb find the dll with the name cdll4_vb.dll. The reason I ask is that I may deploy this to other versions of Windows, and I'm concerned that other versions of Windows keep their DLL files in a different location.
You can install the DLL in the directory you install the VB app into, if it's a DLL only you will need.
You can install it to the windows\system32 directory if it is a DLL shared by other apps.
When you run the Package and Deployment Wizard in VB to make your installer, you get to specify details about the DLL, like where to install it ({appdir} or {win\sys32} or something like that - it's a pull-down with symbols for those locations so the installer will point it all to the right place at each installation). You also get to say whether it's a DLL that may be shared by other apps. If so, it won't be un-installed untill all the other apps that use it are uninstalled as well.
Your app will find the DLL in either location... DLL search rules are a little like .EXE program search rules in DOS...
1. look in the dir your program launched from.
2. look in every location in the PATH.
3. look in the windows directory (not necessarily named C:\windows).
4. look in the windows\system32 directory.
There's pretty good help on all this in the VB6 help system.
- Chuck Somerville
I found this article extremely helpful. It was exactly the right level of detail. However, is it necessary to put the path to the dll in your vb code? Isn't it more common to put the dll in a folder that windows knows about (for example on my Widnows 2000 machine, there's hundreds of dll's in my Windows\System32 folder). This way we could just have vb find the dll with the name cdll4_vb.dll. The reason I ask is that I may deploy this to other versions of Windows, and I'm concerned that other versions of Windows keep their DLL files in a different location.
I'm pretty sure strings are handled differently in VB than in C++.
Thank you very much, your article help me so much. I create the 3 files that you recomended and put the code into the files and after I go to the Visual Basic and put the code, and when I run program, image what happen!!!! It run perfectly.
Well, thank you very much again, and if you need something only ask me.
Regards,
Wilton Filho
Hi,
I am trying to invoke a VB application from C++ dll using the ShellExecuteEx command. The problem is when I execute the program, the VB application comes up, but when I try to move the form, the parent window goes blank. Same thing happens if I switch between windows. Can anyone please guide me how to invoke a VB application from a C++ dll without much changes to my existing code.
Snippet of my code:
HWND lhwndFound;
LPSHELLEXECUTEINFO lsei=new SHELLEXECUTEINFO;
lhwndFound=GetActiveWindow();
if(lhwndFound != NULL)
{
lsei->cbSize=sizeof(SHELLEXECUTEINFO);
lsei->fMask = SEEMASKNOCLOSEPROCESS;
lsei->hwnd =lhwndFound;
lsei->lpVerb = "open";
lsei->lpFile = "MyApplication.exe";
lsei->lpParameters = "Src";
lsei->lpDirectory = lconfigpath;
lsei->nShow = SWSHOWNORMAL;
lsei->hInstApp = NULL;
ShellExecuteEx(l_sei);
WaitForSingleObject(lsei->hProcess , INFINITE);
delete lsei;
}
Thanks in advance
Regards,
Rashmi
Generally in the project settings I'll use the following settings to debug (for the "Debug" settings):
Under the "Link" tab:
In the "General" category, enable "Generate debug info".
In the "Debug" category, enable "Debug info".
Under the "C++" tab:
In the "General" category, enable "Generate browse info", and set the "Debug Info" to "Program Database for Edit and Continue".
In the "C++ Language" category, enable "Enable exception handling".
In the "Listing Files" category, enable "Generate browse info".
Under the "Browse Info" tab:
Enable "Build browse info".
Then just use the Debug version instead of the release version and you can step through on errors.
Note that if you want to step through part of the code even if it doesn't generate an error, just add VERIFY(0); wherever you want to step through.
John
I am developing interface in VB for an application program written in VC++. DLL of C++ code is called in VB. I met a strange problem. I have tested the conversion between structure in C++ and user defined type in VB successfully, which includes another embedded structure and a string as member variables. When I try to add one string member into the embedded structure, VB has a problem. It prompts" VB encountered a problem, .." and aborts completely. Can anyone tell me why this happens? Thanks.
I'm having trouble passing 9 variables into C++. It works fine if I just pass 2 or 3. Any idea why it won't work when passing more than a few variables?
Thanks, it was a very usefull for me.
However I still have one problem...
I'm working with Visual Studio .Net, and I want to debug both, the C++ DLL and the Visual Basic application at once.
The C++ DLL in the article is linked to the applications in a 'dynamic link', that is simmilar to calling LoadLibrary from a C++ application. Is there a 'static link' way as well?
i.e. is there a way to link the .lib file of the DLL to the Visual Basic application, so that when reaching the call to the C++ function when debugging the Visual Basic application, it will be possible to step in to the C++ code etc?
Thanks in advance
Israel
declare the DLL functions as "Private" within a module, you won't be able to call them
directly from any other place. VB complains "Sub or Function not defined"... for what it's worth.
My dll compiled without any problem for Debug. When i tried to compile a release version i got this mess in my output window.
Linking...
Creating library Release/Dll.lib and object Release/Dll.exp
Dll.obj : error LNK2001: unresolved external symbol inetntoa@4
Dll.obj : error LNK2001: unresolved external symbol inetaddr@4
Dll.obj : error LNK2001: unresolved external symbol _gethostbyname@4
Dll.obj : error LNK2001: unresolved external symbol _WSACleanup@0
Dll.obj : error LNK2001: unresolved external symbol _WSAStartup@8
Release/Dll.dll : fatal error LNK1120: 5 unresolved externals
Error executing link.exe.
http://www.mvps.org/vcfaq/il/3.htm actually deals with one of the problems mentioned. Not sure whether a wrapper can be written in this case ...
dwilson
How to include dll file in visual basic 6.0 program?
Thanks in advance
bloodlustangel
I am use studio to do the coding and prompt out this exception
An unhandled exception of type 'System.DllNotFoundException' occurred in WindowsApplication1.exe
Additional information: Unable to load DLL (C:\jacky\JavaTest\extendDLL\Debug\extendDLL.dll).
but it is there already
I'd bet it had something to do with the following:
http://www.mvps.org/vcfaq/il/2.htm
Since you don't have the source of the DLL that you can not change this directly but you could wrapper the _cdecl declared DLL in a C++ object which is declared as _stdcall .
Have a look at the following page, might help http://www.vb2themax.com/HtmlDoc.asp?Table=Articles&ID=60
have you discovered how to solve the problem of the entry point? Would be appreciative if you could share with me.
Cyndi
I tried the code and found it working OK.
but what my problem is that i have to call DLL functions (dll provided by the card manufacturere) of a PCI card from my VB code.
I adopted the same code with some modification to test a single function of dll and it works but the function while in execution throws an exception and pops up a message that PCI-XXX card not found.
while that same dll function is working properly when used in a sample program in VC++ (provided by the manufacturer).
so can any body tell me that how to debug a dll so that i can rectify the problem.
everything seems to work. But when I run VB nothing really happens. I just get a blank window box. I think my VB isn't set up right. All I did was copy and paste the code into my VB code form. I didn't set up any buttons or text boxes. Am I supposed to?
Please help. THanks!
I think this article is very useful to me, as a new vb programmer, however, i got this message when i run the VB
'Bad dll calling conversion'
do anyone know what is the reason?
I have very basic knowledge in Visual C++.I created the dll file and it is correctly compiled.
But when i execute my vb program,I'm getting an error.......Can't find dll entry point ResolveNameTo_In.
Please help
Can i do a *.dll in Borland c/c++ 3.0 , (dos) , i want to make want to use all the port of my PC ( COM1 , LPT1, USB , etc.
I have a problem , i dont know how to make it , can you tell me how ?
Thanks
Actually you can call a .dll in VBScript, however I am not sure that you can create them like this in C++ (maybe you can, I haven't done it that way exactly). You need to create an ActiveX Dll in Visual Basic, simply write a function, then goto File and compile your .dll. Remember the class and project name. In ASP you can do something like this.
<%
Dim x
Set x = Server.CreateObject("Project1.Class1")
If x.Check(1) = 1 Then
Response.Write("Correct")
End If
Set x = Nothing
%>
Hope This Helps
Can a dll which is created using _cdecl be used in VB
I have the following code:
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ulreasonfor_call,
LPVOID lpReserved
 
{
return TRUE;
}
extern "C" __declspec(dllexport) bool a(char* lpszPathName)
{
....
....
}
I called the dll CVB.dll, i made a CVB.DEF file "
LIBRARY C_VB
DESCRIPTION 'A C++ dll that can be called from VB'
EXPORTS
ResolveNameToIp @1
" and no go, says it cannot find the entry point "ResolveNameToIp".
I got by this problem by using dllexport and the extern "C" prefix, no need for a .DEF file?
Secondly Subs work fine under this method, however when I do get a function to 'work' it doesnt, tells me bad calling procedure, I had thought perhaps the [extern "C"] and different calling convention of dllexport [declspec( dllexport )] were responsible but when I use [stdcall] same problem. I suppose im on my own to sort that out.
got it working via the PASCAL calling convention..
///snippet
(Error 49)
Your program is calling a routine in a dynamic-link library (DLL) that either is being passed the wrong type or number of arguments or does not use the Pascal calling convention. Make sure that the arguments passed to the DLL routine exactly match the arguments expected by the routine. If the DLL routine expects arguments by value, then make sure ByVal is specified for those arguments in the declaration for the routine.
snippet///
extern "C" <return-type> __declspec( dllexport ) PASCAL func(...)
perhaps thats useful to someone who runs across the same problems as I.
Hi all,
'How do I create a dll in C++ and call it from VB?' was an article which can be called Simply SUPERB by its simlicity and elegance. Very helpful and informative.
Thank you Kevin Saitta. It was a nice work.
Regards,
Jeri.
You can't call a DLL from VBScript, needs to be VB or VBA.
Regards,
Shifty
I have followed the article to create the dll file and it is correctly compiled. But when i use my ASP program (VBScript) to test it, cannot get the correct output.......What is the problem here???
Here is the ASP code:
<HTML>
<HEAD>
<TITLE>Testing page</TITLE>
</HEAD>
<BODY>
<%
Private Declare Function Check _
Lib "D:\inetpub\H63080\TryItOut\Debug\TryItOut.dll" _
(ByVal input As Integer) As Integer
Private Sub test()
If Check(1)=1 Then
Response.Write "Correct."
End If
End Sub
%>
</BODY>
</HTML>
Can anyone help me out in this? Thanks a lot!
It was an very usefull information for me! Thanx ....
very nice article, thank you. but it's not really c++ with object et al. i would love to know how to instantiate objects in vb whose underlying classes are defined and implemented in a c++ dll.
lol .. oh well
Never mind...I didn't see the text ResolveNameTo_Ip. Now it all makes sense!!
As far as I am aware, the declaration would be valid providing there was a function called "ResolveNameTo_IP" matching the declaration in the DLL.... however, I'm not quite sure how functions in different classes come into the api declarations....
What if there were more than one function available? Would the above VB declaration still been valid?
Surely "Declare Function ResolveNameTo_Ip" is telling VB that there is a function with that name in the DLL? If there is no Alias attribute, VB assumes that the function declaration is the same as in the DLL......
I love reading articles that the source code actually works on. One thing...
Private Declare Function ResolveNameToIp _
Lib "C:\Program Files\Microsoft Visual Studio\MyProjects\cdll4vb\Debug\cdll4_vb.dll" _
(ByVal pcDomainToResolve As String, _
ByVal szReturnIP As String, _
ByRef iSize As Integer) As Long
How did VB know there was a function called ResolveNameTo_Ip available int he DLL. I understand the .def file indicated it, but in most win32 declarations the function name would have been included. If you notice above, it wasn't in this case?
Just what I was looking for!
This thread is for discussions of Calling a C++ DLL from Visual Basic.