G
Guest
Me and my colleagues have been working on a problem since yesterday and can’t
seem to find a solution to it. It relates in a good measure to iterators and
the way we’re using them in our project. I will first give you a little
introduction to our main task. We had at our hands entire modules which were
written in C++. These were to communicate with a stack written in C, and in
turn act as a layer between the C code and C# code used in another
application.
Whoever had developed the C++ code, was building it using makefiles in the
cygwin shell, as the condition then (for whatever reasons) had been that the
code remains ANSI compatible. So the C++ code was being built using
compilers/linkers for cygwin, cygmingw, and vc7.1. A free tool called SWIG[0]
was being used to generate an export file to be compiled with the C++ code as
well as a full C# wrapper of all the C++ classes and functions. (Essentially
SWIG generates a flattened interface to all the C++ classes and then builds
the objects in C# and uses pinvoke with a pointer to access the C++ classes).
In our main C# application, we references these C# wrapper dlls in projects
depending on the functionality and all seemed to work.
Recently though, our project team decided that we should have all the code
in the Visual Studio environment, and we felt strongly that it would enable
us to debug the unmanaged code, if there is a need to, and thus have better
control over code maintainence. Furthermore, we decide to move over to the
VC8.0, which seemed the most logical thing to do.
Implications – First of all, we felt that the effort involved in translating
the makefile script to VS properties was considerable. Even though the
makefiles were done very intelligenty, they also had very specific
instructions, and these were often masked under many layers of variables. A
lot of time and energy led us finally to having a VS 2005 solution with all
the C++ projects, their corresponding C++ test console applications, C#
projects which contained the files automatically generated with SWIG, and
finally the C# unit test projects to test these C# projects.
In addition, we could also debug down to the C++ code, which was
encouraging. We were able to generate the C++ dlls and the C# wrapper dlls as
cygwin. However, with the test modules, we have run into this seemingly
unsolvable problem.
This test aims first at establishing a connection with a server on a real
device and then to compare some characteristics with it. The error we get is:
Debug Assertion Failed!
Program: C:\....\Test.exe
File: C:\Program Files\Microsoft Visual Studio 8\VC\include\xtree
Line: 293
Expression: map/set iterators incompatible
For information on how your program can cause an assertion failure, see the
Visual C++ documentation on asserts.
(Please Retry to debug the application).
As for the code samples, please bear in mind the following:
1. We are using the following typemaps
// Kind of cached item.
enum RefKind {...};
// Vector of cached items of the same kind.
typedef std::vector<string> RefsVec;
typedef std::map<RefKind, RefsVec> KindRefsMap;
typedef std::map<CoreTypes::ObjectName, KindRefsMap> LN2KindMap;
typedef std::map<CoreTypes::ObjectName, LN2KindMap> LD2LNMap;
2. LD2LNMap is instantiates as:
// Cache for References (names). Created per LD the first time a
// directory service is called for an element belonging to the LD.
// Format: {ldName; {lnName; {CDC|...|DS; vectorOfObjRefs}}}
LD2LNMap dirCache;
3. The function that was initially called:
public void useGetDataSetDirectory() {
Console.WriteLine("");
Console.WriteLine("------ useGetDataSetDirectory ----------");
foreach(LDReference ld in _server.GetServerDirectoryLogicalDevices()) {
Console.WriteLine("LD: " + ld.getRef());
foreach(LNReference ln in _server.GetLogicalDeviceDirectory(ld)) {
.......
}
}
}
4. After getLD returns null, hasLDName throws the exception and the above
assertion failure message is displayed:
// getLD()
CoreAcsi::NamingCache::LD2LNMap::const_iterator
CoreAcsi::NamingCache::getLd(const CoreTypes::ObjectName& ldName) const
{
LD2LNMap::const_iterator it1 = dirCache.find(ldName);
if (it1 != dirCache.end()) {
return it1;
}
return NULL;
}
// hasLDName
CoreTypes:_BOOLEAN
CoreAcsi::NamingCache::hasLDName(const CoreTypes::ObjectName& ldName) const
{
return (getLd(ldName) != NULL);
}
seem to find a solution to it. It relates in a good measure to iterators and
the way we’re using them in our project. I will first give you a little
introduction to our main task. We had at our hands entire modules which were
written in C++. These were to communicate with a stack written in C, and in
turn act as a layer between the C code and C# code used in another
application.
Whoever had developed the C++ code, was building it using makefiles in the
cygwin shell, as the condition then (for whatever reasons) had been that the
code remains ANSI compatible. So the C++ code was being built using
compilers/linkers for cygwin, cygmingw, and vc7.1. A free tool called SWIG[0]
was being used to generate an export file to be compiled with the C++ code as
well as a full C# wrapper of all the C++ classes and functions. (Essentially
SWIG generates a flattened interface to all the C++ classes and then builds
the objects in C# and uses pinvoke with a pointer to access the C++ classes).
In our main C# application, we references these C# wrapper dlls in projects
depending on the functionality and all seemed to work.
Recently though, our project team decided that we should have all the code
in the Visual Studio environment, and we felt strongly that it would enable
us to debug the unmanaged code, if there is a need to, and thus have better
control over code maintainence. Furthermore, we decide to move over to the
VC8.0, which seemed the most logical thing to do.
Implications – First of all, we felt that the effort involved in translating
the makefile script to VS properties was considerable. Even though the
makefiles were done very intelligenty, they also had very specific
instructions, and these were often masked under many layers of variables. A
lot of time and energy led us finally to having a VS 2005 solution with all
the C++ projects, their corresponding C++ test console applications, C#
projects which contained the files automatically generated with SWIG, and
finally the C# unit test projects to test these C# projects.
In addition, we could also debug down to the C++ code, which was
encouraging. We were able to generate the C++ dlls and the C# wrapper dlls as
cygwin. However, with the test modules, we have run into this seemingly
unsolvable problem.
This test aims first at establishing a connection with a server on a real
device and then to compare some characteristics with it. The error we get is:
Debug Assertion Failed!
Program: C:\....\Test.exe
File: C:\Program Files\Microsoft Visual Studio 8\VC\include\xtree
Line: 293
Expression: map/set iterators incompatible
For information on how your program can cause an assertion failure, see the
Visual C++ documentation on asserts.
(Please Retry to debug the application).
As for the code samples, please bear in mind the following:
1. We are using the following typemaps
// Kind of cached item.
enum RefKind {...};
// Vector of cached items of the same kind.
typedef std::vector<string> RefsVec;
typedef std::map<RefKind, RefsVec> KindRefsMap;
typedef std::map<CoreTypes::ObjectName, KindRefsMap> LN2KindMap;
typedef std::map<CoreTypes::ObjectName, LN2KindMap> LD2LNMap;
2. LD2LNMap is instantiates as:
// Cache for References (names). Created per LD the first time a
// directory service is called for an element belonging to the LD.
// Format: {ldName; {lnName; {CDC|...|DS; vectorOfObjRefs}}}
LD2LNMap dirCache;
3. The function that was initially called:
public void useGetDataSetDirectory() {
Console.WriteLine("");
Console.WriteLine("------ useGetDataSetDirectory ----------");
foreach(LDReference ld in _server.GetServerDirectoryLogicalDevices()) {
Console.WriteLine("LD: " + ld.getRef());
foreach(LNReference ln in _server.GetLogicalDeviceDirectory(ld)) {
.......
}
}
}
4. After getLD returns null, hasLDName throws the exception and the above
assertion failure message is displayed:
// getLD()
CoreAcsi::NamingCache::LD2LNMap::const_iterator
CoreAcsi::NamingCache::getLd(const CoreTypes::ObjectName& ldName) const
{
LD2LNMap::const_iterator it1 = dirCache.find(ldName);
if (it1 != dirCache.end()) {
return it1;
}
return NULL;
}
// hasLDName
CoreTypes:_BOOLEAN
CoreAcsi::NamingCache::hasLDName(const CoreTypes::ObjectName& ldName) const
{
return (getLd(ldName) != NULL);
}