Search code examples
delphipointerscomrecord

From COM Pointer to Record / How to do a Delphi version of (dotNet's) Marshal.PtrToStructure


Looking for help on how to cast / convert a pointer to a record - similar to what dotNet's Marshal.PtrToStructure does - but using Delphi.

Details: using an ActiveX / COM (original code in C++). Implementing an interface allowing to catch events raised by the ActveX control.

One of the implemented interface's methods signature looks like:

procedure TIUIX_ObjImplEvent.OnEvent(const pSender: IUIX_Obj;  const pEvent: IUIX_Event);

IUIX_Event is an interface (derives from IDispatch). Has a property Param1 of type Param_T.

Param1 holds a pointer to a record type.

Now, I have C# code I would like to convert to Delphi:

public void OnEvent(IUIX_Obj pSender, IUIX_Event pEvent)
{
    //some more code before, and then this part:

    IntPtr outPtr = new IntPtr(pEvent.Param1);
    UIX_NotifyInfo ni = (UIX_NotifyInfo)System.Runtime.InteropServices.Marshal.PtrToStructure(outPtr, typeof(UIX_NotifyInfo));
}

UIX_NotifyInfo is a record (/struct).

Qustion: how to go from pEvent.Param1 to ni? Using Delphi:

procedure TIUIX_ObjImplEvent.OnEvent(const pSender: IUIX_Obj;  const pEvent: IUIX_Event);
var
  ni : UIX_NotifyInfo;
begin
  pEvent.Handled := false;

  if (pEvent.Code = e_Notify) then
  begin

    //how to go from pEvent.Param1 to ni like in C#'s PtrToStructure?

    if (ni.nCode = UIX_Notify_BeforeShowPopup) then
    begin
      pEvent.Handled := true;
    end;
  end;
end;

My guess is using the Move procedure, but whatever I try it either does not compile or crashes :)

Move(??, ni, SizeOf(UIX_NotifyInfo));

I'm adding this after David answered...

Here's an extension to the above question (looking for how to go about Marshal.GetObjectForIUnknown).

I have this C# code:

public void OnEventMonitor(IUIX_Obj pTarget, IUIX_Event pEvent)
{
  IntPtr outPtr;
  pTarget.QueryImpl(typeof(IUIX_Dialog).GUID, null, out outPtr);
  IUIX_Dialog dlg = (IUIX_Dialog)System.Runtime.InteropServices.Marshal.GetObjectForIUnknown(outPtr);
}

Having:

IUIX_Event = interface(IDispatch)
IUIX_Obj = interface(IDispatch)
IUIX_Dialog = interface(IUIX_ObjImpl) (IDispatch)

My Delphi code (dlg : IUIX_Dialog, pImpl : Pointer):

pTarget.QueryImpl(GetTypeData(TypeInfo(IUIX_Dialog)).Guid, nil, @pImpl);
Move(pImpl, dlg, SizeOf(IUIX_Dialog));

The above does work.

Any better approach or that's correct way?


Solution

  • It's simple in unmanaged code, it's just an assignment.

    var
      Rec: TMyRec;
      Ptr: Pointer;
    .... 
    Rec := TMyRec(Ptr^);