Making applications using Visual Studio 2005
As part of my PhD I needed to build some quick and dirty Windows GUI applets, and Visual Studio 2005, which was already being used seemed a logical choice. One advantage is the ease of building GUIs.
The disadvantage is that the Visual Studio is oriented around producing .NET style C++ with object instances being created in managed memory. Much of the code I wanted to interface with was unmanaged code, eg open source libraries. I needed to produce code which was partly .NET code and partly classic C++, and the documentation was unhelpful, so here are a few observations and code snippets.
Debugging mixed .NET and conventional code
The 'debugging' section of the Visual C++ projects property pages includes a 'Debugger type' with a default setting of auto. This is not the right setting for code that is a mix of managed and unmanaged code and 'mixed' should be used instead.
Auto means that it can debug (ie add breakpoints, single step, view variable values) when the code is of the same style as the top level application (which might be .NET/managed or unmanaged), but cannot for the other code type. Mixed ensures it can do both.
Conversion between managed and unmanaged data
There is no problem for simple ints and bools. The problems start with strings, where in .NET the string is held in managed memory.
Some code examples on the internet do not work, so beware!. I ended up using the following pieces of template code successfully.
.NET string to std::string
This is particularly useful if a simple .NET dialogue box is being used to return strings to a conventional C++ core application. Note that the 'Marshal' function returns a pointer to memory that must be freed.
using namespace System::Runtime::InteropServices;
std::string ConvToString(System::Object^ L)
{
if (L == nullptr)
return "";
IntPtr v = Marshal::StringToHGlobalAnsi(L->ToString());
std::string retvalue((char*)v.ToPointer());
Marshal::FreeHGlobal (v);
return retvalue;
}
Getting data in and out of the registry
While the windows API can be used directly for doing this, using .NET allowed the code to be kept to a simple mix of classic and managed C++
using namespace System::Runtime::InteropServices;
using namespace Microsoft::Win32;
void SaveInRegistry(const char * name,const std::string value)
{
RegistryKey^ regKey = Registry::CurrentUser->OpenSubKey(KEY,true);
if (regKey == nullptr)
regKey = Registry::CurrentUser->CreateSubKey(KEY);
regKey->SetValue(gcnew String(name),gcnew String(value.c_str()));
regKey->Close();
}
std::string GetFromRegistry(const char * name)
{
RegistryKey^ regKey = Registry::CurrentUser->OpenSubKey(KEY);
if (regKey == nullptr)
return "";
System::Object^ L = regKey->GetValue(gcnew String(name));
std::string value(ConvToString(L));
regKey->Close();
return value;
}
Problems with the OpenFileDialog box and Vista
I created a .NET dll which included an OpenFileDialog box, and while it ran correctly on XP, would hang on Vista when an attempt was made to use the dialog box. I was not alone in finding this problem:
http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.general/2008-10/msg00308.html
It looks as if the problem can arise if the dialog box is called from a console application, or when it is a dll that is called from an old application. I suspect that it is the lack of manifest information in the top level application that is at the root of the problem.
Fortunately, there is a simple solution: In the 'properties' for the dialog box object switch 'AutoUpgradeEnabled' to false.