I am hopelessly trying to implement the IMAPI interface in my current project.
I have seen the MS presentation on the implementation and created my wrapper
in csharp with the help of the API specification. I have also requested the
source code from the "How to Write Managed Code in VS.NET to Access XP Func"
MS webcast. The only sample missing was the IMAPI sample. So I went to town
and created it from scratch. Here are my two classes that should work. I
have written in comments where the code dies with a null reference passed
error (even though none of the params are null). Any help would be great!


IMAPI Wrapper Class:

using System;
using System.Runtime.InteropServices;

namespace CDAuthoring.IMAPI
{
/// <summary>
///IMAPI Definitions and Interfaces
/// </summary>

#region IMAPI Interface Definitions
[ComImport] [Guid("520CCA62-51A5-11D3-9144-00104BA11C5E")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDiscMaster
{//HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{520CCA62-51A5-11D3-9144-00104BA11C5E}
// Open Opens an IMAPI object.
void Open();
// EnumDiscMasterFormats Retrieves a format enumerator.
void EnumDiscMasterFormats([MarshalAs(UnmanagedType.Interface)]out IEnumDiscMasterFormats
e);
// GetActiveDiscMasterFormat Retrieves the currently selected recorder
format.
void GetActiveDiscMasterFormat(out Guid lpiid);
//SetActiveDiscMasterFormat Sets a new active recorder format.
void SetActiveDiscMasterFormat(ref Guid riid, [MarshalAs(UnmanagedType.IUnknown)]out
Object ppunk);
//EnumDiscRecorders Retrieves a recorder enumerator.
void EnumDiscRecorders([MarshalAs(UnmanagedType.Interface)]out IEnumDiscRecorders
e);
//GetActiveDiscRecorder Retrieves the active disc recorder format.
void GetActiveDiscRecorder([MarshalAs(UnmanagedType.IUnknown)]out Object
ppRecorder);
//SetActiveDiscRecorder Selects a new active disc recorder.
void SetActiveDiscRecorder([MarshalAs(UnmanagedType.IUnknown)]Object pRecorder);
//ClearFormatContent Clears the contents of an unburned image.
void ClearFormatContent();
//ProgressAdvise Registers for progress notifications.
// ProgressAdvise Registers for progress notifications.
//ProgressUnadvise Cancels progress notifications.
// ProgressUnadvise Cancels progress notifications.
//RecordDisc Burns the staged image to media in the active disc recorder.
void RecordDisc(bool bSimulate, bool bEjectAfterBurn);
//Close Closes the interface.
void Close();
}

[ComImport] [Guid("EC9E51C1-4E5D-11D3-9144-00104BA11C5E")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDiscMasterProgressEvents
{//HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{EC9E51C1-4E5D-11D3-9144-00104BA11C5E}
//QueryCancel Checks whether a burn is to be canceled.
void QueryCancel(out bool pbCancel);
//NotifyPnPActivity Reports possible changes to recorder list.
void NotifyPnPActivity();
//NotifyAddProgress Reports progress of audio/data staging.
void NotifyAddProgress(long nCompletedSteps, long nTotalSteps);
//NotifyBlockProgress Reports progress of audio/data burn.
void NotifyBlockProgress(long nCompleted, long nTotal);
//NotifyTrackProgress Reports progress of an audio burn.
void NotifyTrackProgress(long nCurrentTrack, long nTotalTracks);
//NotifyPreparingBurn Reports progress during burn setup.
void NotifyPreparingBurn(long nEstimatedSeconds);
//NotifyClosingDisc Reports progress while closing a disc.
void NotifyClosingDisc(long nEstimatedSeconds);
//NotifyBurnComplete Reports that the burn is fully complete.
//TODO: RP- the following return HRESULT what to map as?
// void NotifyBurnComplete(out HRESULT status);
// //NotifyEraseComplete Reports that an erase is fully complete.
// void NotifyEraseComplete(out HRESULT status);
}

[ComImport] [Guid("85AC9776-CA88-4cf2-894E-09598C078A41")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDiscRecorder
{
/*Init Initializes the object for an underlying device.
Used internally only.*/
void Init(
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] byte[] ID,
ulong nulIDsize, ulong nulDriveNumber);
//GetRecorderGUID Retrieves the underlying device GUID.
void GetRecorderGUID(
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] byte[] ID,
ulong ulBufferSize, out ulong pulReturnSizeRequired);
//GetRecorderType Identifies device as CD-R or CD-RW.
void GetRecorderType(out long fTypeCode);
//GetDisplayNames Retrieves a name suitable for GUI display.
void GetDisplayNames(
[MarshalAs(UnmanagedType.BStr)] out string pbstrVendorID,
[MarshalAs(UnmanagedType.BStr)] out string pbstrProductID,
[MarshalAs(UnmanagedType.BStr)] out string pbstrRevision);
//GetBasePnPID Returns identifier unique to device class.
void GetBasePnPID([MarshalAs(UnmanagedType.BStr)] out string pbstrBasePnPID);
//GetPath Returns an OS path to the device.
void GetPath([MarshalAs(UnmanagedType.BStr)] out string pbstrPath);
//GetRecorderProperties Retrieve a pointer to the IPropertyStorage interface
for the recorder.
//SetRecorderProperties Set properties for the recorder.
//GetRecorderState Checks if recorder is ready to burn.
void GetRecorderState(out ulong pulDevStateFlags);
//OpenExclusive Opens a device for exclusive use.
void OpenExclusive();
//QueryMediaType Identifies the type of media in the recorder.
void QueryMediaType(out long fMediaType,out long fMediaFlags);
/*Media Types:
* MEDIA_CDDA_CDROM
* MEDIA_CD_ROM_XA
* MEDIA_CD_I
* MEDIA_CD_EXTRA
* MEDIA_CD_OTHER
* MEDIA_SPECIAL*/
/*Media Flags:
* MEDIA_BLANK
* MEDIA_RW
* MEDIA_WRITABLE*/
//QueryMediaInfo Retrieves media properties.
void QueryMediaInfo(out byte pbsessions,out byte pblasttrack,out ulong
ulstartaddress,out ulong ulnextwritable, out ulong ulfreeblocks);
//Eject Ejects a recorder's tray, if possible.
void Eject();
//Erase Erases CD-RW media, if possible.
void Erase(bool bFullErase);
//Close Close a recorder after exclusive access.
void Close();
}
#endregion

#region Enums
[ComImport] [Guid("9B1921E1-54AC-11d3-9144-00104BA11C5E")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IEnumDiscRecorders
{
void Next(
ulong cRecorders,
[MarshalAs(UnmanagedType.LPArray)]
out IDiscRecorder[] ppRecorder,
out ulong pcFetched);
void Skip(ulong cRecorders);
void Reset();
void Clone([MarshalAs(UnmanagedType.IUnknown)] out Object e);
}

[ComImport] [Guid("DDF445E1-54BA-11D3-9144-00104BA11C5E")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IEnumDiscMasterFormats
{//{DDF445E1-54BA-11D3-9144-00104BA11C5E}
void Next(
ulong cFormats,
[MarshalAs(UnmanagedType.LPArray)]
out Guid[] ppForamtGuid,
out ulong pcFetched);
void Skip(ulong cFormats);
void Reset();
void Clone(out Guid e);
}
#endregion

#region Class STUBS
[ComImport] [Guid("520CCA63-51A5-11D3-9144-00104BA11C5E")]
public class MSDiscMasterObj{}

[ComImport] [Guid("520CCA61-51A5-11D3-9144-00104BA11C5E")]
public class MSDiscRecorderObj{}

[ComImport] [Guid("8A03567A-63CB-4BA8-BAF6-52119816D1EF")]
public class MSEnumDiscRecordersObj{}
#endregion
}


Implentation Test Class (Just using the def constructor):

using System;
using CDAuthoring.IMAPI;

namespace CDAuthoring
{
/// <summary>
/// Summary description for CDAuth.
/// </summary>
public class CDAuth
{
public CDAuth()
{
IDiscMaster dMaster = (IDiscMaster)new MSDiscMasterObj();
dMaster.Open();
//set the active format to Joliet
Guid IID_JDM = new Guid("E3BC42CE-4E5C-11D3-9144-00104BA11C5E");
Object ojdm = null;
dMaster.SetActiveDiscMasterFormat(ref IID_JDM, out ojdm);

//Set the disc recorder to the first available device
IEnumDiscRecorders pEnum;
ulong num = 0;
dMaster.EnumDiscRecorders(out pEnum);
IDiscRecorder [] dr = new IDiscRecorder[1];
if(dr!=null)
{
pEnum.Next(1, out dr, out num);//THIS LINE GIVES AN ERROR...
/*null reference passed:
* 1 is obviously not a null reference
* dr is not null as you see the conditional statement passes
* num is set to 0 and error still occurrs
*
* This must be a problem with the implementation in IMAPI.cs
* but this is a far as I have gotten*/
dMaster.SetActiveDiscRecorder(dr[0]);
}
}
}
}