Solved

translating a windows app from VB.NEt to C++/C# , or how to use the same GUI in different platforms

Posted on 2008-06-17
18
383 Views
Last Modified: 2013-11-26
We are developing a .NET DLL to control our hardware.
For this we want to provide a couple of demo applications in different programming languages.
We currently have a demo in VB.NET.

We would like to have exaclty the same application also in C++ / C#.

Is there a way to achieve this without starting all over again from scratch? can we somehow reuse the controls and their properties (size, location, settings) in another language.

0
Comment
Question by:m8online
  • 8
  • 7
18 Comments
 
LVL 10

Expert Comment

by:athapa
Comment Utility
To copy your Forms,
open both projects in separate IDEs,
open the Form you'd like to copy,
Select All from the source Form and Paste into your new form in C# (or even C++/CLI).

For your code, you could use the tools like RemoteSoft's Salamander which will convert you existing assembly (compiled dll or exe) into C# or C++/CLI source code. If all you're trying to do is Vb.Net to C# then you can use a whole bunch of free online translation of Vb.Net to C#.  Converting to C++ is slightly tricky and that's where you'd want to use tools like Salamander.
0
 
LVL 1

Author Comment

by:m8online
Comment Utility
I haven't got around to testing the GUI copying thing yet. This will probably work. Sometimes things are so simple that you just cannot see them. thanks for that.

About Salamander. I took a look at their website. It looks like a rather expensive tool.
Did you work with it yourself? What exactly does it do? will it also maintain the variable names used?

Would there also be an open source tool that does a basic translation?  It would be ok for me to have to clean up the generated code later.
0
 
LVL 10

Expert Comment

by:athapa
Comment Utility
I've use Salamander myself. If you have corresponding pdb files (generated while compiling in debug mode) for your exe or dll then all of your internal variable names will also get regenerated. Even without a .pdb files the regenerated codes are still readable. Besides Salamander there are few others commercial ones but I've not used them. There was one open source which I used long time back, Anakrino, but it hasn't been actively developed in a while.

As I mentioned before if all you need to do is Vb.net to C# then try these first before buying Salamander or other tools.
http://labs.developerfusion.co.uk/convert/vb-to-csharp.aspx
http://www.carlosag.net/Tools/CodeTranslator/
http://www.dotnetspider.com/convert/Vb-To-Csharp.aspx
http://www.kamalpatel.net/ConvertCSharp2VB.aspx

There are some windows apps too if you prefer not to use the online ones.
0
 
LVL 1

Author Comment

by:m8online
Comment Utility
I tried copy-pasting from the VB.net project to a C++ project. This did not work.
The paste action just did not work.
Would one of the suggested tools also transfer the GUI?

I am thinking that I might have the wrong approach. A C# user would probable understand the VB.NET example application. Especially because it is nothing more than some glue between a GUI and the DLL which they would actually need.

The difference between VB.NET and C++ is more of a problem because the DLL is in fact a class library. For using it in C++ (no, user would not want to compiler with /clr) it would need to be converted to a classical DLL interface.
For this I am working on a wrapper DLL in C++ which would make an instance of the class and couple its member functions to the classical DLL interface.
This classical DLL could also be used from VB.net. So I could adapt the example app. to work with the two different DLL interfaces.

Current problem is that I cannot get the wrapper DLL to compile correctly.
In the code below the class CL_IO_ctrl is not recognized.

Any ideas?
// M8_IO_ctrl_classic.cpp : Defines the initialization routines for the DLL.

//

#using "C:\temp\IO_Ctrl\USB_IO_211_demo_app\V1_0_0\bin\M8_IO_ctrl.dll"

#include "stdafx.h"

#include "M8_IO_ctrl_classic.h"
 

#ifdef _DEBUG

#define new DEBUG_NEW

#endif
 

#define API_EXPORT __declspec(dllexport)
 

//

//	Note!

//

//		If this DLL is dynamically linked against the MFC

//		DLLs, any functions exported from this DLL which

//		call into MFC must have the AFX_MANAGE_STATE macro

//		added at the very beginning of the function.

//

//		For example:

//

//		extern "C" BOOL PASCAL EXPORT ExportedFunction()

//		{

//			AFX_MANAGE_STATE(AfxGetStaticModuleState());

//			// normal function body here

//		}

//

//		It is very important that this macro appear in each

//		function, prior to any calls into MFC.  This means that

//		it must appear as the first statement within the 

//		function, even before any object variable declarations

//		as their constructors may generate calls into the MFC

//		DLL.

//

//		Please see MFC Technical Notes 33 and 58 for additional

//		details.

//
 

// CM8_IO_ctrl_classicApp
 

BEGIN_MESSAGE_MAP(CM8_IO_ctrl_classicApp, CWinApp)

END_MESSAGE_MAP()
 

 	 class Cl_IO_ctrl IO_ctrl;
 
 
 

// CM8_IO_ctrl_classicApp construction
 

CM8_IO_ctrl_classicApp::CM8_IO_ctrl_classicApp()

{

// TODO: add construction code here,

	// Place all significant initialization in InitInstance

}
 
 

// The one and only CM8_IO_ctrl_classicApp object
 

CM8_IO_ctrl_classicApp theApp;
 
 

// CM8_IO_ctrl_classicApp initialization
 

BOOL CM8_IO_ctrl_classicApp::InitInstance()

{

	CWinApp::InitInstance();
 

	return TRUE;

}

Open in new window

0
 
LVL 10

Expert Comment

by:athapa
Comment Utility
I tried copying vb.net form from the designer and paste in c++.
Here is what I did.
Open the vb.net solution.
Add a new c++ clr project
Open the form that needs to be copied in design mode.
Ctrl+A to copy all elements of the form
Add a new form in c++ file in cpp project
Go to design view of the new form
Ctrl+V to paste

But the method above or any of the tools mentioned previously will only work if you are trying to create c++/clr executables (or dll). If you are trying to use mfc or other framework for your ui then this method won't work.

If I understand you correctly then you're trying to create a wrapper for some 3rd party c++ component which (the wrapper) you'd like to use in dotnet applications. Is this correct? If so, do you need to use those component in c++ applications too?

0
 
LVL 1

Author Comment

by:m8online
Comment Utility
No, it is the other way around.

I have created a class library DLL in VB.NET, and a VB.NET example app to show how to use this class library.

Now I want this class library also to be accessible to C++ apps.
I know that if C++ is compiled managed for .NET (/clr) it should be able to use a class library directly. However, as my customer wants his C++ environment to remain unmanaged, this is not an option for him.

Therefore I am trying to create a wrapper for the  class library. I Guessed the wrapper should be written in managed C++ and then expose al the member functions in the classical DLL way.

Then, because I am trying to avoid having more than one example app. I would use the same VB.NET example app, only now using the classical (GetProcaddress like) way to access the functions.
0
 
LVL 10

Expert Comment

by:athapa
Comment Utility
If you can, read this book
Expert C++/CLI:
.NET for Visual C++ Programmers

This book covers a lot of topic about manged code accessing unmanaged codes and vice versa.

I'm not sure if you'll be able to load vb.net classes using loadlibrary and getprocaddress. It probably would be easier for you to create a wrapper in c++ instead.

Your other alternative would be to use comvisible attribute in your vb.net class and access the class as com from c++.

Here is another approach but it seems convoluted.
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 1

Author Comment

by:m8online
Comment Utility
Yes, Writing a wrapper DLL was indeed the way I wanted to go.

The problem which I am having with the wrapper DLL is that at the moment I cannot get it to recognize the VB.net managed class library.

I added the /CLR compiler switch
I added the VB:net managed DLL to "references"

Still the compiler says: undefined class: Cl_IO_ctrl
0
 
LVL 10

Expert Comment

by:athapa
Comment Utility
I forgot to paste the link in the last post.
Anyway, check this link.
http://www.codeproject.com/KB/dotnet/bridge.aspx

Depending upon the .net framework you're using c++/clr wrapper would be slightly different. The new framework (2.0+) uses slightly different syntax (such as difference in ~ and ! and a new ^, etc.) . One of the comment in the above article also takes a bit about the differences.

Can you post your wrapper code or section of it?

0
 
LVL 1

Author Comment

by:m8online
Comment Utility
I did post the code which I had earlier in this topic. But I don't think it will tell you a whole lot because the only actual piece of code which I added myself is the declaration of an object which should be taken from the managed class library.

Meanwhile I have been doing some more experimenting and managed to at least get a managed C++ application to compile in such a way that the imported class got recognized. I was hoping that I could convert this to a DLL project later on.

The problem I am having now, is that I am not allowed to declare a managed object as global.

In the bridge example (http://www.codeproject.com/KB/dotnet/bridge.aspx)  the bridging functions create an instance of the managed class each time when they are called. Then when the bridge function returns the object is disposed.

I cannot use this principle for my class as it also has data members which need to be retained. Therefore I would need to create an instance (object) of the managed class when calling some init function and do not dispose it before the application ends.
The most logical way I could think of to do this would be to declare a global pointer to an object from the managed class library. Which is not allowed.
Is this possible in some other way?
0
 
LVL 1

Author Comment

by:m8online
Comment Utility
By the way: @athapa.

I just ordered the book you mentioned. It looks very useful. Thanks!
0
 
LVL 10

Expert Comment

by:athapa
Comment Utility
You may have already resolved your issues. Anyway, I tested a simple program where a c# class is wrapped in c++ managed class. The c++ managed class is then accessed using loadlibrary in another pure c++ application. I was able to call the managed functions multiple times and retain the state (i.e. I didn't have to recreate managed object in every function calls).  In the c++ bridge, I added a static managed object. But you need to make sure you don't instantiate the managed object inside constructor or DLL_PROCESS_ATTACH/DLL_THREAD_ATTACH in DllMain.
0
 
LVL 1

Author Comment

by:m8online
Comment Utility
No, in fact I am still working on it. I though I should read some chapters of the book before continuing. I just got it last week.

 Could I take a look at your source code?

I managed to get a static instance of the class using the GCroot. Now I am kind of stuck on how to connect the callback functions. The problem here is that I would want to create objects inside the wrapper handling the callbacks from each object in the managed world. Only you cannot use a method as a callbackfunction directly.
I took a look at functors, but they need such complicated code that I do not know if I will want to use those.
0
 
LVL 10

Accepted Solution

by:
athapa earned 250 total points
Comment Utility
not the best possible code but it works.

managed.dll is written in c#
bridge.dll is written in c++ managed/unmanaged which wraps managed.dll
test.exe is written in c++ unmanaged which uses bridge.dll (class written in c# indirectly).


//BEGIN----------------------------managed.dll-------------------------
 

//managed.cs

//managed class in c#

using System;

using System.Collections.Generic;

using System.Text;
 

namespace managed

{

    public class test

    {

        private static test instance = null;

        private int value1 = 0;
 

        public test()

        {

            return;

        }

        

        public void Method1(int val)

        {

            value1 += val;

        }

        public int Method2()

        {

            return value1;

        }

    }

}
 

//END----------------------------managed.dll-------------------------
 

//BEGIN--------------------------bridge.dll--------------------------
 

// stdafx.h

//-------------

#include "gcroot.h"

#using <mscorlib.dll>

#using <managed.dll>

#pragma once
 

#include <windows.h>

//----------------
 

//stdafx.cpp

//----------------

#include "stdafx.h"

//----------------
 

//managed_bridge.h

//----------------

#include "gcroot.h"

#ifdef BRIDGE_EXPORTS

#define BRIDGE_API __declspec(dllexport)

#else

#define BRIDGE_API __declspec(dllimport)

#endif
 

class BRIDGE_API Cbridge {

private:

	//

	gcroot<managed::test^> t;

public:

	Cbridge(void);

	~Cbridge(void);

	bool Initialized;

	void fnInitialize(void);

	void fnMethod1(int val1);

    int fnMethod2(void);

};

//----------------
 

//managed_bridge.cpp

//----------------

#include "stdafx.h"

#include "managed_bridge.h"
 

void Cbridge::fnInitialize(void)

{

	t = gcnew managed::test();

	Initialized = true;

}
 

int Cbridge::fnMethod2(void)

{

	return t->Method2();

}
 

void Cbridge::fnMethod1(int val1)

{

	t->Method1(val1);

}
 

Cbridge::Cbridge(void)

{

	Initialized = false;

	return;

}
 

Cbridge::~Cbridge()

{

	delete t;

	return;

}

//----------------
 

//unmanaged_bridge.h

//----------------

#include "managed_bridge.h"

#pragma unmanaged
 

static Cbridge* cb;

static bool Initialized;

static void fnInitializeIfNeeded(void);

//----------------
 

//unmanaged_bridge.cpp

//----------------

#include "stdafx.h"

#include "unmanaged_bridge.h"
 

#ifdef _MANAGED

#pragma managed(push, off)

#endif
 

BOOL APIENTRY DllMain( HMODULE hModule,

                       DWORD  ul_reason_for_call,

                       LPVOID lpReserved

					 )

{

	switch (ul_reason_for_call)

	{

	case DLL_PROCESS_ATTACH:

		//DONOT CREATE ANY MANAGED INSTANCES HERE

		//if (cb == NULL)

		//	cb = new Cbridge();

	case DLL_THREAD_ATTACH:

		//DONOT CREATE ANY MANAGED INSTANCES HERE

		//if (cb == NULL)

		//	cb = new Cbridge();

	case DLL_THREAD_DETACH:

		/*if (cb != NULL)

			delete cb;*/

	case DLL_PROCESS_DETACH:

		//if (cb != NULL)

		//	delete cb;

		break;

	}

    return TRUE;

}
 

#ifdef _MANAGED

#pragma managed(pop)

#endif
 

extern "C" int WINAPI fnMethod2(void)

{

	fnInitializeIfNeeded();

	return cb->fnMethod2();

}
 

extern "C" void WINAPI fnMethod1(int val1)

{

	fnInitializeIfNeeded();

	cb->fnMethod1(val1);

}
 
 

static void fnInitializeIfNeeded(void)

{

	if (!Initialized) 

	{

		if (cb == NULL)

			cb = new Cbridge();

		cb->fnInitialize();

		Initialized = true;

	}

	return;

}

//----------------
 

//END----------------------------bridge.dll--------------------------
 

//BEGIN--------------------------test.exe----------------------------

//Pure unmanaged class which will use the bridge
 

//stdafx.h

//----------------

#pragma once

//----------------
 

//stdafx.cpp

//----------------

#include "stdafx.h"

//----------------
 

//test.cpp

//----------------

#include "stdafx.h"
 

#include <afx.h>

#include <afxwin.h> 

#include <afxext.h> 
 

#include <windows.h>
 

#include <string>

#include <iostream>
 

using namespace std;
 

typedef void (WINAPI *fnMethod1)(int val1);

typedef int (WINAPI *fnMethod2)(void);
 

int _tmain(int argc, _TCHAR* argv[])

{

	USES_CONVERSION;
 

	HMODULE m;
 

	MessageBox(NULL,_T("Loading library"),_T("Loading"),0);
 

	m = LoadLibrary(_T("bridge.dll"));

	if (m != NULL)

	{

		fnMethod1 fnM1 = (fnMethod1) GetProcAddress (m, "fnMethod1");

		if (fnM1 != NULL)

		{

			fnMethod2 fnM2 = (fnMethod2) GetProcAddress (m, "fnMethod2");

			if (fnM2 != NULL)

			{

				//test the functions
 

				int val1=0;				

				char *val2;

				wchar_t *val3;

				int len;
 

				val2 = new char[20];
 

				//call the functions few times

				fnM1(50);

				val1 = fnM2();

				//first time the value returned from fnM2 is 50

				itoa(val1,val2,10);

				val3 = A2W(val2);

				MessageBox(NULL,val3,_T("Val1"),0);
 
 

				fnM1(20);

				val1 = fnM2();

				//second time the value returned from fnM2 is 70 (50+20)

				//so the object is presisting beyond one call

				itoa(val1,val2,10);

				val3 = A2W(val2);

				MessageBox(NULL,val3,_T("Val1"),0);

				

				delete val2;

			}

		}

		FreeLibrary(m);

	}

	return 0;

}

//----------------
 

//END----------------------------test.exe----------------------------

Open in new window

0
 
LVL 1

Author Comment

by:m8online
Comment Utility
Hello All,

Just to let you all know.
I am still working on this, but time pressure on some other project forces me to put it on hold regularly.
I will keep you informed on any new progress.
0

Featured Post

Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

Join & Write a Comment

Recently while returning home from work my wife (another .NET developer) was murmuring something. On further poking she said that she has been assigned a task where she has to serialize and deserialize objects and she is afraid of serialization. Wha…
Welcome my friends to the second instalment and follow-up to our Minify and Concatenate Your Scripts and Stylesheets (http://www.experts-exchange.com/Programming/Languages/.NET/ASP.NET/A_4334-Minify-and-Concatenate-Your-Scripts-and-Stylesheets.html)…
THe viewer will learn how to use NetBeans IDE 8.0 for Windows to perform CRUD operations on a MySql database.
The viewer will learn how to synchronize PHP projects with a remote server in NetBeans IDE 8.0 for Windows.

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now