VC10 Compiler Porting
Introduction
3ds Max 2013 has been upgraded to use version 10.0 of the Microsoft C/C++ compiler. This is the compiler that comes with Visual Studio 2010 Service Pack 1. Plug-in developers can now use Visual Studio 2010 with Platform Toolset vc100 to compile their projects. This document is a guide for upgrading plugins to compile with Visual Studio Service Pack 1.
Breaking Changes in 3ds Max
With the introduction of VC 10.0 there were few breaking changes in the max code base. These are specific, or mostly specific to the 3ds Max code base. Simple issues such as adding includes will not be discussed here are they are simple to diagnose, and already described on the MSDN.
Renamed ParamTags::end
to ParamTags::p_end
Inside of ParamType.h
is an enum called ParamTags
with an enumerator called end
. This conflicts with new symbols in the STL std
namespace. For instance,
1> ...\xmlmtlexporter.cpp(233): error C2872: 'end': ambiguous symbol
1> could be '...\paramtype.h(665): ParamTags end'
1> or 'end'
The compiler is not going to show what the conflicting symbol is. However this is caused by adding a 'using namespace std
' declaration in a header file. It is generally not recommended to add a using namespace declaration in a header file. Also, the symbol name 'end' was too generic, so the enumeration was renamed to avoid potential conflicts here and in the future.
Small block heap no longer supported
The C Runtime (CRT) header file malloc.h
no longer declares nor defines the functions \_get_sbh_threshold
or \_set_sbh_threshold
. As such, any usage of these functions should be removed.
STL Set Iterators are all const
The C++ Standard Template Library in VC 10.0 no longer supports non-const
iterators for sets and hash_sets
. Thus, the std::set<>::iterator
behaves identically to the const_iterator
.
In particular, de-referencing the iterators will now return const types instead of non-const
types. For instance, the following code may no longer work for an std::set
iterator.
MyType& t = *it;
Instead, you would have to make the type const
.
const MyType& t = *it;
You could alternatively perform a copy using the assignment operator, and drop the reference symbol.
MyType t = *it;
To ensure that iterators are not altered within a loop, only const
methods can be called on const
types. Because set and hash_set is keyed on the type itself, performing non-const operations on the instance is now forbidden.
// Avoid the following for an iterator 'it':
(*it)->changeThis();
// Proper call of a const method:
(*it)->MyConstMethod();
One way to fix this is to make the method declaration const. For instance, the virtual method SelectFilterCallback::IsFiltered
in maxapi.h
was not const
and failed to compile because the filters were stored in a set, and iterated using iterators. Changing this method to const enabled the code to compile properly. Note however that the compiler does not always flag such instances as issues. For instance, the following code compiles properly:
const AnimatableNotifierPtr& pNotifier = (*it);
pNotifier->SetOwnerSet(NULL);
In cases where the iterator will be modified, a useful alternative to std::set<>
is std::map<>
. For instance, a hash_set can be replaced by a hash_map.
Named Template Parameters
Passing in arguments to functions through the template type instead of the normal function parameter list is no longer supported. The following example illustrates the proper use of templates.
// Wrong: the 'AccumulatorType wholeScale' is included in the template definition.
template <class AccumulatorType, class DataType, AccumulatorType wholeScale>
static inline void scale(const DataType *source, int sourceCount, DataType *dest, int destCount) {
//...
}
// Correct: the 'AccumulatorType wholeScale' is a parameter in the scale() function.
template <class AccumulatorType, class DataType>
static inline void scale(const DataType* source, int sourceCount, DataType* dest, int destCount, AccumulatorType wholeScale) {
// ...
}
.NET 4.0
Previous versions of 3ds Max used a range of .NET 2.0 and .NET 4.0 functionality. 3ds Max 2013 now only uses .NET 4.0.
Possible Compiler Errors
The following is a list of frequently encountered compiler errors encountered while porting 3ds Max to the VC 10.0 compiler.
error C2678 - std::set<>::iterator
is now const; it cannot have non-const methods invoked on it.
binary '=' : no operator found which takes a left-hand operand of type 'const <type>' (or there is no acceptable conversion)
Operations such as the following ones are therefore disallowed:
// Will not compile:
MaterialTemplates::iterator p = MaterialTemplates::msTemplates.find(info.mID);
*p = info;
error C2872 or error C2664 - ParamTags::end
was renamed to ParamTags::p_end
in paramtype.h
.
error C2872: 'end' : ambiguous symbol
could be '<filepath> : ParamTags end'
or 'end'
error C1189 - The use of \#define _WIN32_WINNT 0x0400
targets Windows 95 and below. Note that 3ds Max is not supported on Windows 95, nor Windows 98, nor Windows 2000. Plugin developers should adhere to \#define _WIN32_WINNT 0x0502
(MaxWindowsVersion.h in the sdk), corresponding to Windows XP Service Pack 2.
fatal error C1189:
#error : This file requires _WIN32_WINNT to be #defined at least to 0x0403. The value 0x0501 or higher is recommended.
error C2440 - This may occur if you are attempting to pass a NULL or zero (0) value to an STL method or constructor which requires a real pointer. Note that the keyword nullptr
has been introduced in VC 10.0 to account for null value instantiations.
error C2440: 'initializing' : cannot convert from 'int' to 'StPathObject *'
For example, an std::map
can be defined in the following way:
std::map<int*, int*> mymap;
If you tried to insert NULL into it, the compiler would complain with the warning above.
// Will not compile:
mymap.insert(std::pair<int*, int*>(NULL, NULL));
Similarly, defining a standard pair is also invalid:
// Will not compile:
std::pair<int*, int*>mypair(NULL, NULL);
Both of these approaches can be fixed by passing in properly typed arguments. For instance, you can now pass in nullptr
.
// Will compile:
mymap.insert(std::pair<int*, int*>(nullptr, nullptr));
error C2039 - Resolved by using boost version 1.44 or newer.
1> ...\file.hpp(141): error C2039: 'unchecked_copy' : is not a member of 'stdext'
This is documented by Microsoft as a breaking change, where it says "In the <algorithm> header, the checked_* and unchecked_* functions are removed".
Possible Linker Errors
error LNK2019 - A result of linking against libraries which contain STL code compiled with VC 9.0.
error: LNK2019: unresolved external symbol "__declspec(dllimport) public:class std::basic_string<whcar_t,struct std::char_traits<wchar_t>,..."
error LNK2005 - Occurs with DLLs which make extensive use of MFC. Ensure that stdafx.h is included first at the top of every .cpp file in the project. Consult the knowledge base article on Microsoft: http://support.microsoft.com/kb/148652.
error: LNK2005: _DllMain@12 already defined in MSVCRTD.LIB (dllmain.obj)