Click here to Skip to main content
13,190,404 members (51,438 online)
Click here to Skip to main content
Add your own
alternative version


217 bookmarked
Posted 29 Dec 2007

Burning CD/DVD Media with the Image Mastering API Version 2.0 (IMAPI2)

, 12 Dec 2009
Rate this:
Please Sign up or sign in to vote.
Example of a CD/DVD burning application using IMAPI2.


If you are looking for a sample in C#/.NET, then check out my article: "Burning and Erasing CD/DVD Media with C# and IMAPI2".

Windows introduced the new IMAPIv2.0 with the release of the Vista Operating System, which was a big improvement over the original IMAPI. The original IMAPI is great for CDROMs, but it has some huge limitations like not being able to write to DVD media. I am sure this limitation is due to almost nobody having a DVD writer when Windows XP was released back in 2001. IMAPIv2 allows you to write to CD and DVD media, as well as read and write ISO files. IMAPIv2.0 had a problem since it was only available with Windows Vista. But in June of 2007, Microsoft released update packages for Windows XP and Windows 2003. You can download the updates here.

You will also need to download and install the Microsoft Windows Software Development Kit to get the header files necessary to compile the application. You can download the SDK here.

After you download and install the SDK, you will need to make sure the SDK's include directory is in Visual Studio's Include path. When using Visual Studio 2005, you must also make the SDK's LIB path as the first entry in the LIB directory list.

Anybody wanting to develop a full application should also read the "Joliet Recording Specification".

Using the Code

I have created several wrappers around the IMAPIv2 interfaces to assist in managing instances of the interfaces:

CDiscMaster wraps the IDiscMaster2 interface which allows you to determine if the computer has any optical devices installed, and if so, allows you to enumerate the CD and DVD drives installed on the computer.

CDiscRecorder wraps the IDiscRecorder2 interface which represents each physical drive. You use this interface to retrieve information about the drive including manufacturer information, logical drive, and supported media.

CDiscFormatData wraps the IDiscFormat2Data interface which is used to write data to the media.

CDiscFormatDataEvent wraps the DDiscFormat2DataEvents notifications which is used to receive the status of the IDiscFormat2Data write function.

For the file system, I created a base class CBaseObject which has three functions: GetPath(), GetName(), and GetSizeOnDisc(). GetPath returns the full path of the file or directory on the computer. GetName returns just the filename of the file or the directory which is used for display purposes, and is also used as the name of the file or directory in the root directory of the recorded image. GetSizeOnDisc is a pure virtual function that the two classes that are derived from CBaseObject, CFileObject, and CDirObject, implement. CFileObject returns the size the file will use on the media. CDirObject returns the size of all files and subdirectories of the directory.

I will cover a few main points here, but you should download the source code to see all the code.

You will need to include the imapi2 header files in your application:

#include <imapi2.h>
#include <imapi2error.h>
#include <imapi2fs.h>
#include <imapi2fserror.h>

imapi2.h and imapi2error.h are needed for the imapi2 interfaces. imapi2fs.h and imapi2fserror.h are needed for the imapi2 file system interfaces.

Then, I create an instance of the CDiscMaster class, initialize it, and get the unique ID for each device. The unique ID is used to initialize a CDiscRecord object, and I use that to get display information for the combobox entry and store the pointer for the item data.

CDiscMaster discMaster;
long totalDevices = discMaster.GetTotalDevices();
for (long deviceIndex = 0; deviceIndex < totalDevices; deviceIndex++)
 CString recorderUniqueID = discMaster.GetDeviceUniqueID(deviceIndex);
 CDiscRecorder* pDiscRecorder = new CDiscRecorder();
 // Get the volume path(s). usually just 1
 CString volumeList;
 ULONG totalVolumePaths = pDiscRecorder->GetTotalVolumePaths();
 for (ULONG volIndex = 0; volIndex < totalVolumePaths; volIndex++)
  if (volIndex)
   volumeList += _T(",");
  volumeList += pDiscRecorder->GetVolumePath(volIndex);
 // Add Drive to combo and IDiscRecorder as data
 CString productId = pDiscRecorder->GetProductID();
 CString strName;
 strName.Format(_T("%s [%s]"), (LPCTSTR)volumeList, (LPCTSTR)productId);
 int comboBoxIndex = m_deviceComboBox.AddString(strName);
 m_deviceComboBox.SetItemDataPtr(comboBoxIndex, pDiscRecorder);

When an item is selected in the device combobox, I get the CDiscRecorder object of the selected device, which I placed in the item's data. I then use the CDiscRecorder object to get the supported media types. The supported media types return an integer that is defined in the enum IMAPI_MEDIA_PHYSICAL_TYPE type. Since I get values like IMAPI_MEDIA_TYPE_DVDPLUSR and IMAPI_MEDIA_TYPE_DVDDASHR, I have three member variables (m_isCdromSupported, m_isDvdSupported, and m_isDualLayerDvdSupported) that I set to true if any media in the family is supported. I then add these media types to a media type combobox and let users select what type of media they are going to use. I then use a very "rough" estimate to determine how much of the media the user has filled up.

void CBurnCDDlg::OnCbnSelchangeDeviceCombo()
  m_isCdromSupported = false;
  m_isDvdSupported = false;
  m_isDualLayerDvdSupported = false;
  int selectedIndex = m_deviceComboBox.GetCurSel();
  ASSERT(selectedIndex >= 0);
  if (selectedIndex < 0)
  CDiscRecorder* discRecorder =
  if (discRecorder != NULL)
   CDiscFormatData discFormatData;
   if  (!discFormatData.Initialize(discRecorder, CLIENT_NAME))
   // Display Supported Media Types
   CString supportedMediaTypes;
   ULONG totalMediaTypes = discFormatData.GetTotalSupportedMediaTypes();
   for (ULONG volIndex = 0; volIndex < totalMediaTypes; volIndex++)
    int mediaType = discFormatData.GetSupportedMediaType(volIndex);
    if (volIndex > 0)
     supportedMediaTypes += _T(", ");
    supportedMediaTypes += GetMediaTypeString(mediaType);
   // Add Media Selection
   if (m_isCdromSupported)
    int stringIndex = m_mediaTypeCombo.AddString(_T("700MB CD Media"));
    m_mediaTypeCombo.SetItemData(stringIndex, CD_MEDIA);
   if (m_isDvdSupported)
     int stringIndex = m_mediaTypeCombo.AddString(_T("4.7GB DVD Media"));
     m_mediaTypeCombo.SetItemData(stringIndex, DVD_MEDIA);
   if (m_isDualLayerDvdSupported)
    int stringIndex = m_mediaTypeCombo.AddString(_T("8.5GB Dual-Layer DVD"));
    m_mediaTypeCombo.SetItemData(stringIndex, DL_DVD_MEDIA);

When the user adds a file to the list, I create a CFileObject and I add it to the file listbox. I then call the UpdateCapacity function which calculates the total storage required by all the items in the file listbox and update the capacity progress bar.

void CBurnCDDlg::OnBnClickedAddFilesButton()
        ("All Files (*.*)|*.*||"), NULL, 0);
  if (fileDialog.DoModal() == IDOK)
    CFileObject* pFileObject = new CFileObject(fileDialog.GetPathName());
    int addIndex = m_fileListbox.AddString(pFileObject->GetName());
    m_fileListbox.SetItemDataPtr(addIndex, pFileObject);

When the user adds a folder to the list, I create a CDirObject and I add it to the file listbox. Just like the file object, I call the UpdateCapacity function to calculate the total storage required by all the items in the file listbox and update the capacity progress bar.

void CBurnCDDlg::OnBnClickedAddFolderButton()
  BROWSEINFO bi = {0};
  bi.hwndOwner = m_hWnd;
  LPITEMIDLIST lpidl = SHBrowseForFolder(&bi);
  if (!lpidl)
  TCHAR selectedPath[_MAX_PATH] = {0};
  if (SHGetPathFromIDList(lpidl, selectedPath))
    CDirObject* pDirObject = new CDirObject(selectedPath);
    int addIndex = m_fileListbox.AddString(pDirObject->GetName());
    m_fileListbox.SetItemDataPtr(addIndex, pDirObject);

When the user presses the Burn button, I disable the user interface and launch another thread, BurnThread, to perform the burn. This will keep the UI responsive during the burn process.

void CBurnCDDlg::OnBnClickedBurnButton()
  if (m_isBurning)
    m_isBurning = true;
    AfxBeginThread(BurnThread, this, THREAD_PRIORITY_NORMAL);
UINT CBurnCDDlg::BurnThread(LPVOID pParam)
  IStream* dataStream = NULL;
  CBurnCDDlg* pThis = (CBurnCDDlg*)pParam;
  if (!CreateMediaFileSystem(pThis, &dataStream))
  { // CreateMediaFileSystem reported error to UI
   return false;
  // Get the selected recording device from the combobox
  int selectedIndex = pThis->m_deviceComboBox.GetCurSel();
  ASSERT(selectedIndex >= 0);
  if (selectedIndex < 0)
    pThis->SendMessage(WM_BURN_FINISHED, 0, 
      (LPARAM)_T("Error: No Device Selected"));
    return 0;
  CDiscRecorder* pOrigDiscRecorder =
  if (pOrigDiscRecorder == NULL)
    // This should never happen
    pThis->SendMessage(WM_BURN_FINISHED, 0,
        (LPARAM)_T("Error: No Data for selected device"));
    return 0;
  // Did user cancel?
  if (pThis->GetCancelBurning())
    pThis->SendMessage(WM_BURN_FINISHED, 0, (LPARAM)_T("User Canceled!"));
    return 0;
  pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0,
        (LPARAM)_T("Initializing Disc Recorder..."));
  // Create another disc recorder because we're in a different thread
  CDiscRecorder discRecorder;
  CString errorMessage;
  if (discRecorder.Initialize(pOrigDiscRecorder->GetUniqueId()))
    if (discRecorder.AcquireExclusiveAccess(true, CLIENT_NAME))
     CDiscFormatData discFormatData;
     if (discFormatData.Initialize(&discRecorder, CLIENT_NAME))
      discFormatData.SetCloseMedia(pThis->m_closeMedia ? true : false);
      // Burn the media here
      discFormatData.Burn(pThis->m_hWnd, dataStream);
      // Release the IStream after burning
      // Eject Media if they chose
      if (pThis->m_ejectWhenFinished)
     // Finished Burning, GetHresult will determine if it was successful or not
     pThis->SendMessage(WM_BURN_FINISHED, discFormatData.GetHresult(),
     errorMessage.Format(_T("Failed: %s is exclusive owner"),
     pThis->SendMessage(WM_BURN_FINISHED, discRecorder.GetHresult(),
    errorMessage.Format(_T("Failed to initialize recorder - Unique ID:%s"),
    pThis->SendMessage(WM_BURN_FINISHED, discRecorder.GetHresult(),
   return 0;

UI Notifications

The worker thread communicates with the UI via SendMessage commands. I send Status Messages (WM_BURN_STATUS_MESSAGE) and Burn Finished (WM_BURN_FINISHED) messages from the worker thread to the UI.

I send event notifications to the UI with a WM_IMAPI_UPDATE message from the CDiscFormatDataEvent::Update function. I create an instance of the CDiscFormatDataEvent class, which implements the DDiscFormat2DataEvents interface, in the CDiscFormatData::Burn function. When it receives an event, it gets the data and sends it to the UI so it can update the status.


  • v1 - Dec 29, 2007

    • Initial release.
  • v2 - Jan 8, 2008

    • Converted project from Visual Studio 2008 to Visual Studio 2005.
    • Removed ATL from the CDiscFormatDataEvent class.
    • Sample application statically linked with MFC DLLs.
    </li />

    v3 - Jan 16, 2008

    </li />
    • Bug fix - Not setting image to size of media.
    • Supports extra large files. Thanks Dale Stewart.
    • Does not assert when InitializeDiscRecorder fails because of Virtual CDROMs, etc.
  • v4 - Dec 12, 2009

    • Updated the link to the latest Windows SDK.
    • Fixed a leak where an IStream wasn't being released.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Eric Haddan
Software Developer (Senior) Tranxition Corp
United States United States
Thank you for voting on my articles!



The Tranxition Developer's Blog[^]

You may also be interested in...

Comments and Discussions

Questionbuggy blu-ray support? Pin
Member 1102545817-Mar-17 12:14
memberMember 1102545817-Mar-17 12:14 
QuestionGUI Pin
Member 128805479-Dec-16 8:58
memberMember 128805479-Dec-16 8:58 
AnswerRe: GUI Pin
Member 1102545817-Mar-17 10:48
memberMember 1102545817-Mar-17 10:48 
QuestionFile system question Pin
Member 116480644-May-15 22:54
memberMember 116480644-May-15 22:54 
AnswerRe: File system question Pin
DaveCamp6-Oct-15 5:36
memberDaveCamp6-Oct-15 5:36 
GeneralRe: File system question Pin
Member 1102545817-Mar-17 10:49
memberMember 1102545817-Mar-17 10:49 
QuestionIs there any library for Java like Imapi Pin
Member 109670648-Jan-15 4:31
memberMember 109670648-Jan-15 4:31 
Questioncreate bootable cd/dvd Pin
saeed karimi8-Nov-14 21:59
membersaeed karimi8-Nov-14 21:59 
SuggestionOne read and the other IDiscFormat2Data.Write Pin
jiangyong62842211-Jun-14 18:00
memberjiangyong62842211-Jun-14 18:00 
Bugmany thanks!! Pin
Member 81519295-Jun-14 0:22
memberMember 81519295-Jun-14 0:22 
Questionwhy i am Not able to burn DVD-RW in next session? Pin
Member 1015248115-Jul-13 4:00
memberMember 1015248115-Jul-13 4:00 
Questionusing Source Code for GNU GPL Projects Pin
SepBen29-May-13 23:33
memberSepBen29-May-13 23:33 
AnswerRe: using Source Code for GNU GPL Projects Pin
Eric Haddan30-May-13 11:03
memberEric Haddan30-May-13 11:03 
Questionerror-code-0x80004005 Pin
Daryappa22-May-13 21:55
memberDaryappa22-May-13 21:55 
QuestionRe: error-code-0x80004005 Pin
ashag8716-Dec-15 23:00
memberashag8716-Dec-15 23:00 
QuestionStash file Pin
Member 974141211-Apr-13 23:37
memberMember 974141211-Apr-13 23:37 
QuestionError Readable CD or dvd for burning data again Pin
gauri_21vaidya23-Aug-12 21:26
membergauri_21vaidya23-Aug-12 21:26 
QuestionWindows 7 with IMAPI2 Pin
tantle1-Feb-12 8:50
membertantle1-Feb-12 8:50 
QuestionWrite Speed Pin
Member 849723420-Dec-11 2:49
memberMember 849723420-Dec-11 2:49 
QuestionBorland 6.0 Imapi2 Pin
stankomix122-Nov-11 23:26
memberstankomix122-Nov-11 23:26 
QuestionError 0x80040154 Pin
Member 79192399-Nov-11 10:39
memberMember 79192399-Nov-11 10:39 
GeneralUnable to Initialize IDiscMaster2 - Error:0x800401f0 Pin
PraChauhan20-Apr-11 20:13
memberPraChauhan20-Apr-11 20:13 
GeneralRe: Unable to Initialize IDiscMaster2 - Error:0x800401f0 Pin
xbanana8-May-11 12:06
memberxbanana8-May-11 12:06 
GeneralRe: Unable to Initialize IDiscMaster2 - Error:0x800401f0 Pin
jiachangyu08-Feb-12 22:54
memberjiachangyu08-Feb-12 22:54 
GeneralRe: Unable to Initialize IDiscMaster2 - Error:0x800401f0 Pin
jiachangyu08-Feb-12 22:55
memberjiachangyu08-Feb-12 22:55 
QuestionMultisession? Pin
aravindkrgec8-Mar-11 22:06
memberaravindkrgec8-Mar-11 22:06 
GeneralWindows XP SP3 + IMAPIv2.0 for Windows XP SP2 SP3 (KB932716) - ERROR Pin
pasztor.laszlo20-Feb-11 21:39
memberpasztor.laszlo20-Feb-11 21:39 
Generalbackup files to CD Pin
LoAnn8-Dec-10 10:58
memberLoAnn8-Dec-10 10:58 
QuestionCoCreateInstance Error Pin
Zhang Long24-Oct-10 18:59
memberZhang Long24-Oct-10 18:59 
AnswerRe: CoCreateInstance Error Pin
herowolf1-Jun-11 23:24
memberherowolf1-Jun-11 23:24 
QuestionHow to read cd / dvd manufacturer using IMAPI / IMAPI v2 ????? Pin
javadpro212-Jun-10 19:14
memberjavadpro212-Jun-10 19:14 
GeneralEnhanced Version Pin
Nic Wilson11-Jun-10 19:39
memberNic Wilson11-Jun-10 19:39 
GeneralRe: Enhanced Version Pin
bayview16-Sep-10 11:51
memberbayview16-Sep-10 11:51 
GeneralRe: Enhanced Version Pin
bayview16-Sep-10 12:17
memberbayview16-Sep-10 12:17 
GeneralCreating ISO image Pin
podeeshk5-Apr-10 23:26
memberpodeeshk5-Apr-10 23:26 
QuestionHow to connect IDiscFormat2Data and DDiscFormat2DataEvents without MFC or ATL? Pin
guardianoc9-Mar-10 23:01
memberguardianoc9-Mar-10 23:01 
AnswerRe: How to connect IDiscFormat2Data and DDiscFormat2DataEvents without MFC or ATL? Pin
Eric Haddan10-Mar-10 7:56
memberEric Haddan10-Mar-10 7:56 
GeneralRe: How to connect IDiscFormat2Data and DDiscFormat2DataEvents without MFC or ATL? Pin
guardianoc10-Mar-10 21:44
memberguardianoc10-Mar-10 21:44 
GeneralRe: How to connect IDiscFormat2Data and DDiscFormat2DataEvents without MFC or ATL? Pin
Eric Haddan11-Mar-10 2:45
memberEric Haddan11-Mar-10 2:45 
GeneralRe: How to connect IDiscFormat2Data and DDiscFormat2DataEvents without MFC or ATL? [modified] Pin
guardianoc11-Mar-10 4:59
memberguardianoc11-Mar-10 4:59 
GeneralRe: How to connect IDiscFormat2Data and DDiscFormat2DataEvents without MFC or ATL? Pin
Eric Haddan11-Mar-10 5:55
memberEric Haddan11-Mar-10 5:55 
AnswerRe: How to connect IDiscFormat2Data and DDiscFormat2DataEvents without MFC or ATL? Pin
yaseeen1-Aug-11 22:25
memberyaseeen1-Aug-11 22:25 
GeneralRe: How to connect IDiscFormat2Data and DDiscFormat2DataEvents without MFC or ATL? Pin
lg_36352-Feb-17 20:31
memberlg_36352-Feb-17 20:31 
Questionhow to create multisession disc? Pin
ming__nan18-Jan-10 1:24
memberming__nan18-Jan-10 1:24 
AnswerRe: how to create multisession disc? Pin
Eric Haddan19-Jan-10 8:47
memberEric Haddan19-Jan-10 8:47 
AnswerWindows 7 - CD Burning Locks Files on Hard Drive Fix Pin
Zyrenthian8-Dec-09 9:02
memberZyrenthian8-Dec-09 9:02 
GeneralRe: Windows 7 - CD Burning Locks Files on Hard Drive Fix Pin
Eric Haddan8-Dec-09 9:29
memberEric Haddan8-Dec-09 9:29 
GeneralRe: Windows 7 - CD Burning Locks Files on Hard Drive Fix Pin
Zyrenthian9-Dec-09 2:51
memberZyrenthian9-Dec-09 2:51 
GeneralRe: Windows 7 - CD Burning Locks Files on Hard Drive Fix Pin
Maddie from Dartford25-Feb-11 23:40
memberMaddie from Dartford25-Feb-11 23:40 
GeneralRe: Windows 7 - CD Burning Locks Files on Hard Drive Fix Pin
Nickm3242-Dec-11 11:51
memberNickm3242-Dec-11 11:51 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.171016.2 | Last Updated 12 Dec 2009
Article Copyright 2007 by Eric Haddan
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid