Home > front end >  Generated COM method lacks 'out' keyword on a parameter
Generated COM method lacks 'out' keyword on a parameter

Time:12-27

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);
}
  • Related