EXETOOLS FORUM  

Go Back   EXETOOLS FORUM > General > General Discussion

Notices

Reply
 
Thread Tools Display Modes
  #1  
Old 04-09-2019, 20:19
jonwil jonwil is offline
VIP
 
Join Date: Feb 2004
Posts: 278
Rept. Given: 2
Rept. Rcvd 18 Times in 6 Posts
Thanks Given: 1
Thanks Rcvd at 15 Times in 7 Posts
jonwil Reputation: 18
Reverse engineering MS C++ exception handling

I have a function (compiled originally with VS .NET 2003) in IDA that looks like this:
Code:
.text:10038AD0 ; int __thiscall W3dExportClass::DoExport(W3dExportClass *this, const TCHAR *name, ExpInterface *ei, Interface *i, BOOL suppressPrompts, DWORD options)
.text:10038AD0 W3dExportClass__DoExport proc near      ; DATA XREF: .rdata:1007AE04↓o
.text:10038AD0
.text:10038AD0 anonymous_0     = dword ptr -0E58h
.text:10038AD0 var_E50         = dword ptr -0E50h
.text:10038AD0 var_23C         = RawFileClass ptr -23Ch
.text:10038AD0 var_220         = dword ptr -220h
.text:10038AD0 Caption         = byte ptr -21Ch
.text:10038AD0 Dir             = byte ptr -118h
.text:10038AD0 var_14          = dword ptr -14h
.text:10038AD0 var_10          = dword ptr -10h
.text:10038AD0 var_C           = dword ptr -0Ch
.text:10038AD0 var_4           = dword ptr -4
.text:10038AD0 name            = dword ptr  8
.text:10038AD0 ei              = dword ptr  0Ch
.text:10038AD0 i               = dword ptr  10h
.text:10038AD0 suppressPrompts = dword ptr  14h
.text:10038AD0 options         = dword ptr  18h
.text:10038AD0
.text:10038AD0 ; FUNCTION CHUNK AT .text:10072A00 SIZE 0000000B BYTES
.text:10038AD0
.text:10038AD0 ; __unwind { // SEH_10038AD0
.text:10038AD0                 push    ebp
.text:10038AD1                 mov     ebp, esp
.text:10038AD3                 push    0FFFFFFFFh
.text:10038AD5                 push    offset SEH_10038AD0
.text:10038ADA                 mov     eax, large fs:0
.text:10038AE0                 push    eax
.text:10038AE1                 mov     large fs:0, esp
.text:10038AE8                 sub     esp, 0E44h
.text:10038AEE                 mov     eax, ___security_cookie
.text:10038AF3                 push    ebx
.text:10038AF4                 push    esi
.text:10038AF5                 mov     esi, ecx
.text:10038AF7                 push    edi
.text:10038AF8                 mov     edi, [ebp+i]
.text:10038AFB                 xor     ebx, ebx
.text:10038AFD                 mov     [ebp+var_14], eax
.text:10038B00                 mov     eax, [ebp+ei]
.text:10038B03                 mov     ecx, edi        ; this
.text:10038B05                 mov     [esi+W3dExportClass.ExpInt], eax
.text:10038B0B                 mov     [esi+W3dExportClass.Int], edi
.text:10038B11                 mov     [esi+W3dExportClass.field_47C], ebx
.text:10038B17                 mov     [esi+W3dExportClass.OriginNodeList], ebx
.text:10038B1D                 mov     [esi+W3dExportClass.DamageNodeList], ebx
.text:10038B23                 mov     [esi+W3dExportClass.HierarchyStruct], ebx
.text:10038B29                 mov     edx, [ecx]
.text:10038B2B                 mov     [ebp+var_10], esp
.text:10038B2E                 mov     [ebp+var_220], esi
.text:10038B34 ;   try {
.text:10038B34                 mov     [ebp+var_4], ebx
.text:10038B37                 call    [edx+InterfaceVtable.GetTime]
.text:10038B3D                 mov     [esi+W3dExportClass.Time], eax
.text:10038B43                 call    ds:GetFrameRate(void)
.text:10038B49                 mov     [esi+W3dExportClass.FrameRate], eax
.text:10038B4F                 push    ebx             ; Ext
.text:10038B50                 lea     eax, [ebp+Caption]
.text:10038B56                 push    eax             ; Filename
.text:10038B57                 mov     eax, [ebp+name]
.text:10038B5A                 lea     ecx, [ebp+Dir]
.text:10038B60                 push    ecx             ; Dir
.text:10038B61                 lea     edx, [ebp+ei]
.text:10038B64                 push    edx             ; Drive
.text:10038B65                 push    eax             ; FullPath
.text:10038B66                 mov     [esi+W3dExportClass.field_478], 2
.text:10038B70                 call    __splitpath
.text:10038B75                 lea     ecx, [ebp+Dir]
.text:10038B7B                 push    ecx
.text:10038B7C                 lea     edx, [ebp+ei]
.text:10038B7F                 push    edx
.text:10038B80                 push    offset aSS      ; "%s%s"
.text:10038B85                 push    offset buf ; char *
.text:10038B8A                 call    _sprintf
.text:10038B8F                 lea     eax, [ebp+Caption]
.text:10038B95                 add     esp, 24h
.text:10038B98                 lea     edx, [eax+1]
.text:10038B9B                 jmp     short loc_10038BA0
.text:10038B9B ; ---------------------------------------------------------------------------
.text:10038B9D                 align 10h
.text:10038BA0
.text:10038BA0 loc_10038BA0:                           ; CODE XREF: W3dExportClass__DoExport+CB↑j
.text:10038BA0                                         ; W3dExportClass__DoExport+D5↓j
.text:10038BA0                 mov     cl, [eax]
.text:10038BA2                 inc     eax
.text:10038BA3                 cmp     cl, bl
.text:10038BA5                 jnz     short loc_10038BA0
.text:10038BA7                 sub     eax, edx
.text:10038BA9                 cmp     eax, 0Fh
.text:10038BAC                 jbe     short loc_10038BC5
.text:10038BAE                 cmp     [ebp+suppressPrompts], ebx
.text:10038BB1                 jnz     short loc_10038BC5
.text:10038BB3                 push    ebx             ; uType
.text:10038BB4                 push    offset aWarning ; "Warning"
.text:10038BB9                 push    offset aWarningW3dFile ; "Warning: W3D filenames should be 15 cha"...
.text:10038BBE                 push    ebx             ; hWnd
.text:10038BBF                 call    ds:MessageBoxA
.text:10038BC5
.text:10038BC5 loc_10038BC5:                           ; CODE XREF: W3dExportClass__DoExport+DC↑j
.text:10038BC5                                         ; W3dExportClass__DoExport+E1↑j
.text:10038BC5                 mov     eax, [edi]
.text:10038BC7                 mov     ecx, edi        ; Interface *
.text:10038BC9                 call    [eax+InterfaceVtable.GetCurFilePath]
.text:10038BCF                 mov     ecx, eax
.text:10038BD1                 call    ds:CStr::operator char *(void)
.text:10038BD7                 push    ebx             ; Ext
.text:10038BD8                 push    ebx             ; Filename
.text:10038BD9                 lea     ecx, [ebp+Dir]
.text:10038BDF                 push    ecx             ; Dir
.text:10038BE0                 lea     edx, [ebp+ei]
.text:10038BE3                 push    edx             ; Drive
.text:10038BE4                 push    eax             ; FullPath
.text:10038BE5                 call    __splitpath
.text:10038BEA                 lea     eax, [ebp+Dir]
.text:10038BF0                 push    eax
.text:10038BF1                 lea     ecx, [ebp+ei]
.text:10038BF4                 push    ecx
.text:10038BF5                 lea     edx, [esi+W3dExportClass.Path]
.text:10038BF8                 push    offset aSS      ; "%s%s"
.text:10038BFD                 push    edx             ; char *
.text:10038BFE                 call    _sprintf
.text:10038C03                 mov     eax, [ebp+suppressPrompts]
.text:10038C06                 add     esp, 24h
.text:10038C09                 push    eax             ; suppressPrompts
.text:10038C0A                 mov     ecx, esi        ; this
.text:10038C0C                 call    W3DExportClass__DoExportDialog
.text:10038C11                 cmp     al, bl
.text:10038C13                 jz      loc_10038DA5
.text:10038C19                 cmp     [esi+W3dExportClass.ExportStruct.ExportSkeleton], bl
.text:10038C1F                 jnz     short loc_10038C35
.text:10038C21                 cmp     [esi+W3dExportClass.ExportStruct.ExportAnimation], bl
.text:10038C27                 jnz     short loc_10038C35
.text:10038C29                 cmp     [esi+W3dExportClass.ExportStruct.ExportGeometry], bl
.text:10038C2F                 jz      loc_10038DA5
.text:10038C35
.text:10038C35 loc_10038C35:                           ; CODE XREF: W3dExportClass__DoExport+14F↑j
.text:10038C35                                         ; W3dExportClass__DoExport+157↑j
.text:10038C35                 push    ebx
.text:10038C36                 call    CreateLogDialog
.text:10038C3B                 mov     ecx, [ebp+name]
.text:10038C3E                 add     esp, 4
.text:10038C41                 push    ecx             ; filename
.text:10038C42                 lea     ecx, [ebp+var_23C] ; this
.text:10038C48                 call    RawFileClass__RawFileClass
.text:10038C4D                 push    2               ; a2
.text:10038C4F                 lea     ecx, [ebp+var_23C] ; this
.text:10038C4F ;   } // starts at 10038B34
.text:10038C55 ;   try {
.text:10038C55                 mov     byte ptr [ebp+var_4], 1
.text:10038C59                 call    RawFileClass::Open(int)
.text:10038C5E                 cmp     eax, ebx
.text:10038C60                 jnz     short loc_10038C8B
.text:10038C62                 push    10000h          ; uType
.text:10038C67                 push    offset aError   ; "Error"
.text:10038C6C                 push    offset aUnableToOpenFi ; "Unable to open file."
.text:10038C71                 push    ebx             ; hWnd
.text:10038C72                 call    ds:MessageBoxA
.text:10038C78                 lea     ecx, [ebp+var_23C] ; this
.text:10038C78 ;   } // starts at 10038C55
.text:10038C7E ;   try {
.text:10038C7E                 mov     byte ptr [ebp+var_4], bl
.text:10038C81                 call    RawFileClass::~RawFileClass()
.text:10038C86                 jmp     loc_10038DA5
.text:10038C8B ; ---------------------------------------------------------------------------
.text:10038C8B
.text:10038C8B loc_10038C8B:                           ; CODE XREF: W3dExportClass__DoExport+190↑j
.text:10038C8B                 lea     edx, [ebp+var_23C]
.text:10038C91                 push    edx             ; _DWORD
.text:10038C92                 lea     ecx, [ebp+var_E50]
.text:10038C98                 call    ChunkSaveClass::ChunkSaveClass(FileClass *)
.text:10038C9D                 mov     ecx, esi        ; this
.text:10038C9F                 call    W3dExportClass__CreateOriginNodeList
.text:10038CA4                 cmp     eax, ebx
.text:10038CA6                 jz      short loc_10038CBD
.text:10038CA8                 lea     eax, [ebp+var_E50]
.text:10038CAE                 push    eax             ; int
.text:10038CAF                 lea     ecx, [ebp+Caption]
.text:10038CB5                 push    ecx             ; lpCaption
.text:10038CB6                 mov     ecx, esi
.text:10038CB8                 call    W3dExportClass__ExportData
.text:10038CBD
.text:10038CBD loc_10038CBD:                           ; CODE XREF: W3dExportClass__DoExport+1D6↑j
.text:10038CBD                 lea     ecx, [ebp+var_23C]
.text:10038CC3                 call    RawFileClass::Close(void)
.text:10038CC8                 mov     edi, [esi+48Ch]
.text:10038CCE                 cmp     edi, ebx
.text:10038CD0                 jz      short loc_10038CE8
.text:10038CD2                 mov     ecx, edi        ; this
.text:10038CD4                 call    HierarchySave__DHierarchySave
.text:10038CD9                 push    edi             ; void *
.text:10038CDA                 call    MAX_delete(void *)
.text:10038CDF                 add     esp, 4
.text:10038CE2                 mov     [esi+W3dExportClass.HierarchyStruct], ebx
.text:10038CE8
.text:10038CE8 loc_10038CE8:                           ; CODE XREF: W3dExportClass__DoExport+200↑j
.text:10038CE8                 mov     edi, [esi+W3dExportClass.OriginNodeList]
.text:10038CEE                 cmp     edi, ebx
.text:10038CF0                 jz      short loc_10038D08
.text:10038CF2                 mov     ecx, edi        ; this
.text:10038CF4                 call    INodeListClass__destructor2
.text:10038CF9                 push    edi             ; void *
.text:10038CFA                 call    MAX_delete(void *)
.text:10038CFF                 add     esp, 4
.text:10038D02                 mov     [esi+W3dExportClass.OriginNodeList], ebx
.text:10038D08
.text:10038D08 loc_10038D08:                           ; CODE XREF: W3dExportClass__DoExport+220↑j
.text:10038D08                 mov     edi, [esi+W3dExportClass.DamageNodeList]
.text:10038D0E                 cmp     edi, ebx
.text:10038D10                 jz      short loc_10038D28
.text:10038D12                 mov     ecx, edi        ; this
.text:10038D14                 call    INodeListClass__destructor2
.text:10038D19                 push    edi             ; void *
.text:10038D1A                 call    MAX_delete(void *)
.text:10038D1F                 add     esp, 4
.text:10038D22                 mov     [esi+W3dExportClass.DamageNodeList], ebx
.text:10038D28
.text:10038D28 loc_10038D28:                           ; CODE XREF: W3dExportClass__DoExport+240↑j
.text:10038D28                 lea     ecx, [ebp+var_23C] ; this
.text:10038D28 ;   } // starts at 10038C7E
.text:10038D2E ;   try {
.text:10038D2E                 mov     byte ptr [ebp+var_4], bl
.text:10038D31                 call    RawFileClass::~RawFileClass()
.text:10038D36                 jmp     short loc_10038D6D
.text:10038D38 ; ---------------------------------------------------------------------------
.text:10038D38
.text:10038D38 loc_10038D38:                           ; DATA XREF: .rdata:stru_10086C44↓o
.text:10038D38 ;   catch(ErrorClass) // owned by 10038B34
.text:10038D38 ;   catch(ErrorClass) // owned by 10038C55
.text:10038D38                 mov     esi, [ebp+i]
.text:10038D3B                 push    10000h          ; uType
.text:10038D40                 push    offset aError   ; "Error"
.text:10038D45                 push    esi             ; lpText
.text:10038D46                 xor     ebx, ebx
.text:10038D48                 push    ebx             ; hWnd
.text:10038D49                 call    ds:MessageBoxA
.text:10038D4F                 cmp     esi, ebx
.text:10038D51                 jz      short loc_10038D5F
.text:10038D53                 mov     edx, ds:void (*MAX_free)(void *)
.text:10038D59                 push    esi
.text:10038D5A                 call    dword ptr [edx]
.text:10038D5C                 add     esp, 4
.text:10038D5F
.text:10038D5F loc_10038D5F:                           ; CODE XREF: W3dExportClass__DoExport+281↑j
.text:10038D5F                 mov     eax, offset loc_10038D65
.text:10038D64                 retn
.text:10038D65 ; ---------------------------------------------------------------------------
.text:10038D65
.text:10038D65 loc_10038D65:                           ; CODE XREF: W3dExportClass__DoExport+294↑j
.text:10038D65                                         ; DATA XREF: W3dExportClass__DoExport:loc_10038D5F↑o
.text:10038D65                 mov     esi, [ebp+var_220]
.text:10038D6B                 xor     ebx, ebx
.text:10038D6B ;   } // starts at 10038D2E
.text:10038D6D
.text:10038D6D loc_10038D6D:                           ; CODE XREF: W3dExportClass__DoExport+266↑j
.text:10038D6D                 mov     [ebp+var_4], 0FFFFFFFFh
.text:10038D74                 call    W3dExportClass__PrintTotalVertexCount
.text:10038D79                 xor     eax, eax
.text:10038D7B                 mov     al, [esi+W3dExportClass.ExportStruct.ReviewLog]
.text:10038D81                 push    eax             ; a1
.text:10038D82                 call    W3dExportClass__DestroyLogDialog
.text:10038D87                 mov     ecx, [esi+W3dExportClass.Int] ; this
.text:10038D8D                 mov     edi, [ecx]
.text:10038D8F                 add     esp, 4
.text:10038D92                 push    ebx
.text:10038D93                 push    8
.text:10038D95                 call    [edi+InterfaceVtable.GetTime]
.text:10038D9B                 mov     ecx, [esi+W3dExportClass.Int] ; Interface *
.text:10038DA1                 push    eax             ; t
.text:10038DA2                 call    [edi+InterfaceVtable.RedrawViews]
.text:10038DA5
.text:10038DA5 loc_10038DA5:                           ; CODE XREF: W3dExportClass__DoExport+143↑j
.text:10038DA5                                         ; W3dExportClass__DoExport+15F↑j ...
.text:10038DA5                 mov     ecx, [ebp+var_C]
.text:10038DA8                 mov     large fs:0, ecx
.text:10038DAF                 mov     ecx, [ebp+var_14]
.text:10038DB2                 mov     eax, 1
.text:10038DB7                 call    __security_check_cookie(x)
.text:10038DBC                 pop     edi
.text:10038DBD                 pop     esi
.text:10038DBE                 pop     ebx
.text:10038DBF                 mov     esp, ebp
.text:10038DC1                 pop     ebp
.text:10038DC2                 retn    14h
.text:10038DC2 ; } // starts at 10038AD0
.text:10038DC2 W3dExportClass__DoExport endp

.text:10072A0B SEH_10038AD0    proc near               ; DATA XREF: W3dExportClass__DoExport+5↑o
.text:10072A0B                                         ; .rdata:1008556C↓o
.text:10072A0B                 mov     eax, offset stru_10086C68
.text:10072A10                 jmp     ___CxxFrameHandler
.text:10072A10 SEH_10038AD0    endp

.rdata:10086C68 stru_10086C68   FuncInfo_V1 <19930520h, 3, offset stru_10086C2C, 1, \
.rdata:10086C68                                         ; DATA XREF: SEH_10038AD0↑o
.rdata:10086C68                              offset stru_10086C54, 0, 0>

.rdata:10086C2C stru_10086C2C   UnwindMapEntry <-1, 0>  ; DATA XREF: .rdata:stru_10086C68↓o
.rdata:10086C34                 UnwindMapEntry <0, offset loc_10072A00>
.rdata:10086C3C                 UnwindMapEntry <-1, 0>

.text:10072A00 loc_10072A00:                           ; DATA XREF: .rdata:10086C34↓o
.text:10072A00 ; __unwind { // SEH_10038AD0            ; this
.text:10072A00 ;   cleanup() // owned by 10038C55
.text:10072A00 ;   cleanup() // owned by 10038C7E
.text:10072A00 ;   cleanup() // owned by 10038D2E
.text:10072A00                 lea     ecx, [ebp+var_23C]
.text:10072A06                 jmp     RawFileClass::~RawFileClass()
.text:10072A06 ; } // starts at 10072A00

.rdata:10086C54 stru_10086C54   TryBlockMapEntry <0, 1, 2, 1, offset stru_10086C44>
.rdata:10086C54                                         ; DATA XREF: .rdata:stru_10086C68↓o

.rdata:10086C44 stru_10086C44   HandlerType <0, offset ErrorClass `RTTI Type Descriptor', 16, \
.rdata:10086C44                                         ; DATA XREF: .rdata:stru_10086C54↓o
.rdata:10086C44                              offset loc_10038D38>
I have a clone of the function (without any try/catch statements in there) as follows:
Code:
int __thiscall W3dExportClass::DoExport(W3dExportClass *this, const TCHAR *name, ExpInterface *ei, Interface *i, BOOL suppressPrompts, DWORD options)
{
  this->ExpInt = ei;
  this->Int = i;
  this->field_47C = 0;
  this->OriginNodeList = NULL;
  this->DamageNodeList = NULL;
  this->HierarchyStruct = NULL;
  this->Time = i->GetTime(i);
  this->FrameRate = GetFrameRate();
  this->field_478 = 2;
  _splitpath(name, (char *)&ei, &Dir, &Caption, NULL);
  sprintf(buf, "%s%s", &ei, &Dir);
  if ( strlen(&Caption) > 0xF && !suppressPrompts )
    MessageBoxA(NULL, "Warning: W3D filenames should be 15 characters or less!", "Warning", 0);
  _splitpath((const char *)i->GetCurFilePath(), (char *)&ei, &Dir, NULL, NULL);
  sprintf(this->Path, "%s%s", &ei, &Dir);
  if ( W3DExportClass::DoExportDialog(this, suppressPrompts)
    && (this->ExportStruct.ExportSkeleton || this->ExportStruct.ExportAnimation || this->ExportStruct.ExportGeometry) )
  {
    CreateLogDialog(0);
    RawFileClass r(name);
    if ( r.Open(2) )
    {
      ChunkSaveClass::ChunkSaveClass(&r);
      if ( W3dExportClass::CreateOriginNodeList(this) )
        W3dExportClass::ExportData(this, &Caption, (int)&v21);
      r.Close();
      if ( this->HierarchyStruct )
      {
	delete this->HierarchyStruct;
        this->HierarchyStruct = NULL;
      }
      if ( this->OriginNodeList )
      {
        delete this->OriginNodeList;
        this->OriginNodeList = NULL;
      }
      if ( this->DamageNodeList )
      {
        delete this->DamageNodeList;
        this->DamageNodeList = NULL;
      }
      W3dExportClass::PrintTotalVertexCount();
      W3dExportClass::DestroyLogDialog(this->ExportStruct.ReviewLog);
      this->Int->RedrawViews(this->Int->GetTime() //not sure of full prototype for this function, may have more arguments);
    }
    else
    {
      MessageBoxA(NULL, "Unable to open file.", "Error", MB_SETFOREGROUND);
    }
  }
  return 1;
}
Can anyone tell me based on the ASM and the above clone where the try/catch statements and other EH stuff need to go to complete the clone? (if any further information is needed I can provide that)
Reply With Quote
  #2  
Old 04-10-2019, 03:11
chants chants is offline
Friend
 
Join Date: Jul 2016
Posts: 337
Rept. Given: 0
Rept. Rcvd 11 Times in 10 Posts
Thanks Given: 265
Thanks Rcvd at 304 Times in 171 Posts
chants Reputation: 12
It is strange because I see no references to those structures at the end in the code. The comments in the code seem to be inferred somehow from those data structures. Perhaps the compiler optimized out the try-catch already and just left in some extra metadata.

RTTI is Run-time Type Information, its basically a reflection metadata system for C++ especially for class hierarchy identification to allow for virtual destructors and the like. It does not necessarily mean it was referenced in the code as I think its merely a compiler option. Please refer to MSDN or even here:
Quote:
https://en.wikipedia.org/wiki/Run-time_type_information
So the real keys here are about compiler optimizations and whether they already optimized out unnecessary SEH, and whether the compiler is included extra and unneeded SEH data. Regardless, to resurrect the original source accurately, you would want to bring back those useless optimized out code and so this is definetely a bonus to have the information.

I don't understand the question further as the first dump shows where a try { block starts and also gives a comment as to its end so it should be easy for you to add those to your clone function. You can basically merge the contiguous try blocks as the close brace is misleading. There is just one try and one catch.

Code:
.text:10038B34 ;   try {
.text:10038C4F ;   } // starts at 10038B34
.text:10038C55 ;   try {
.text:10038C78 ;   } // starts at 10038C55
.text:10038C7E ;   try {
.text:10038D28 ;   } // starts at 10038C7E
.text:10038D2E ;   try {
.text:10038D38 ;   catch(ErrorClass) // owned by 10038B34
.text:10038D38 ;   catch(ErrorClass) // owned by 10038C55
.text:10038D6B ;   } // starts at 10038D2E
Basically because of the structure you already put in the clone you cannot match this easily. However again knowing what is safe and non-safe of the calls is crucial and the compiler theoretically uses heuristics to deduce and optimize based on this.

Possibly you just wrap the entire code block you show up to W3dExportClass::PrintTotalVertexCount(); in:
Code:
try {
 (original clone)
} catch (ErrorClass* ec) {
//.text:10038D38                 mov     esi, [ebp+i] really [ebp+0x10] so some error class with a zero terminated ascii string at 0x10 bytes in which we call szMessage 
  MessageBox(NULL, ec->szMessage, "Error", MB_SETFOREGROUND); //0x10000=MB_SETFOREGROUND
}
//.text:10038D5F                 mov     eax, offset loc_10038D65
W3dExportClass::PrintTotalVertexCount();
The problem is you need to invert your control flow and return early or use goto's very similar to the way Microsoft does in a lot of their source code for large functions...
e.g.
Code:
if ( !r.Open(2) ) {
  MessageBoxA(NULL, "Unable to open file.", "Error", MB_SETFOREGROUND);
  return 1; //or goto return_loc
//...return_loc: return 1;
}
Code:
if ( !(W3DExportClass::DoExportDialog(this, suppressPrompts)
    && (this->ExportStruct.ExportSkeleton || this->ExportStruct.ExportAnimation || this->ExportStruct.ExportGeometry)) ) return 1; //or goto return_loc

Last edited by chants; 04-10-2019 at 03:34.
Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



All times are GMT +8. The time now is 19:34.


��ICP��05004977��
Always Your Best Friend: Aaron, JMI, ahmadmansoor, ZeNiX