It is All about Traffic, and Programming
Search
Archives
0 visitors online now
0 guests, 0 members

Aimsun

The Move Constructor: A Linking Pitfall of Qt Library with Different Compilers

Move constructor is a C++11 feature from ISO/IEC14882:2011.  It enhanced the old-school C++ copy constructor by moving the resource of an object, instead of member-wise copying.  It is faster than a copy constructor.  Thus a C++11 compiler will generate six special member functions for a C++ object, including  move constructor and move assignment operator:

  • Default Constructor
  • Copy Constructor
  • Copy Assignment Operator
  • Destructor
  • Move Constructor
  • Move Assignment Operator

We are not going to discuss C++11 Move Constructor in details here –  better details and better explanations are there, and there.

The motivation of  this article,  is not to discuss the semantics or usage of Move Constructor,  but an interesting debugging experience, and the lessons learned which involves C++11 move constructor.

Long story short – I have been working on developing an advanced Qt-based C++ plugin DLL for a host software developed in Qt 4.8.7.   I was using Visual C++ 2010 compiler, and the Qt for VS2010 official release for commercial applications.

The plugin DLL is supposed to be dynamically loaded by the host via Qt’s QLibrary API (see my previous article on this subject), which internally will call Microsoft’s Win32 API LoadLibrary.  Somehow, I got the following error, when trying to load the DLL into the host software:

34f8:3518 @ 01570140 – LdrpGetProcedureAddress – INFO: Locating procedure “AcdssPluginFactory” by name
34f8:3518 @ 01570140 – LdrpNameToOrdinal – WARNING: Procedure “AcdssPluginFactory” could not be located in DLL at base 0x0B630000
34f8:3518 @ 01570140 – LdrpReportError – WARNING: Locating export “AcdssPluginFactory” for DLL “Unknown” failed with status: 0xc0000139
34f8:1168 @ 01570265 – LdrpReportError – ERROR: Locating export “??4QString@@QAEAAV0@$$QAV0@@Z” for DLL “C:\Program Files (x86)\…\plugins\acdssplugin.DLL” failed with status: 0xc0000139

The above debug messages were generated by GFlags Utility, which comes with Debugging Tools for Windows. You can find the most advanced debugging techniques including how to use GFlags utility from the excellent book Inside Windows Debugging.  In our case, we just need to set “Show Loader Snaps” flag, as shown in the figure.  This is a typical way of debugging LoadLibrary failures.

2016-10-12_21-41-26

Looking at the debug messages, it is simply pointing out that LoadLibrary fails because an exported function is missing from the image space – its C++ mangled name as  “??4QString@@QAEAAV0@$$QAV0@@Z”,  which can be interpreted as:


    ? = C++ mangled symbol
    ?4 = "operator="
    QString@ = the enclosing class, hence method name: QString::operator=
    @ = end of the scope
    Q = public
    A = no const and volatile qualifier
    E = __thiscall
    AAV0 = const ref to the first named class (QString) - the return value (const QString &)
    @ = end return type
    $$ = move constructor &&
    QAV0 = const pointer to first named class - QString * const
    @ = end parameter type
    @ = end parameters
    Z = function

So clearly, the host software was complaining that the Move Constructor of QString can not be located in any of the image space.  Upon further inspection of the host software, it is discovered it was compiled using VS2005.  QtCore4.dll does not have the Move Constructor generated with VC++ 2005 compiler.  

The solution is simple – just rebuilt the Qt 4.8.7 using VC++ 2005, and rebuilt the plugin DLL.  Above all, the lessons learned are:

Do NOT mix Qt library compiled with different compilers, EVEN with the same Qt Version.  Period.

A cute example of Aimsun scripting

Aimsun is traffic simulation software developed by Transport Simulation System (TSS). It has a very powerful python-based scripting engine.  Though other traffic simulation software, e.g., PTV Vissim or Caliper TransModeler provides scripting functionality as well – yet Aimsun’s scripting engine has some unique features that make the scripting work not only productive, but also quite fun 😆 .

One such feature is the so-called live-binding of  a script to any selected object type.  

In Aimsun framework,  all elements of the simulation task – from network geometry,  control devices, script,  to menus, dialogs, projects, scenarios, algorithms …. everything … anything – is an “object”,  derived from a base class GKBaseObject which is rooted from Qt’s QObject.  The entire Aimsun software is built upon a Model-View-Controller (MVC) framework taking advantage of Qt framework.  This framework is well exposed to end users via its SDKs, APIs, and the Scripting Engine.  Apart from being a  comprehensive traffic simulation tool,  Aimsun presents itself as an excellent example of  modern design patterns and software engineering. It has very small memory footprint as well.

The following example comes with default Aimsun installation, i.e.,  the sample script No. 30 “Copy Control Plan”.

Please note, the latest Aimsun 8.0.x versions have some internal changes breaking the scripts that once had worked with Aimsun version 7.x. TSS releases  these scripts with the official Version 8.0.x without upgrading those scripts,  and you’ll have to fix them yourself.   (UPDATE: Aimsun 8.0.8 released on March 19, 2015 has fixed this.)

The following is the original script Copy Control Plan that comes with Aimsun official 8.0.x installation:

2015-03-06_22-26-59

In the above,  Line 3 – Line 7 should be replaced as follows:

2015-03-06_22-31-46

So, the script after the fix should look like the following:

2015-03-06_22-34-31

Some notes:

  • The object that the script binds to is represented by the name “target”. Therefore,  if the script is bound to node-type objects (e.g., the script is added to the context menu of node objects),  “target” would refer to the subject node object.  To bind a script to another  object,  you simply right click the script, select “Properties”. Then from “Settings” tab –> “Add Script to a Menu”, select an object type in the drop-down list “To Context Menu for Object Type” .  See the figure below.

2015-03-06_22-41-19

  • getControlPlan is called twice, at Line 11, and at Line 14. At Line 11,  it is called to get the source control plan object. At Line 14, it is called to get the destination control plan object.
  • GAnyObjectChooserEditor and GAnyObjectChooser are two interesting classes.  GAnyObjectChooserEditor is a later-addition.  Originally there was only GAnyObjectChooser class.  The helper class GAnyObjectChooserEditor is added to separate the chooser class and the editor class – a better design/refactoring but breaking some of the existing scripts .  Basically,  as its name indicates, it provides a user interface to choose an object of the specified type in Aimsun framework.  You can see it in action in the following figure:

2015-03-06_22-53-48

  •   chooser.setType is the one responsible for specifying what type of objects that the Editor dialog should present.

In summary – Aimsun python scripting engine are able to:

  1. Dynamically bind a script  to any objects during run-time;
  2. Inside the script engine, Aimsun provides ready-made UI elements to facilitate the interactions between the end user and the Aimsun host.  This allows productive and efficient workflow of simulation projects with the creative minds of a traffic modeler.
  3. Agree?  Any thoughts, or Aimsun scripting experience to share?

Advanced Aimsun API Programming (2)

Aimsun MicroAPI has a total of 444 functions,  in three header files:

  • AKIProxie
  • ANGConProxie
  • CIProxie

These functions are ported to Delphi language, and the following shows a demo of obtaining vehicle information:

Aimsun API-Delphi Demo 1: Obtaining Vehicle Information

  • First the exported functions are defined in the project file, as follows:
// AIMSUN API  Delphi Interface
// Ported by Wuping Xin
// Last Update @2014-03-21 20:23:55
//---------------------------------------------------

library AAPI_veh_info;

uses
  AAPI in 'AAPI.pas',
  AAPI_Util in 'AAPI_Util.pas',
  AKIProxie in 'AKIProxie.pas',
  ANGConProxie in 'ANGConProxie.pas',
  CIProxie in 'CIProxie.pas';

{$R *.res}

exports
  AAPILoad,
  AAPIInit,
  AAPIManage,
  AAPIPostManage,
  AAPIFinish,
  AAPIUnLoad,
  AAPIEnterVehicle,
  AAPIExitVehicle,
  AAPIEnterVehicleSection,
  AAPIExitVehicleSection,
  AAPIInternalName,
  AAPIPreRouteChoiceCalculation;

begin
  //
end.
  • Second,  the exported functions are actually implemented in unit AAPI.pas file, as follows:
unit AAPI;

interface
  function AAPILoad: Integer; cdecl;
  function AAPIInit: Integer; cdecl;
  function AAPIManage(aTime: Double; aTimeSta: Double; aTimeTrans: Double;
      aSimStep: Double): Integer; cdecl;
  function AAPIPostManage(aTime: Double; aTimeSta: Double; aTimeTrans: Double;
      aSimStep: Double): Integer; cdecl;
  function AAPIFinish: Integer; cdecl;
  function AAPIUnLoad: Integer; cdecl;

  function AAPIEnterVehicle(aVehID: Integer; aSectionID: Integer): Integer; cdecl;
  function AAPIExitVehicle(aVehID: Integer; aSectionID: Integer): Integer; cdecl;
  function AAPIEnterVehicleSection(aVehID: Integer; aSectionID: Integer; aTime:
      Double): Integer; cdecl;
  function AAPIExitVehicleSection(aVehID: Integer; aSectionID: Integer; aTime:
      Double): Integer; cdecl;
  function AAPIInternalName: PAnsiChar; cdecl;

  function AAPIPreRouteChoiceCalculation(aTime: Double; aTimeSta: Double):
      Integer; cdecl;

implementation

uses
  SysUtils, AKIProxie, ANGConProxie, CIProxie;

  function AAPIEnterVehicle(aVehID: Integer; aSectionID: Integer): Integer; cdecl;
  begin
    Result := 0;
  end;

  function AAPIEnterVehicleSection(aVehID: Integer; aSectionID: Integer; aTime:
      Double): Integer; cdecl;
  begin
    Result := 0;
  end;

  function AAPIExitVehicle(aVehID: Integer; aSectionID: Integer): Integer; cdecl;
  begin
    Result := 0;
  end;

  function AAPIExitVehicleSection(aVehID: Integer; aSectionID: Integer; aTime:
      Double): Integer; cdecl;
  begin
    Result := 0;
  end;

  function AAPIFinish: Integer; cdecl;
  begin
    Result := 0;
  end;

  function AAPIInit: Integer; cdecl;
  begin
    Result := 0;
  end;

  function AAPIInternalName: PAnsiChar; cdecl;
  begin
    Result := 'AAPI_veh_info';
  end;

  function AAPILoad: Integer; cdecl;
  begin
    Result := 0;
  end;

  function AAPIManage(aTime: Double; aTimeSta: Double; aTimeTrans: Double;
      aSimStep: Double): Integer; cdecl;
  var
    lvVehInfo: InfVeh;
    lvNumOfSections, lvNumOfVehs, lvNumOfJunctions: Integer;
    lvSectionIdx, lvVehIdx, lvJunctionIdx: Integer;
    lvSectionID, lvJunctionID: Integer;
    lvVehInfoStr: string;
  begin
    try
      lvNumOfSections := AKIInfNetNbSectionsANG;

      for lvSectionIdx := 0 to lvNumOfSections - 1 do
      begin
        lvSectionID := AKIInfNetGetSectionANGId(lvSectionIdx);
        lvNumOfVehs := AKIVehStateGetNbVehiclesSection(lvSectionID, True);

        for lvVehIdx := 0 to lvNumOfVehs - 1 do
        begin
          lvVehInfo := AKIVehStateGetVehicleInfSection(lvSectionID, lvVehIdx);
          lvVehInfoStr := Format('Vehicle %d, Section %d, Lane %d, CurrentPos %f, CurrentSpeed %f',
            [
              lvVehInfo.idVeh,
              lvVehInfo.idSection,
              lvVehInfo.numberLane,
              lvVehInfo.CurrentPos,
              lvVehInfo.CurrentSpeed
            ]);

          AKIPrintString(PAnsiChar(AnsiString(lvVehInfoStr)));
        end;
      end;

      lvNumOfJunctions := AKIInfNetNbJunctions;

      for lvJunctionIdx := 0 to lvNumOfJunctions - 1 do
      begin
        lvJunctionID := AKIInfNetGetJunctionId(lvJunctionIdx);
        lvNumOfVehs := AKIVehStateGetNbVehiclesJunction(lvJunctionID);

        for lvVehIdx := 0 to lvNumOfVehs - 1 do
        begin
          lvVehInfo := AKIVehStateGetVehicleInfJunction(lvJunctionID, lvVehIdx);
          lvVehInfoStr := Format('Vehicle %d, Node %d, From %d, To %f, CurrentPos %f, CurrentSpeed %f',
            [
              lvVehInfo.idVeh,
              lvVehInfo.idJunction,
              lvVehInfo.idsectionFrom,
              lvVehInfo.idSectionTo,
              lvVehInfo.CurrentPos,
              lvVehInfo.CurrentSpeed
            ]);

          AKIPrintString(PAnsiChar(AnsiString(lvVehInfoStr)));
        end;


      end;

      Result := 0;
    finally
      //
    end;
  end;

  function AAPIPostManage(aTime: Double; aTimeSta: Double; aTimeTrans: Double;
      aSimStep: Double): Integer; cdecl;
  begin
    Result := 0;
  end;

  function AAPIPreRouteChoiceCalculation(aTime: Double; aTimeSta: Double):
      Integer; cdecl;
  begin
    Result := 0;
  end;

  function AAPIUnLoad: Integer; cdecl;
  begin
    Result := 0;
  end;

end.

 The above demo and the ported Aimsun API in Object Pascal can be downloaded from here.

http://wupingxin.net/wx-files/aimsun_api_pascal.zip

 

Advanced Aimsun API Programming (1)

Aimsun MicroAPIs are the programming interface of Aimsun microscopic traffic simulator. These APIs provided 10 predefined call back hooks, together with various other utility functions.

MicroAPIs allow advanced users to implement sophisticated external logic, for example, non-standard ramp metering, advanced traffic management strategies, adaptive signal control etc.. These are not readily available with standard off-the-shelf Aimsun features, but made possible with Aimsun MicroAPIs.

The Aimsun MicroAPIs are very flexible, as its final product is in the format of a Dynamic Link Library (DLL). The DLL is loaded by Aimsun host during run time before running a simulation replication, and unloaded after the simulation replication finishes. The supported programming language is C++ and Python. But a developer with sufficient knowledge of DLL programing can easily port the development in other languages such as Delphi, C#, Java, Fortran, if he or she desires so.

One nuance about Aimsun MicroAPIs programming  is the granular control level down to a single simulation step. This is no surprise since Aimsun Micro is a time-discretized space continuous simulator that all the simulation events have to be driven by incrementing simulation steps.  However,   this might pose some programming challenges or certain pitfalls when multi-threading is involved, or  when a TCP/IP based client-server structure is employed.  The tricky point is that at the simulation step level,  the control of flow is transferred from Aimsun host to MicroAPI DLL,  while NOT until the call back finishes,  Aimsun host is essentially “blocked”. This could possibly counter-balance any benefits obtained from the multi-threaded code implemented inside the API logic.

Overall, Aimsun MicroAPIs include two types of functions:

  1. Predefined DLL Exported Functions (hooks to the Aimsun Host);
  2. Utility Functions provided by the Aimsun Host to retrieve various run time information.

The utility functions can be further classified into three categories:

  1. External Control Interface Functions for traffic signal control (ramp metering, intersection signal control etc). These functions are usually prefixed with ECI, for example, ECIChangeParametersFlowAlineaMeteringById;
  2. Aimsun NG Objects Connection Interface Functions for accessing properties of Aimsun internal objects. These functions are usually prefixed with ANGConn, for example, ANGConnActivatePolicy;
  3. Aimsun Kernel Interface Functions to retrieve other simulation run time information. These functions are usually prefixed with AKI, for example, AKIDetGetDensityAggregatedbyId.

Predefined Callbacks

As mentioned above, Aimsun MicroAPIs provided 10 predefined call-back functions (hooks). These functions are exported by the MicroAPI DLL, so that the Aimsun host can load the DLL and call these functions at appropriate time during simulation. It is the task of the MicroAPI developers to design the external logic and implement the logic under the framework of these functions properly.

In a nutshell, Aimsun host will call back these functions on the following events:

  1. The MicroAPI DLL is loaded or unloaded by the Aimsun host;
  2. The external logic is registered with the Aimsun host;
  3. Before running, or after finishing the simulation;
  4. Before or after a simulation step is executed;
  5. A vehicle enters or exits the transportation network;
  6. Before a route choice calculation is performed.

In addition to the 10 predefined call-backs (See Table 1 below)  exported by the MicroAPI DLL, there are also many utility functions exported by the Aimsun host. This renders two way communication between the MicroAPI DLL and the Aimsun host for exchanging of information and control.

As to be explained in future post,  Aimsun’s two way communication is quite different from VISSIM, another popular traffic simulator developed and marketed by the Germany company PTV AG.  VISSIM also provides various APIs, e.g., VISSIM external driver APIs,  VISSIM signal control APIs etc.   Particularly, VISSIM provides an automation mechanism by virtue of Microsoft’s COM technology.   Regardless,  in terms of APIs,  VISSIM is merely one way communication.  The pros and cons of these two types of interfaces will be discussed later.

To use the utility functions exported by the Aimsun host, “angext.lib” must be specified for the linker.  However,  for some reason,  the corresponding DLLis not named angext.dll,  but a2kernel.dll.

The following table summaries the 10 predefined call-backs.

TABLE 1. Aimsun MicroAPIs 10 Call-backs (hooks)

Interfacing Aimsun API with Delphi

AIMSUN provides several programming interfaces for advanced applications,  for example,  Python scriping,  Aimsun SDK,  Driver Behavior API,  Micro-Simulator API etc.. Among these, AIMSUN Micro-Simulator APIs, formerly known as AIMSUN GETRAM Extensions, are probably the widely used.

In the AIMSUN MicroAPIs manual, these APIs functions  (and examples, if any) are specified in C/C++.  This doesn’t mean MicroAPIs only work with C/C++, while it should be noted that it is also possible to use these APIs with Delphi (Object Pascal).   Doing this has some benefits such as the fun with the Pascal language, the powerful VCL framework, and the various Delphi components available from the Delphi community.  For example, the Indy component for Socket programming,  RemObject for multi-tier development.

The following shows a simple AIMSUN API example written in Delphi.  The key steps are:

  1. Use CDECL calling convention;
  2. Reference a2kernelxxx.dll, where “xxx” is the version number;
  3. Unlike C++, Delphi doesn’t do name mangling.

[delphi]

Library AAPI_DE;

uses
AKIProxie in ‘AKIProxie.pas’;

{$R *.res}
function AAPILoad:Integer; cdecl;
begin
AKIPrintString(‘LOAD AIMSUN EXTENSTION DLL FROM DELPHI!’);
Result := 0;
end;

function AAPIInit:Integer; cdecl;
begin
AKIPrintString(‘\tInit’);
Result := 0;
end;

function AAPIManage(time:Single; timeSta:Single; timTrans:Single; acicle:Single):Integer;cdecl;
begin
AKIPrintString(‘\tManage’);
Result := 0;
end;

function AAPIPostManage(time:Single; timeSta:Single; timTrans:Single; acicle:Single) :Integer;cdecl;
begin
AKIPrintString(‘\tPostManage’);
Result := 0;
end;

function AAPIFinish:Integer;cdecl;
begin

AKIPrintString(‘\tFinish’);

Result := 0;

end;

function AAPIUnLoad:Integer;cdecl;
begin
AKIPrintString(‘\tUnload’);
Result := 0;
end;

exports
AAPILoad,
AAPIInit,
AAPIManage,
AAPIPostManage,
AAPIFinish,
AAPIUnLoad;

begin

end.

// Pascal unit of APKProxie.h in C/C++
unit AKIProxie;

interface
function AKIPrintString(Str:PChar):Integer;cdecl;

implementation
const
AIMSUN_KERNEL_DLL = ‘…\a2kernel7.dll’;

function AKIPrintString(Str:PChar):Integer;cdecl; external AIMSUN_KERNEL_DLL;

end.

[/delphi]

Aimsun scripting: A different perspective

Aimsun is an Object-Oriented Framework and Unified Platform for Traffic Modeling.  It  provides quite a few programming interfaces for advanced applications and customization. To name a few,  those  include Aimsun Simulator API,  Aimsun SDK,  Aimsun Python-based Scripting,  MicroSDK,  Logistics SDK, Parking APIs.  These SDKs and APIs  together with Aimsun main software  provide powerful tools for its users.

Interestingly, by design all these APIs, albeit having different focuses, have ONE in common, i.e., they MUST either be invoked within Aimsun host ( e.g., Aimsun SDK and Aimsun Pyhton-based Scripting), or called-back during run time (i.e., simulator API and MicroSDK). This means Aimsun cannot be used as a COM automation sever, and therefore it may not be invoked by external applications.

Actually, it is only partially true.  First of all, this is not something to complain about.  Aimsun is a cross-platform software package;  it runs on Linux, MacOS, and Windows. COM is a very much Windows specific technology, so in spite of that it is doable it simply doesn’t seem to make much sense to dedicate Aimsun to a platform specific feature.  Second some the COM-like functionality can be achieved by using ANGApp class, which is fully accessible by Python scripting.

In this post,  I would like to discuss a way of porting ANGApp class by Python C API,  so that some of  its advanced functionality becomes available to a common compiler-based language.  To start with,  the following shows a Python wrapper class that encapsulate some COM-like interfaces, on top of the ANGApp class:

from PyANGBasic   import *
from PyANGApp     import *
from PyANGAimsun  import *
from PyANGKernel  import *
from PyANGConsole import *

__author__    = "Wuping Xin"
__company__   = "No Inc."
__copyright__ = "Copyright (c) No Rights Reserved"
__license__   = "python"
__version__   = "$1.0.0 $"
__date__      = "$Date: 2009/07/15 11:57 $"

class AimsunApp:
"Wrapper class of Aimsun ANGApp class for C++ application with Python C API"
def __init__(self, isCon = False):
  self.angInstance = None
  self.simulator   = None
  self.model       = None
  self.angGui      = None
  self.isConsole   = isCon
  def initInstance(self):
  pass

def freeInstance(self):
pass

def openNetwork(self,filename):
pass

def runInteractive(self):
  self.angInstance.run()

def __setModel(self):
  self.model = self.angInstance.getModel()

def initSimulator(self,repID,simMode = 0):

.......
def runSingleStep(self):
  self. angInstance.processEvents()
  self.simulator.simulationStep()

With this wrapper class ready, we can use the following C code to invoke:

Py_Initialize();
..........

pName    = PyString_FromString("aimsunpy_interface");
pModule  = PyImport_Import(pName);
pDict    = PyModule_GetDict(pModule);

// Build the name of a callable class
pClass = PyDict_GetItemString(pDict, "AimsunApp");

// Create an instance of the wrapper cls.
if (PyCallable_Check(pClass))
{
    pInstance = PyObject_CallObject(pClass, NULL);
}

PyObject_CallMethod(pInstance, "initInstance", NULL);
PyObject_CallMethod(pInstance, "openNetwork","s","C:\\Test\\test.ang");
PyObject_CallMethod(pInstance, "initSimulator","i",346);

This is a nuance to note – when trying to load a C-Extension module ( i.e., *.pyd file),  if the host program that embeds Python interpreter links with pythonxx_d.dll, then PyImport_Import will import the xxxx_d.pyd, even if the module’s name is specified without “_d”!  Also this approach is dependent on Aimsun’s embedded Python  interpreter hence there is some run-time performance hit. But if that is not an issue, this approach would make it possible to integrate Aimsun with external applications, for example, MATLAB platform.

Inside Aimsun ANGApp.close

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 *.

Doh~!
.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:00B620FB retn
.text:00B620FC ; —————————————————————————
.text:00B620FC

.text:00B620FC loc_B620FC:
[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()
.text:00B62107push 1

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!