You've probably got an extra layer of indirection. The Delphi code you have marshals a pointer to a pointer to the record. I expect that the C# code marshals a pointer to the record. I expect this not least because it takes quite a bit of effort to marshal a pointer to a pointer to the record in C#.
My guess is that the C# code is like this:
public static void CreateSampleInstance(out Sample sample)
In which case you need to write it all like this:
C#
public struct Sample
{
[MarshalAs(UnmanagedType.BStr)]
string Name;
}
[DllExport]
public static void CreateSampleInstance(out Sample sample)
{
sample.Name = "boo yah";
}
Delphi
type
TSample = record
Name: WideString;
end;
procedure CreateSampleInstance(out sample: TSample); stdcall;
external 'myDotNetAssembly.dll';
On the Delphi side, I wrote it with load-time linking for simplicity. You can readily adapt to run-time linking if that's a requirement for you.