Convert C++/MFC from visual studio.net 2002 to visual studio 2010 - c++

We will convert a number of programs written in C++ and MFC in Visual Studio.NET 2002 to Visual Studio 2010. What problems can we expect to encounter? What changes are there in the libraries that are worth knowing?

MFC has had a number of breaking changes over those releases. All the changes are documented on MSDN, and usually they're pretty straightforward - function signature changes and the like (which can often be fixed simply by inspecting the compiler error message and working out what it wants instead).

I've been through this moving a project to VS 2008 and the two big ones were the "secure CRT" functions and the for loop scope change. (I can't remember precisely when that happened, but it might affect you.) Basically the compiler is your friend ... build the whole thing and it will find the problems, which you can then fix. You can suppress the secure CRT warnings but you might as well get them taken care of.
I'm not aware of any "I'm happy to compile but I won't do quite what I used to do at runtime, thus ruining your world" breaking changes in MFC or C++ over the last decade. So once you make the compiler happy you should be confident your app still works.

dynamic_cast will behave differently at runtime
class A
{
}
class B : public A
{
}
class C : public A
{
}
//...
C* c = new C();
//This used to work, i.e. didn't return NULL, with 2002
B* b = dynamic_cast<B*>(c); //... won't work any more --> returns NULL.

Related

DLL fails to load if unused ref class is removed

I'm running into a very strange problem trying to compile and use a windows runtime component within an UWP application (VS2017 community 15.9.13 with NetCore.UniversalWindowsPlatform 6.2.8, compiled without /clr but with /ZW).
It is basically something like the Grayscaletransform. The runtime component is actually working as expected, now I wanted to remove some unused code. However, as soon as I remove it from a particular file and recompile, it indeed compiles, links, but the DLL does not load any more.
Here's some example code that I have to put in:
ref class DummyU sealed
{
public:
DummyU() {}
};
DummyU^ CreateDummyU()
{
return ref new DummyU();
}
The code just makes it work, although it is a) not referenced at all and b) does not do anything useful.
The result of removing it:
Exception thrown at 0x0EFF322F (vccorlib140d_app.dll) in TestAppUWP.exe: 0xC0000005: Access violation reading location 0x00000000.
in
STDAPI DllGetActivationFactory(_In_ HSTRING activatibleClassId, _Deref_out_ IActivationFactory** ppFactory)
{
return Platform::Details::GetActivationFactory(Microsoft::WRL::Details::ModuleBase::module_, activatibleClassId, ppFactory);
}
function in dllexports.cpp which is part of VS. The module_ becomes NULL.
Does anyone have an idea if there are any known bugs with respect to the windows runtime not being initialized/used properly if there is no explicit instantiation of a ref class in a file?
EDIT 1:
Here's the link to the full source code:
What's happening here is that you're mixing modes a bit. Since you've compiled your C++ code with the /CX flag, you've told the compiler to enable winrt extensions to produce a WinRT DLL. In practice though, none of your code is actually using the CX extensions to implement classes. You're using WRL and standards C++. The compiler looks at the DLL, finds no CX-style WinRT classes, and doesn't set up the module, accordingly.
This is basically an untested & unsupported case, since you've chosen to say that you want to expose ref classes by picking a UWP component library project type, but then didn't actually provide any ref classes. It happens that under the hood, /CX effectively uses WRL, so you can nudge it along and initialize the state to work correctly, but you're kinda hacking the implementation details of the system.
There are two options I would recommend, either works: just make the project a non-CX Win32 DLL and init the module as described above. Or, better yet, flip over to C++ /WinRT, which will give you better support for the WinRT types than /CX and allow you to more easily mix in the classic COM types in your implementation. You can get started by just turning off the /CX flag in the compiler switches, then start updating the code accordingly.
Ben
You might have wrong .winmd file for your component. WinRT components made in C++ produce two outputs, dll and winmd. Both must match. It's possible you have them from different builds.
Another possible reason is error in manifest. The manifest of the app must include all referenced runtime components.
BTW, for native DLLs written in classic C++ and exposing C API, deployment is simpler, you include a DLL in the package and they just work, with [DllImport] if you're consuming them from C#.
Update: You can replace that ref class with the following code, works on my PC.
struct ModuleStaticInitialize
{
ModuleStaticInitialize()
{
Microsoft::WRL::Module<Microsoft::WRL::InProc>::GetModule();
}
};
static ModuleStaticInitialize s_moduleInit;
Probably a bug in Microsoft's runtime somewhere.

How to teach Visual Assist to assist me with smart pointers?

We usually define classes that are often used like this:
class SomeClass
{
// Some code here
};
typedef std::shared_ptr<SomeClass> SomeClassPtr;
Because frankly having to type std::shared_ptr<SomeClass> every time is a suicide.
However Visual Assist, addon that my company paid for on top of Visual Studio, cannot cope with either SomeClassPtr or std::shared_ptr<SomeClass> and give member suggestions. Strangely though, I noticed that it handles QPointer<SomeClass> without any problems and gives SomeClass member suggestions as expected.
I noticed that status bar shows these two messages after I type pointer-> (right after typing > character):
IntelliSense: 'No additional information available' (See 'Troubleshooting IntelliSense in C++ projects' for further help.)
Which is weird because IntelliSense (I prefer to call it DumbSense) is turned off. Second message that appears only for 200ms:
VA X: Parsing D:\ ... \myFile.cpp
myFile.cpp here refers to the file being currently edited.
Can I do anything at all to teach Visual Assist to properly give suggestions on std::shared_ptr smart pointers?

VS2015 C++ static initialization crash, possible bug

I'm seeing something weird happening with Visual Studio 2015 Community. Code that worked perfectly in VS2012 crashes at startup when ported to VS2015, before main is invoked: the classic symptoms of some static initialization mess. I have a few static variables, but used properly, with the standard "Construct On First Use" pattern, e.g.:
const int& i()
{
static int *v = new int(1);
return *v;
}
The code above causes an assert from the runtime while initializing the program (see image http://i.stack.imgur.com/nsQGS.png). Pressing retry simply quits the program: no call stack, no information whatsoever.
The code below however works flawlessly:
const int& i()
{
static int *v = nullptr;
if (v == nullptr)
v = new int(1);
return *v;
}
It seems to me that VS2015 is doing what looks like some (illegal) optimization (even in a debug build), by executing the static variable initialization code during program initialization, and not the first time that the function is called, as the C++ standard requires.
I tried several variations of the code above: class methods, free functions, different objects (std::vector, cv::Mat), always with the same result: the static pointer has to be initialized to null or the program doesn't start.
So... am I missing something or is VS2015 actually messing up badly?
UPDATE:
I spent some time trying to find the minimal setup that shows the problem, and this is what I got:
create a project using the "CLR empty project" template.
add a cpp file, containing just the offending function and main(). Main can be empty, it doesn't matter: the bug occurs BEFORE it is even reached.
add 'main' as entry point (or you get a link error).
The x86 version works, but the x64 doesn't.
For comparison, a project with the identical code but created as "Win32 console application" doesn't have the problem, even after adding the /CLR option. I can see differences in the vcxproj files, but none justifies the error, although one or more of them clearly IS the cause.
Is there a way to upload a zip with the project?
Well, #bogdan got it right. My project had a mix of settings that was neither /SUBSYSTEM:CONSOLE nor /SUBSYSTEM:WINDOWS. Once I fixed that, everything started to work as expected. My test projects had the same problem, I blame Microsoft for not having a clear "CLR windows app" C++ template any more in VS2015 (they want to push you to use C# for that, which makes sense most of the times, but not always).
I found this page particularly useful in explaining all the different settings that have to be consistent (it's not just /SUBSYSTEM...).
I wish I could mark #bogdan's comment as answer, but I can't see anything to do that.
Thanks Bogdan!

Upgrade to VS2012 resulting in crash due to different VC++ runtimes?

There is a large legacy project I have to maintain, which I recently upgraded from Visual Studio 2008 to Visual Studio 2012. As it is a COM server and a OCX control, creating all the typelib stuff etc. resulted in some problems that I managed to solve. However, when I run the Release build now I frequently get crashes.
I followed some advise I found here on SO and was able to track down the crash to the following piece of code:
int Phx2Preview::ClearOvlElementList() {
for (int i = 0; i < (int)m_vOvlElements.size(); i++) {
P_SAFE_DELETE(m_vOvlElements[i].pPolyOrig); // <- code crashes here
P_SAFE_DELETE(m_vOvlElements[i].pPolyDispl);
}
m_vOvlElements.clear();
m_vRefElemList.clear();
m_pRefElemSelected = NULL;
return PHXE_NO_ERROR;
}
P_SAFE_DELETE is a macro that checks if the pointer is null, and in case it's not deletes and sets it to null. The actual vector elements are created like this:
if (v1) {
tNew.pPolyOrig = new CInPolygon();
tNew.pPolyDispl = new CInPolygon();
tNew.pPolyOrig->FromSafeArray(v1);
tNew.pPolyOrig->Rotate(NULLPOINT, m_nTurnAngle*__pi/180.);
tNew.eType = (overlayET)type;
tNew.nImagenr = nImageNr;
m_vOvlElements.push_back(tNew);
}
Now, the thing is that CInPolygon is a class from an external library which is created with Visual C++ 7.1. The P_SAFE_DELETE is also defined in a header from that library. From here I know that mixing different runtime versions is bad, and this question lets me suspect that this mixing may be responsible from the crash.
My question is: Why does it happen? After all, since both new and delete are called from the same place, no actual objects are passed between the different CRTs. Also, when the OCX is compiled using Visual Studio 2008, no problems occur. Is this due to pure luck? I guess the basic issue is existing in that setting, too. And, well, what can I do to solve to problem? Switch back to VS2008?
Edit:
As asked: The destructor of CInPolygon is just
CInPolygon::~CInPolygon(void) {
m_vPoints.clear();
}
here the m_vPoints is a std::vector<..> defined in the class. Maybe I should mention that CInPolygon inherits from that:
interface IRoi {
virtual ~IRoi() {
return;
}
public:
// other stuff
};
(Didn't even know that interface was a valid keyword in plain C++...) Could it be that the fact that the base class destructor is defined in the header is causing the problem? After all, that header is also known to the host programm..
tNew.pPolyOrig = new CInPolygon();
Yes, this is guaranteed to fail. Short from having different allocators in your program, your host program cannot possibly compute the size of the CInPolygon object correctly. It uses an entirely different implementation of std::vector. It was significantly rewritten in VS2012 to take advantage of C++11. Inevitably, the code in the library using the old version of vector will corrupt the heap.
You must rebuild the library as well, using the exact same version of the compiler with the exact same settings.

Can a CString be safely treated like it was a simple type and not a class, in Visual C++ 6.0 MFC?

Unfortunately the documentation I have is either (a) original product documentation without any errrata (MS VC++ 6.0 help files) or (b) later MSDN help that applies to later MFC versions.
In particular:
[Q1] Is the operator += known to be buggy in VC++6 MFC CString? This code from VC++6 had to be fixed before it would even compile in a modern MFC app:
CString szTemp;
unsigned char m_chReceive[MY_BUF_SIZE];
// compiles and seems to run but may be buggy in VC++6, won't compile in modern MFC
szTemp += m_chReceive;
// the above won't compile in modern MFC versions, but this "&+cast" does:
szTemp.Append( (const char *)&m_chReceive[0]);
[Q2] Is it safe and robust to return a CString as the result of a function, in this manner, or does this cause memory corruption?
CString MyClass:MyMethod(void)
{ CString Stuff;
// set a value to Stuff here.
return Stuff; // return a stack-allocated-CString
}
I have code that uses the above two things all over the place and which also seems to exhibit random runtime memory corruption. Those two things are red flags to me, am I right in suspecting that CString was intended by the authors of MFC in Visual C++ 6.0 to be nice simple thing that you could use like it was an int or a char type, and return it from a function and somehow copy constructors and memory management all just worked?
Obvious stuff: Yes of course I will get all my code off VC++ 6.0 when I can, but I first need to patch a production system which is crashing, and then I can begin the huge task of moving this legacy codebase forward.
According to Documentation for VC6.0
CString objects can grow as a result of concatenation operations.
CString objects follow “value semantics.”
Microsoft Documentation seems to indicate that CString in purpose is similar to std::string in that it grows automatically when needed, and can be safely be passed around as arguements or return values of functions.