代码路上『App开发专区』『C/C++编程论坛』 例程: 用IMAPIv2.0来刻录CD/DVD

1  /  1  页   1 跳转 查看:5366

例程: 用IMAPIv2.0来刻录CD/DVD

例程: 用IMAPIv2.0来刻录CD/DVD

程序:

附件: BurnCD.zip (2008-3-14 21:46:24, 177.37 K)
该附件被下载次数 393


源码:

附件: BurnCD_src.zip (2008-3-14 21:46:24, 39.34 K)
该附件被下载次数 396




简介

Windows在Vsita操作系统的发布版中引入了新的IMAPIv2.0(Image Mastering API Version 2.0), 2.0对以前的IMAPI有了很大的改善。以前的IMAPI尽管可以用于CDROM,但是也有很大的限制,比如不能写DVD。而之所以有这个限制是因为当2001年Windows XP才发布的时候,还没有人有DVD刻录机。现在IMAPIv2可以让你写CD和DVD,也可以读写ISO文件。IMAPIv2.0其实也有个问题,就是它只能在Windows Vista下使用。不过2007年6月,微软发布了对Windows XP和Windows 2003更新包。你可以在这里下载

做开发需要下载安装微软的Windows SDK(Software Development Kit),这里面有编译应用程序所需的必须的头文件。你可以在这里下载

下载安装完SDK后,要确保Visual Studio的include路径里引用了SDK的include路径。另外就是如果你用的是Visual Studio 2005,你必须确保SDK的LIB路径在VS2005的LIB库列表中排在第一个。

代码的使用方法

代码里面已经写了几个围绕IMAPIv2接口的封装类,来辅助管理相应的接口。

1。CDiscMaster类封装了IDiscMaster接口,这个接口可以用来获得计算机上是否已经安装了相应的硬件设备,如果已经安装的话,还可以枚举该计算机上所有的CD,DVD驱动器。
2。CDiscRecorder类封装了IDiscRecorder2接口,这个接口代表了相应的硬件驱动器,可以用来获得驱动器的信息,比如制造商信息,逻辑驱动和所支持的介质。
3。CDiscFormatData类封装了IDiscFormat2Data接口,这个接口可以用来把数据到介质上。
4。CDiscFormatDataEvent类封装了DDiscFormat2DataEvents通知,可以用来接收接口IDiscFormat2Data的工作状态。

对于文件操作,代码里面写了一个基类CBaseObject,类里面包括三个函数:GetPath()、 GetName()、 GetSizeOnDisc(),GetPath返回文件或目录在该计算机上的完整路径。GetName仅返回文件或目录的文件名,结果可以用来屏幕显示,也可以用作刻录映像的根路径下的文件或目录的名字。GetSizeOnDisc是个纯虚函数,有两个类派生于CBaseObject类:CFileObject、 CDirObject。CFileObject类中GetSizeOnDisc返回文件在介质上所占的空间大小,CDirObject类中返回该目录下所有的文件和子目录的大小。

下面我仅说明一些主要的代码,你可以下载源码查看所有的代码。


包含IMAPI2头文件:

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


imapi2.h和imapi2error.h里面含有IMAPI的接口.imapi2fs.h和imapi2fserror.h里面含有IMAPI文件操作的接口。

创建CDiscMaster类的实例并初使化,循环得到每个设备的唯一ID。ID用来初使化CDiscRecord对象,然后用CDiscRecord对象获得的信息来填充组合框,并将CDiscRecord指针存储在组合框的对应项中。

CollapseCDiscMaster discMaster;
.
.
discMaster.Initialize();
.
.
long totalDevices = discMaster.GetTotalDevices();
for (long deviceIndex = 0; deviceIndex < totalDevices; deviceIndex++)
{
CString recorderUniqueID = discMaster.GetDeviceUniqueID(deviceIndex);
CDiscRecorder* pDiscRecorder = new CDiscRecorder();
pDiscRecorder->Initialize(recorderUniqueID);
//
// 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);
}


当用户在驱动组合框中选中一项时,先得到被选中的设备所对应的CDiscRecorder对象(存储在组合框对应的项中)。然后使用CDiscRecorder对象来得到设备所支持的介质类型,介质类型值是一种IMAPI_MEDIA_PHYSICAL_TYPE枚举类型。得到像IMAPI_MEDIA_TYPE_DVDPLUSR 和 IMAPI_MEDIA_TYPE_DVDDASHR之类的值后,如果有支持某种介质,则将将三个成员变量(m_isCdromSupported, m_isDvdSupported, and m_isDualLayerDvdSupported)相应的一个设为true。接着添加所有支持的介质类型到一个类型组合框,让用户来选择想使用介质类型。选择后再大概估计下介质已经被用去了多少空间。

Collapsevoid CBurnCDDlg::OnCbnSelchangeDeviceCombo()
{
  m_isCdromSupported = false;
  m_isDvdSupported = false;
  m_isDualLayerDvdSupported = false;
  m_mediaTypeCombo.ResetContent();
  int selectedIndex = m_deviceComboBox.GetCurSel();
  ASSERT(selectedIndex >= 0);
  if (selectedIndex < 0)
  {
  return;
  }
  CDiscRecorder* discRecorder =
  (CDiscRecorder*)m_deviceComboBox.GetItemDataPtr(selectedIndex);
  if (discRecorder != NULL)
  {
  CDiscFormatData discFormatData;
  if  (!discFormatData.Initialize(discRecorder, CLIENT_NAME))
  {
    return;
  }
  //
  // 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);
  }
  m_supportedMediaTypes.SetWindowText(supportedMediaTypes);
  //
  // 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);
  }
  m_mediaTypeCombo.SetCurSel(0);
  OnCbnSelchangeMediaTypeCombo();
  }
}


当用户添加了一个文件到文件列表框以后,就创建一个CFileObject对象,然后添加到列表框中。接着调用UpdateCapacity函数,函数用来计算文件列表框中所有文件所需的总空间大小,并且更新容量进度条。

void CBurnCDDlg::OnBnClickedAddFilesButton()
{
  CFileDialog fileDialog(TRUE, NULL, NULL, OFN_FILEMUSTEXIST, _T
        ("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);
    UpdateCapacity();
    EnableBurnButton();
  }
}


当用户添加了一个文件夹到文件列表框后,就创建一个CDirObject对象,然后添加到列表框中。就像上面一样,接着调用UpdateCapacity函数来计算文件列表框中所有文件所需的总空间大小,并且更新容量进度条。

void CBurnCDDlg::OnBnClickedAddFolderButton()
{
  BROWSEINFO bi = {0};
  bi.hwndOwner = m_hWnd;
  bi.ulFlags = BIF_RETURNONLYFSDIRS|BIF_USENEWUI;
  LPITEMIDLIST lpidl = SHBrowseForFolder(&bi);
  if (!lpidl)
    return;
  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);
    UpdateCapacity();
    EnableBurnButton();
  }
}


当用户按下Burn按钮,先让用户界面失效,接着启动工作线程BurnThread,来实现刻录。启动另一个线程可以避免程序挂起。

Collapsevoid CBurnCDDlg::OnBnClickedBurnButton()
{
  if (m_isBurning)
  {
    SetCancelBurning(true);
  }
  else
  {
    SetCancelBurning(false);
    m_isBurning = true;
    UpdateData();
    EnableUI(false);
    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 =
    (CDiscRecorder*)pThis->m_deviceComboBox.GetItemDataPtr(selectedIndex);
  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);
      //
      // Eject Media if they chose
      //
      if (pThis->m_ejectWhenFinished)
      {
      discRecorder.EjectMedia();
      }
    }
    discRecorder.ReleaseExclusiveAccess();
    //
    // Finished Burning, GetHresult will determine if it was successful or not
    //
    pThis->SendMessage(WM_BURN_FINISHED, discFormatData.GetHresult(),
      (LPARAM)(LPCTSTR)discFormatData.GetErrorMessage());
    }
    else
    {
    errorMessage.Format(_T("Failed: %s is exclusive owner"),
      (LPCTSTR)discRecorder.ExclusiveAccessOwner());
    pThis->SendMessage(WM_BURN_FINISHED, discRecorder.GetHresult(),
      (LPARAM)(LPCTSTR)errorMessage);
    }
  }
  else
  {
    errorMessage.Format(_T("Failed to initialize recorder - Unique ID:%s"),
    (LPCTSTR)pOrigDiscRecorder->GetUniqueId());
    pThis->SendMessage(WM_BURN_FINISHED, discRecorder.GetHresult(),
    (LPARAM)(LPCTSTR)errorMessage);
  }
  return 0;
}


与用户界面通信

工作线程与用户界面用函数SendMessage来通信,可以从工作线程中发送状态消息(WM_BURN_STATUS_MESSAGE),和刻录完成消息(WM_BURN_FINISHED)到用户界面上。

在CDiscFormatDataEvent::Update函数中用消息WM_IMAPI_UPDATE来通知用户界面。先在函数CDiscFormatData::Burn中创建CDiscFormatDataEvent类的实例,这个类包装了DDiscFormat2DataEvents接口,当其接收到一个事件,就将获得的数据发送到用户界面,从而更新当前状态。
最后编辑cychou 最后编辑于 2008-03-15 11:14:51
 

回复:例程: 用IMAPIv2.0来烧录CD/DVD

原文:

Introduction
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 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;
.
.
discMaster.Initialize();
.
.
long totalDevices = discMaster.GetTotalDevices();
for (long deviceIndex = 0; deviceIndex < totalDevices; deviceIndex++)
{
CString recorderUniqueID = discMaster.GetDeviceUniqueID(deviceIndex);
CDiscRecorder* pDiscRecorder = new CDiscRecorder();
pDiscRecorder->Initialize(recorderUniqueID);
//
// 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:nCbnSelchangeDeviceCombo()
{
  m_isCdromSupported = false;
  m_isDvdSupported = false;
  m_isDualLayerDvdSupported = false;
  m_mediaTypeCombo.ResetContent();
  int selectedIndex = m_deviceComboBox.GetCurSel();
  ASSERT(selectedIndex >= 0);
  if (selectedIndex < 0)
  {
  return;
  }
  CDiscRecorder* discRecorder =
  (CDiscRecorder*)m_deviceComboBox.GetItemDataPtr(selectedIndex);
  if (discRecorder != NULL)
  {
  CDiscFormatData discFormatData;
  if  (!discFormatData.Initialize(discRecorder, CLIENT_NAME))
  {
    return;
  }
  //
  // 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);
  }
  m_supportedMediaTypes.SetWindowText(supportedMediaTypes);
  //
  // 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);
  }
  m_mediaTypeCombo.SetCurSel(0);
  OnCbnSelchangeMediaTypeCombo();
  }
}
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:nBnClickedAddFilesButton()
{
  CFileDialog fileDialog(TRUE, NULL, NULL, OFN_FILEMUSTEXIST, _T
        ("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);
    UpdateCapacity();
    EnableBurnButton();
  }
}
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:nBnClickedAddFolderButton()
{
  BROWSEINFO bi = {0};
  bi.hwndOwner = m_hWnd;
  bi.ulFlags = BIF_RETURNONLYFSDIRS|BIF_USENEWUI;
  LPITEMIDLIST lpidl = SHBrowseForFolder(&bi);
  if (!lpidl)
    return;
  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);
    UpdateCapacity();
    EnableBurnButton();
  }
}
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:nBnClickedBurnButton()
{
  if (m_isBurning)
  {
    SetCancelBurning(true);
  }
  else
  {
    SetCancelBurning(false);
    m_isBurning = true;
    UpdateData();
    EnableUI(false);
    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 =
    (CDiscRecorder*)pThis->m_deviceComboBox.GetItemDataPtr(selectedIndex);
  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);
      //
      // Eject Media if they chose
      //
      if (pThis->m_ejectWhenFinished)
      {
      discRecorder.EjectMedia();
      }
    }
    discRecorder.ReleaseExclusiveAccess();
    //
    // Finished Burning, GetHresult will determine if it was successful or not
    //
    pThis->SendMessage(WM_BURN_FINISHED, discFormatData.GetHresult(),
      (LPARAM)(LPCTSTR)discFormatData.GetErrorMessage());
    }
    else
    {
    errorMessage.Format(_T("Failed: %s is exclusive owner"),
      (LPCTSTR)discRecorder.ExclusiveAccessOwner());
    pThis->SendMessage(WM_BURN_FINISHED, discRecorder.GetHresult(),
      (LPARAM)(LPCTSTR)errorMessage);
    }
  }
  else
  {
    errorMessage.Format(_T("Failed to initialize recorder - Unique ID:%s"),
    (LPCTSTR)pOrigDiscRecorder->GetUniqueId());
    pThis->SendMessage(WM_BURN_FINISHED, discRecorder.GetHresult(),
    (LPARAM)(LPCTSTR)errorMessage);
  }
  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.
 
1  /  1  页   1 跳转

版权所有 代码路上  CODES63.NET
特别声明:本站资料和信息全部来自互联网和网站会员上传,若侵犯作者权益请与本站联系,我们将在24小时内删除!  Sitemap

Powered by Discuz!NT 2.1.202    Copyright © 2001-2010 Comsenz Inc.
Processed in 0.0625 second(s) , 5 queries.
返顶部