Data Types

The following table shows commonly used data types, and how to "translate" them for managed code:

Unmanaged Data Type

Managed Data Type

Input Parameter

Output Parameter

Pointer to string (PChar)

String

IntPtr

Character array (array[a..b] of

' Char)

String

String

Array of value type (array[a..b]

of Byte)array[a..b] of Bytearray[a..b] of Byte

Dynamic array (array[0..0] of

type)

IntPtr

IntPtr

Array of struct (array[1..2] of

TRect)

IntPtr or flatten

IntPtr or flatten

Pointer to structure (PRect)

IntPtr

IntPtr

Pointer to simple type (PByte)

IntPtr

IntPtr

Pointer to array (PInteger)

IntPtr

IntPtr

Pointer to pointer type (APInteger)

IntPtr

IntPtr

When working with arrays and strings in structures, the MarshalAs attribute is used to describe additional information to the default marshaler about the data type. A record declared in Delphi 7, for example:

type

TMyRecord = record

IntBuffer: array[0..31] of Integer; CharBuffer: array[0..127] of Char; lpszInput: LPTSTR; lpszOutput: LPTSTR; end;

Would be declared as follows in Delphi 8 for .NET:

type

  • StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] TMyRecord = record
  • MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] IntBuffer: array[0..31] of Integer;
  • MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] CharBuffer: string; [MarshalAs(UnmanagedType.LPTStr)] lpszInput: string; lpszOutput: IntPtr; end;

The above declarations assume that the strings contain platform dependant TChar's (as commonly used by the Win32 API). It is important to note that in order to receive text in lpszOutput, the Marshal. AllocHGlobal method needs to be called before passing the structure to an API function.

A structure can contain structures, but not pointers to structures. For such cases an IntPtr must be declared, and the Marshal. StructureToPtr method used to move data from the managed structure into unmanaged memory. Note that StructureToPtr does not allocate the memory needed (this must be done separately). Be sure to use Marshal. SizeOf to determine the amount of memory required, as Delphi's SizeOf is not aware of the MarshalAs attribute (in the example above, CharBuffer would be 4 bytes using Delphi's SizeOf when it in fact should occupies 128 bytes on a single byte system). The following examples show how to send messages that pass pointers to a structure:

procedure SetRect(Handle: HWND; const Rect: TRect); var

Buffer: IntPtr; begin

Buffer := Marshal.AllocHGlobal(Marshal.SizeOf(TypeOf(TRect))); try

  1. StructureToPtr(TObject(Rect), Buffer, False); SendMessage(Handle, EM_SETRECT, 0, Buffer); finally
  2. DestroyStructure(Buffer, TypeOf(TRect)); end; end;

procedure GetRect(Handle: HWND; var Rect: TRect); var

Buffer: IntPtr; begin

Buffer := Marshal.AllocHGlobal(Marshal.SizeOf(TypeOf(TRect))); try

SendMessage(Handle, EM_GETRECT, 0, Buffer);

Rect := TRect(Marshal.PtrToStructure(Buffer, TypeOf(TRect))); finally

Marshal.DestroyStructure(Buffer, TypeOf(TRect)); end; end;

It is important to call DestroyStructure rather than FreeHGlobal if the structure contains fields where the marshaling layer needs to free additional buffers (see the documentation for DestroyStructure for more details).

Project Management Made Easy

Project Management Made Easy

What you need to know about… Project Management Made Easy! Project management consists of more than just a large building project and can encompass small projects as well. No matter what the size of your project, you need to have some sort of project management. How you manage your project has everything to do with its outcome.

Get My Free Ebook


Post a comment