In order to study the life cycle of CCOMVissim, we have to track the calling stack of comsvr.dll. This DLL is the host of CCOMVissim and other helper classes of Vissim COM functionalities. Please note it is not possible and not an option to perform static code analysis using a typical debugger. This is because CodeMeter hardware chip employs sophisticated anti-debugging mechanism, black-listing all known static/dynamic analysis debuggers such as OllyDBG or IDAPro . We’d have to return to comsrv.DLL – and recall in this post – the 58 exported functions, something like below:
As an effective approach (for interoperability among Vissim’s own various licensed modules), let’s start creating a DLL project, using the same name “comsrv.DLL”, as the one in the Exe folder of Vissim installation.
As a good background reading on exporting C++ classes in a DLL, here is an detailed post CodeProject: Export C++ classes from a DLL
Following this new Visual Studio C++ DLL project, create a new class called CCOMVissim – pay attention to the class definition, and the empty methods, and the declaration “__declspec(dllexport)“. By default, the calling convention is “thiscall“. Because we know Vissim is compiled in Visual C++ compiler apriori, thus name mangling wouldn’t be an issue (because of the same C++ compiler).
Now, compile this project, and a dll called comsrv.dll is generated. After this new DLL is generated, de-compile it to verify the exported functions (see the figure below):
We just created a “proxy” DLL with the same name as Vissim’s original comsrv.dll. We emulated some of the original exported functions and classes. The point is, as long as the same list of functions are exported by this new dll, it is “loadable” by Vissim. Therefore, we are enableed to append additional code to track, manage, and manipulate the calling stack of those class methods or functions relevant to the life-cycle of IVissimPtr. This will help accomplish the objective of enabling interoperability of Vissim COM functionalities within Vissim’s various DLL-based modules, including Signal Control API DLL, External Driver DLL and such.
If you could understand up to this point, there should be no problem for you to move on to a final working solution to the question asked in the beginning. The efforts are yours, and the omissions are mine. One last hint:
Rename the original “comsrv.dll” to a different name, e.g., “comsrv_org.dll”. Redirect calls from inside the proxy comsrv.dll to the original dll.
There was an interesting discussion at PTV Vissim LinkedIn group – how to access Vissim COM interface inside a DLL, e.g., a Signal Control DLL, an External Driver DLL etc. To properly answer this question, some in-depth understanding of the COM technology, C++ compiler internals, and Vissim binary level details are in order.
To begin with, Component Object Model (COM) is just a binary-level coding standard for out-of-process and in-process communication. It’s been out there for many years but somehow never become popular due to its daunting learning-curve for ordinary programmers, and then Microsoft began promoting .NET, which is essentially similar idea revamped at the level of Common Language Run-time (CLR) and Intermediate Language (IL).
In the nostalgia good-old days, COM/C++ programming required too steep learning curve to weed out sub-par programmers. Nowadays programming is so much easier with various .NET languages or scripting languages that do not require low-level knowledge of hardware or compiler internals. The barrier to programing is quite low nowadays; anyone with common sense can pick up programming, develop some apps, and sell such on streets.
In the context of Vissim, PTV wraps up the simulation elements and workflow into various interfaces. These interfaces are implemented (in C++) at binary level thus any language that supports COM (by their respective compilers) will be able to use Vissim’s COM interface to interact with Vissim functionality.
In the earlier days of Vissim, its COM interfaces allow a client application to invoke Vissim as an automation server (as an out-of-process use case). Then PTV added In-Menu scripting, that supports invoking COM inside the active Vissim instance, using Python, VBS, or JS.
Starting Vissim 6, PTV completely refactored and redesigned Vissim, almost rebuild the software from scratch, inside out. As part of this process, more gems are added, one of such, is the so-called “event-based” COM scripting. “Event-based” COM scripting is a use case of in-process COM; it was added since Vissim v7.
Once again, with the In-Menu COM/Event-based Scripting, and many other new designs/architectures, Vissim has set up a solid foundation significantly better than its v5 and any earlier generations, making itself readily primed for the future. A big congratulation is due to the PTV development team for this achievement, seriously.
As of today, Vissim 7-09 appears as the most impressive redemption of a legacy software (I mean, particularly, Vissim v4 and earlier versions) – and presents itself, with so many improvements and beef-ups, and as a powerful, sleek and increasingly popular tool for its users that have been yelling and crying for years while its competitors eating up its market share.
Aside from COM interface, Vissim also provides various APIs e.g., Signal Control API, Emission API, External Driver API etc. These APIs have to be compiled in DLL to be loaded by Vissim host, which calls back the exported functions when certain events fire.
It is interesting that “event-based” COM scripting is capable of providing a unified interface for all the above APIs. In future, it is possible that PTV might gradually phase out all these DLL-based APIs so everything is done through a unified event-based COM scripting. Granted, that is just my personal perspective.
Now, coming back to the million dollar question – can we access COM interface from inside an API DLL? For example, from inside External Driver DLL, how can we access some, if not all of the COM functions?
The answer is: yes, that is doable, but with some twist.
Now you start to have a faint of heart, aren’t you? Before we roll up our sleeves and jump to the 1-2-3 steps, I want you to take a look at the following snapshots – they are the key to the solution.
The following are the 58 exported functions from comsrv.dll, which is located in Vissim installation Exe folder. Most of these exported functions, are class methods of several classes, primarily:
💡 comsrv.dll is the “hub” of all Vissim COM functionality.
With the above in mind, let me lead you to the interesting journey to figure out comsvr.dll and Vissim COM invocation flow, till we reach the final solution to the original question.
(to be continued)
Aimsun ANGApp is a class available to python scripting. It is a very interesting class that TSS provides to its general users, and can be very powerful if the user really appreciates how it works.
In the past a few days, I have been cleaning up my previous codes, while working on a project proposal that may require Aimsun micro + meso. And for some reason, one code snippet that has worked previously crashes on ANGApp.close … …
This time I am pretty hesitant to write to TSS for help – though I am sure they are going to help, as always TSS is very kind and prompt in supporting their users – sometimes a little delay if they are busy. And for these couple of days, I know they are being working their tails off on the new release of Aimsun 6.1.0 – couldn’t be more busier.
So I decided not to bother them and find out myself.
All rightee ……the question is, what is really going on inside ANGAPP.close()? And why there is a crash? Let’s take a partial look at the code segment:
OK, save the current state of ESI by pushing it to stack. This is a no brainer.
.text:00B620E0 push esi
Note, ECX always holds the “this” pointer for C++ class. So, after mov ESI, ECX, ESI stores the starting address of the current ANGApp instance
.text:00B620E1 mov esi, ecx
Now, since ESI+0 is the starting address of the subject ANGApp instance, ESI + 8 must be the address for some private member-variable, and by looking at the instruction at 00B620EA , we can immediately get the hint that it must be the address for a GGui* pointer . Now, what about ESI + 4? Note the fact that ANGApp inherits from QObject, thus ESI+4 actually is the address for a protected pointer of type QObjectData. What about ESI+0xC? Hey, are you as curious as I am? That is a good question! That is actually the address for a pointer of type GKModel *.
.text:00B620E3 mov ecx, [esi+8]
IS the GGui* NULL?
.text:00B620E6 test ecx, ecx
.text:00B620E8 jz short loc_B620FC
If the GGui* is not NULL then call GGui.getActiveModel
.text:00B620EA call ds:__imp_?getActiveModel@GGui@@QBEPAVGKModel@@XZ ;
.text:00B620F0 mov ecx, [esi+8]
Now after invoking GGui.getActiveModel, EAX holds the returned pointer for GKModel
.text:00B620F3 push eax
Then GGui.closeDocument is called with the returned GKModel pointer from above instruction
.text:00B620F4 call ds:__imp_?closeDocument@GGui@@QAE_NPAVGKModel@@@Z
Okaydokay. So far so good! Now restore ESI.
.text:00B620FA pop esi
.text:00B620FC ; —————————————————————————
[ESI + 0xC] is the address that holds the pointer of type GKModel*
.text:00B620FC mov ecx, [esi+0Ch]
Now ECX holds the pointer to GKModel
.text:00B620FF test ecx, ecx
.text:00B62101 jz short loc_B62112
Here is the tricky part. [ECX +0] is the address of the v-table of GKModel class
.text:00B62103 mov eax, [ecx]
Now EDX stores the address of the v-table of GKModel class
.text:00B62105 mov edx, [eax]
Index 1 means the first virtual function in the v-table. Note, GKModel inherits from GKObject. Therefore, the first virtual function in the v-table is the destructor ~GKObject()
Now call the destructor
.text:00B62109 call edx
Reset the GKModel* pointer to zero.
.text:00B6210B mov dword ptr [esi+0Ch], 0
This is perfect code logically showing no problem at all! And it turns out that the crash was caused by a corrupted memoy I artificially manipulated which screw up ANGApp’s initernal data!