I'm trying to use the Image Mastering API from C# but some methods lack the out
keyword and therefore fail to execute.
I generated the interop code by doing the following:
- References, Add Reference
- COM, Type Libraries
- Microsoft IMAPI2 Base Functionality
It worked correctly until I hit a wall, here's the code I'm currently using:
using System;
using IMAPI2;
namespace ConsoleApp1
{
internal static class Program
{
private static void Main(string[] args)
{
var master2 = new MsftDiscMaster2();
var recorder2 = new MsftDiscRecorder2();
var recorderUniqueId = master2[0];
Console.WriteLine(recorderUniqueId);
recorder2.InitializeDiscRecorder(recorderUniqueId);
var recorder2Ex = (IDiscRecorder2Ex)recorder2;
// this fails as pointer should be an 'out' parameter
// System.NullReferenceException: 'Object reference not set to an instance of an object.'
var discInformation = new IntPtr();
recorder2Ex.GetDiscInformation(discInformation, out var byteSize);
}
}
}
The original signature for IDiscRecorder2Ex::GetDiscInformation:
HRESULT GetDiscInformation(
[out] BYTE **discInformation,
[out] ULONG_IMAPI2_DISC_INFORMATION *byteSize
);
The signature that was generated by Visual Studio:
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetDiscInformation([Out] IntPtr discInformation, out uint byteSize);
I suppose that coding the interfaces manually would work but it's a huge task...
Question:
Is there a way to get Visual Studio generating the correct signature?
CodePudding user response:
This function is intended to return a pointer to an array, and a size, and both of these results come through out
parameters. The discInformation
parameter is double-indirected: it points to a location which stores a pointer to the start of the array being returned.
Technically speaking, I think this could have been translated as
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetDiscInformation(
[Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] out byte[] discInformation,
[Out] out uint byteSize);
Then you can just do
GetDiscInformation(out var discInformation, out var byteSize);
However, the type library converter has not done this. So you need to marshal the array yourself. It looks like you simply aren't doing this correctly. :
byte[] discInformation;
unsafe
{
var di = new IntPtr();
recorder2Ex.GetDiscInformation((IntPtr)&di, out var byteSize);
discInformation = new byte[byteSize];
Marshal.Copy(di, discInformation, 0, byteSize);
}