Something like this should be generated by compiler to solve issue (code is functional):
Code: Select all
MODULE A;
IMPORT S := SYSTEM, W := WinApi, COM, Log := StdLog;
CONST
ExceptionContinueExecution = 0;
ExceptionContinueSearch = 1;
ExceptionNestedException = 2;
ExceptionCollidedUnwind = 3;
EXCEPTION_UNWINDING = {1};
EXCEPTION_EXIT_UNWIND = {2};
EXCEPTION_STACK_INVALID = {3};
EXCEPTION_NESTED_CALL = {4};
EXCEPTION_TARGET_UNWIND = {5};
EXCEPTION_COLLIDED_UNWIND = {6};
TYPE
ExcpFramePtr = POINTER TO ExcpFrame;
ExcpFrame = EXTENSIBLE RECORD [untagged]
link: ExcpFramePtr;
handler: PROCEDURE [ccall] (
excpRec: W.PtrEXCEPTION_RECORD;
estFrame: ExcpFramePtr;
context: W.PtrCONTEXT;
dispCont: INTEGER
): INTEGER;
END;
ReleaseHandlerPtr = POINTER TO ReleaseHandler;
ReleaseHandler = RECORD (ExcpFrame)
ptr: INTEGER;
END;
Object = POINTER TO RECORD (COM.IUnknown)
END;
PROCEDURE [code] InstallExcp (VAR e: ExcpFrame) 64H, 8BH, 0DH, 0, 0, 0, 0, 89H, 8, 64H, 0A3H, 0, 0, 0, 0;
PROCEDURE [code] RemoveExcp (VAR e: ExcpFrame) 8BH, 0, 64H, 0A3H, 0, 0, 0, 0;
PROCEDURE [ccall] ExcpHandler (
excpRec: W.PtrEXCEPTION_RECORD;
estFrame: ExcpFramePtr;
context: W.PtrCONTEXT;
dispCont: INTEGER
): INTEGER;
VAR unk: COM.IUnknown;
BEGIN
Log.String("ExcpHandler(");
Log.Set(excpRec.ExceptionFlags);
Log.String(")"); Log.Ln;
IF excpRec.ExceptionFlags * (EXCEPTION_UNWINDING + EXCEPTION_EXIT_UNWIND) # {} THEN
(* cleanup phase, called from W.RtlUnwind *)
(* call ptr.Release *)
S.PUT(S.ADR(unk), estFrame(ReleaseHandlerPtr).ptr); unk := NIL;
ELSE
(* final handler search phase *)
END;
RETURN ExceptionContinueSearch;
END ExcpHandler;
PROCEDURE (o: Object) RELEASE;
BEGIN
Log.String("Object.RELEASE"); Log.Ln;
END RELEASE;
PROCEDURE (o: Object) FINALIZE;
BEGIN
Log.String("Object.FINALIZE"); Log.Ln;
END FINALIZE;
PROCEDURE NewObject (): Object;
VAR o: Object;
BEGIN
NEW(o);
RETURN o;
END NewObject;
PROCEDURE Do*;
VAR excp: ReleaseHandler; obj: COM.IUnknown;
BEGIN
excp.handler := ExcpHandler;
excp.ptr := 0;
InstallExcp(excp);
obj := NewObject();
excp.ptr := S.VAL(INTEGER, obj);
HALT(0);
RemoveExcp(excp);
END Do;
END A.
A.Do
Kernel.Collect
DevDecoder.Decode A
Compiler already generate SEH handler install code for [guarded] procedures, handler is Kernel.InterfaceTrapHandler. It can be reused and new SEH handler can be created for calling IUnknown.Release for COM pointer in local variables. COM pointer list should be generated by compiler and passed to SEH handler.