Run C++ Console in Vb.net ?

Hello everybody.

Can make .dll with VS C++2012 console and import to vb.net2012?

Thankyou very much.



My vb.net is pretty weak, but there's System InterOp Services (SysInvoke or whatever, I forget), where you can call Windows Api Functions and oter functions in dlls. That should work. In my case, I've used my ActiveX Grid Control in VB.NET. That works fine. Actually, the one I tested was written in PowerBASIC, but last year I rewrote it in C++ just for the h*** of it. Don't recall if I tested that in VB.NET or not. But my opinion is you should be able to do it. Start by just making a small test project, like adding two numbers, and see if you can get it to work.
Hello Freddie1.

Can you make .dll by VC++2012 with Console and import to Vb.net 2012 with winform .

Thankyou very much.
Last edited on
Thanks Freddie1
But i need more details with step by step !!!!!!!!!!!!!!!!!!
Geeez! What ever happened to figuring things out for oneself? When I wanted to do that years ago I did a search for PInvoke, if I recall correctly. That stands for 'Platform Invoke'. It means you want to do something 'outside' of the .NET Framework. Like call a Windows Api function, or native code in a C++ dll like you want to do. When I got my search results back from MSDN I think, there was a short five or ten line code blurb showing how to do it. At the time I was working with PowerBASIC instead of C++ but that doesn't matter a bit. PowerBASIC makes native 32 bit exes or dlls. So I made a dll exporting a function that returns an int where one passes in one int through the parameters. I named the function AddOne(int iNumber); It worked perfectly. That's all you have to do.
Taipscode, do you still need help? I'm sorry about my aweful reply above. What happened is I'm kind of old, and so is my wife. We're both 62. Yesterday morning about 5 AM she fell down the steps at our house. Unbelievably enough, she wasn't hurt. But I was pretty shaken up. It was about a half hour after that I answered as above. I shouldn't even have been on the internet.

But in any case, I did work out an example in C++ and VB.net if you want it. Let me know.

Fred
Yeah hi Freddie1. You are really a good friend.
I ussually sick after read msdn.microsoft.com ,so i like more step by step ,hic hic....
This is a code run good with VC++ Console 2012 , can you help me run on VB.net with winform .
Thankyou very much , and i will send some gifts for you ,hic hic ....

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include "stdafx.h"
#include <EndpointVolume.h>
#include "Audioclient.h"
#include <mmdeviceapi.h>
#include <functiondiscoverykeys.h>

#include "CmdLine.h"

#include <mmdeviceapi.h>
#include <endpointvolume.h>

int main(int argc, CHAR* argv[])
{
 HRESULT hr=NULL;
    bool decibels = false;
    bool scalar = false;
    double newVolume=0.5;
 
    CoInitialize(NULL);
    IMMDeviceEnumerator *deviceEnumerator = NULL;
    hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, 
                          __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
    IMMDevice *defaultDevice = NULL;
 
    hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
    deviceEnumerator->Release();
    deviceEnumerator = NULL;
 
    IAudioEndpointVolume *endpointVolume = NULL;
    hr = defaultDevice->Activate(__uuidof(IAudioEndpointVolume), 
         CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume);
    defaultDevice->Release();
    defaultDevice = NULL;
 
    // -------------------------
    float currentVolume = 0.8;
    endpointVolume->GetMasterVolumeLevel(&currentVolume);
    printf("Current volume in dB is: %f\n", currentVolume);

    hr = endpointVolume->GetMasterVolumeLevelScalar(&currentVolume);
    //CString strCur=L"";
    //strCur.Format(L"%f",currentVolume);
    //AfxMessageBox(strCur);

   
       // hr = endpointVolume->SetMasterVolumeLevel((float)newVolume, NULL);
  system("pause");
       hr = endpointVolume->SetMasterVolumeLevelScalar((float)newVolume, NULL);
   
    endpointVolume->Release();

	
    CoUninitialize();
 
    return FALSE;
	
}

Last edited on
First let me say Tapiscode, that I have been totally unable to get any of my examples working on 64 bit Windows 7. When I first became interested in this topic of calling unmanaged code from VB.NET was back in 2008 or so. And at that time I was using PowerBASIC for my tests. PowerBASIC isn’t anything at all like VB.NET. Its much closer to C or C++ than .NET. So what my code works on at this point is Windows XP or 32 bit Windows 7. I’m simply not knowledgable enough in .NET to know why my code won’t work on 64 bit machines, so I’m going to have to leave that up to you to figure out.

The Microsoft link I used to learn what I did is this …

http://msdn.microsoft.com/en-us/library/42b9ea93%28v=vs.110%29.aspx

It uses a MessageBox() example. MessageBox() is the Win32/64 function in the Windows Api. What I did was create the following PowerBASIC Dll…

1
2
3
4
5
#Compile Dll

Function AddOne Alias "AddOne" (Byval x As Long) Export As Long
  AddOne = x + 1
End Function


The function is called AddOne(), and all it does is increment and return the ‘x’ parameter passed in the parameter list. In other words, if you pass in 5 it returns 6.

Here is my VB.NET program that creates a GUI Window and calls AddOne() from the PowerBASIC Dll…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
'vbc /r:System.dll,System.Windows.Forms.dll,System.Drawing.dll /t:winexe PInvoke.vb
Imports System
Imports System.Drawing
Imports System.Windows.Forms
Imports System.Runtime.InteropServices

Public Class PowerBasic
  Declare Function AddOne Lib "ADDONE.DLL" Alias "AddOne" (Byval x As Long) As Integer   
End Class

Class PInvoke
  Inherits Form
  
  Sub New()
    Me.Text="Using PowerBASIC In VB.NET"    
    Me.BackColor = SystemColors.Window
    Me.ForeColor = SystemColors.WindowText
  End Sub
  
  Protected Overrides Sub OnPaint(ByVal pea As PaintEventArgs)
    Dim br As SolidBrush
    Dim iNum As Integer

    iNum=5
    iNum=PowerBasic.AddOne(5)
    br=New SolidBrush(SystemColors.WindowText)
    pea.Graphics.DrawString("iNum=" & iNum.ToString(),Me.Font,br,0,0)
  End Sub
End Class

Module Main
  Sub Main()
    Application.Run(New PInvoke())
  End Sub
End Module 


Note that the key to doing this is the three lines at top as so…

1
2
3
Public Class PowerBasic
  Declare Function AddOne Lib "ADDONE.DLL" Alias "AddOne" (Byval x As Long) As Integer   
End Class


As my link above describes, you have to wrap a VB Declare Statement within a ‘Class’, and I arbitrarily named the Class PowerBASIC. And you can see in the OnPaint() message handler for my Pinvoke Class how I called the function, and I used the DrawString member of the Graphics Class to output the incremented number to the form. This works perfectly on XP or 32 bit Windows 7.

Note I don’t use the Visual Studio IDE to compile .NET programs. Basically I dislike Visual Studio and I hate .NET. I compiled the above program from the command line using vbc.exe which is the VB.NET compiler. On my computer it can be found here…

C:\Windows\Microsoft.NET\Framework\v3.0
C:\Windows\Microsoft.NET\Framework\v3.5
C:\Windows\Microsoft.NET\Framework\v4….
Etc.

To compile I make a batch file like so …

1
2
3
4
5
6
CD\
CD C:\Code\MS.NET\vb.net\PInvoke
Path C:\Windows\Microsoft.net\framework\v3.5
cls
C:\Windows\system32\cmd.exe
Cls


In my case above my project directory where I’m working on this stuff is…

C:\Code\MS.NET\vb.net\Pinvoke

What the above code blurb does is change the current directory to my project directory, and add a temporary PATH to the vbc compiler, so that when I try to compile the system can find vbc. Here is the command line to compile the above vb.net program if the file is named Pinvoke.vb and it is in the above directory…


vbc /r:System.dll,System.Windows.Forms.dll,System.Drawing.dll /t:winexe PInvoke.vb

You can see I have that command line remmed out at the top of PInvoke.vb. And like I said, that works perfectly. But I had great reservations about getting that to work in C or C++ because of the Calling Convention issue. I’ll discuss that next…

The issue is this….

Both PowerBASIC and .NET I believe use a parameter passing convention known as Standard Call. If you are familiar at all with Win32 coding you might have seen these entities around some functions …


WINAPI
CALLBACK

These are #defines of the C/C++ __stdcall keyword. So in C or C++ you can specify a function as __stdcall if you like, but the default calling convention of C or C++ is __cdecl or C Declaration. The difference is whether the caller or the callee releases stack memory after a function call. Otherwise these are very close. So close, in fact, that even if the wrong calling convention is specified, it’ll still work – sort of. What will happen is that there will be a small, almost un-noticable memory leak with each function call. So anyway, I made the following C++ Dll to convert the PowerBAIC code above …

1
2
3
4
5
6
extern "C" __declspec(dllexport) int AddOne(int iNumber);    // Dll

int AddOne(int iNumber)
{
 return ++iNumber;
}


That, when compiled into a dll with your favorite Windows C++ compiler, is the exact equivalent of the PowerBASIC function above, but because I didn’t specify an alternate calling convention, it will default to __cdecl. Oh! And by the way, I named the dll produced by the above code DllServer.dll. And here is the above VB program modified to use that dll’s AddOne() C++ function …

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
‘Pinvoke1.vb
'vbc /r:System.dll,System.Windows.Forms.dll,System.Drawing.dll /t:winexe PInvoke1.vb
Imports System
Imports System.Drawing
Imports System.Windows.Forms
Imports System.Runtime.InteropServices

Public Class CPP
  Declare Function AddOne Lib "DllServer.dll" Alias "AddOne" (Byval x As Int32) As Int32   
End Class

Class PInvoke
  Inherits Form
  
  Sub New()
    Me.Text="Using C++ In VB.NET"    
    Me.BackColor = SystemColors.Window
    Me.ForeColor = SystemColors.WindowText
  End Sub
  
  Protected Overrides Sub OnPaint(ByVal pea As PaintEventArgs)
    Dim br As SolidBrush
    Dim iNum As Integer

    iNum=5
    iNum=CPP.AddOne(5)
    br=New SolidBrush(SystemColors.WindowText)
    pea.Graphics.DrawString("iNum=" & iNum.ToString(),Me.Font,br,0,0)
  End Sub
End Class

Module Main
  Sub Main()
    Application.Run(New PInvoke())
  End Sub
End Module 


Note I named this program Pinvoke1.vb, and the command line compilation string is also above. Naturally, I put DllServer.dll (my C++ dll) in that project directory too. And that seems to work perfectly, even though I know for sure there is a calling convention mismatch. Every call to that function will likely leak a few bytes. So if its called millions of times in a loop there will surely be problems.

So I searched around in the .NET documentation to see if there is a way of dealing with this calling convention issue, and there is. VB.NET has a concept known as ‘attributes’. These can be prefaced to various .NET program statements to add additional information to them. There is an attribute known as DllImport where one can specify a calling convention for an external function. So here is the above program modified to specify the calling convention of the AddOne() function as __cdecl. Its Pinvoke2…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
‘Pinvoke2
'vbc /r:System.dll,System.Windows.Forms.dll,System.Drawing.dll /t:winexe PInvoke2.vb
Imports System
Imports System.Drawing
Imports System.Windows.Forms
Imports System.Runtime.InteropServices

Class PInvoke
  Inherits Form
  
  <DllImport("DllServer.dll", EntryPoint:="AddOne", CallingConvention:=CallingConvention.Cdecl)> _ 
  Public Shared Function AddOne(Byval x As Int32) As Int32
  End Function

  Sub New()
    Me.Text="Using C++ In VB.NET"    
    Me.BackColor = SystemColors.Window
    Me.ForeColor = SystemColors.WindowText
  End Sub
  
  Protected Overrides Sub OnPaint(ByVal pea As PaintEventArgs)
    Dim br As SolidBrush
    Dim iNum As Integer

    iNum=5
    iNum=AddOne(5)
    br=New SolidBrush(SystemColors.WindowText)
    pea.Graphics.DrawString("iNum=" & iNum.ToString(),Me.Font,br,0,0)
  End Sub
End Class

Module Main
  Sub Main()
    Application.Run(New PInvoke())
  End Sub
End Module 


You can find information on this issue here…

http://msdn.microsoft.com/en-us/library/aa984739%28v=vs.71%29.aspx

At this time I feel really bad I can’t get this working on 64 bit Windows 7 – even as just 32 bit binaries, but by and large, I think my treatment of this issue of calling C++ dll code from VB.NET is sound. Its working for me just fine on XP and 32 bit Win 7 (I have that at work). Maybe you can figure out the 64 bit Win 7 issue and let me know. There is probably some setting I need to add to my command line compilation string or something.

In terms of your code, I haven’t looked at it yet, but what I’ve provided should give you a start. I’d first start by trying to get these simple dlls of mine working, then move up to your code. Hope this helps!

Figured out why my code wouldn't run on Windows 7! I needed to add a /platform:x86 switch to my VB Command Line compilation string. If the C++ Dll is an x86 one, then the vb program has to be told to only compile the ILSAM in the .exe file to x86 code. For my PInvoke2.vb progam it should look like so ...

vbc /r:System.dll,System.Windows.Forms.dll,System.Drawing.dll /platform:x86 /t:winexe PInvoke2.vb

I figured to had to be something like that to work on 32 bit Win7 but not x64.
Op!
Hi Freddie1.

Can you help me run my code C++ in vb.net ?
I had said , i alway sick after read msdn.microsoft.com hic hic...
Topic archived. No new replies allowed.