2008-09-17 113 views
13

我們需要以編程方式將文件刻錄到使用Borlands Turbo C++開發的C \ C++ Windows XP/Vista應用程序中的CD。Windows CD刻錄API

什麼是最簡單和最好的方法來做到這一點?我們更喜歡本地Windows API(不依賴於MFC),以便在任何第三方軟件/驅動程序可用時不依賴任何第三方軟件/驅動程序。

回答

15

我們使用以下:

將文件存儲在由GetBurnPath返回的目錄,然後寫使用燒錄。 GetCDRecordableInfo用於檢查CD何時準備就緒。

#include <stdio.h> 
#include <imapi.h> 
#include <windows.h> 

struct MEDIAINFO { 
    BYTE nSessions; 
    BYTE nLastTrack; 
    ULONG nStartAddress; 
    ULONG nNextWritable; 
    ULONG nFreeBlocks; 
}; 
//============================================================================== 
// Description: CD burning on Windows XP 
//============================================================================== 
#define CSIDL_CDBURN_AREA    0x003b 
SHSTDAPI_(BOOL) SHGetSpecialFolderPathA(HWND hwnd, LPSTR pszPath, int csidl, BOOL fCreate); 
SHSTDAPI_(BOOL) SHGetSpecialFolderPathW(HWND hwnd, LPWSTR pszPath, int csidl, BOOL fCreate); 
#ifdef UNICODE 
#define SHGetSpecialFolderPath SHGetSpecialFolderPathW 
#else 
#define SHGetSpecialFolderPath SHGetSpecialFolderPathA 
#endif 
//============================================================================== 
// Interface IDiscMaster 
const IID IID_IDiscMaster = {0x520CCA62,0x51A5,0x11D3,{0x91,0x44,0x00,0x10,0x4B,0xA1,0x1C,0x5E}}; 
const CLSID CLSID_MSDiscMasterObj = {0x520CCA63,0x51A5,0x11D3,{0x91,0x44,0x00,0x10,0x4B,0xA1,0x1C,0x5E}}; 

typedef interface ICDBurn ICDBurn; 
// Interface ICDBurn 
const IID IID_ICDBurn = {0x3d73a659,0xe5d0,0x4d42,{0xaf,0xc0,0x51,0x21,0xba,0x42,0x5c,0x8d}}; 
const CLSID CLSID_CDBurn = {0xfbeb8a05,0xbeee,0x4442,{0x80,0x4e,0x40,0x9d,0x6c,0x45,0x15,0xe9}}; 

MIDL_INTERFACE("3d73a659-e5d0-4d42-afc0-5121ba425c8d") 
ICDBurn : public IUnknown 
{ 
public: 
    virtual HRESULT STDMETHODCALLTYPE GetRecorderDriveLetter(
     /* [size_is][out] */ LPWSTR pszDrive, 
     /* [in] */ UINT cch) = 0; 

    virtual HRESULT STDMETHODCALLTYPE Burn(
     /* [in] */ HWND hwnd) = 0; 

    virtual HRESULT STDMETHODCALLTYPE HasRecordableDrive(
     /* [out] */ BOOL *pfHasRecorder) = 0; 
}; 
//============================================================================== 
// Description: Get burn pathname 
// Parameters:  pathname - must be at least MAX_PATH in size 
// Returns:  Non-zero for an error 
// Notes:   CoInitialize(0) must be called once in application 
//============================================================================== 
int GetBurnPath(char *path) 
{ 
    ICDBurn* pICDBurn; 
    int ret = 0; 

    if (SUCCEEDED(CoCreateInstance(CLSID_CDBurn, NULL,CLSCTX_INPROC_SERVER,IID_ICDBurn,(LPVOID*)&pICDBurn))) { 
     BOOL flag; 
     if (pICDBurn->HasRecordableDrive(&flag) == S_OK) { 
      if (SHGetSpecialFolderPath(0, path, CSIDL_CDBURN_AREA, 0)) { 
       strcat(path, "\\"); 
      } 
      else { 
       ret = 1; 
      } 
     } 
     else { 
      ret = 2; 
     } 
     pICDBurn->Release(); 
    } 
    else { 
     ret = 3; 
    } 
    return ret; 
} 
//============================================================================== 
// Description: Get CD pathname 
// Parameters:  pathname - must be at least 5 bytes in size 
// Returns:  Non-zero for an error 
// Notes:   CoInitialize(0) must be called once in application 
//============================================================================== 
int GetCDPath(char *path) 
{ 
    ICDBurn* pICDBurn; 
    int ret = 0; 

    if (SUCCEEDED(CoCreateInstance(CLSID_CDBurn, NULL,CLSCTX_INPROC_SERVER,IID_ICDBurn,(LPVOID*)&pICDBurn))) { 
     BOOL flag; 
     WCHAR drive[5]; 
     if (pICDBurn->GetRecorderDriveLetter(drive, 4) == S_OK) { 
      sprintf(path, "%S", drive); 
     } 
     else { 
      ret = 1; 
     } 
     pICDBurn->Release(); 
    } 
    else { 
     ret = 3; 
    } 
    return ret; 
} 
//============================================================================== 
// Description: Burn CD 
// Parameters:  None 
// Returns:  Non-zero for an error 
// Notes:   CoInitialize(0) must be called once in application 
//============================================================================== 
int Burn(void) 
{ 
    ICDBurn* pICDBurn; 
    int ret = 0; 

    if (SUCCEEDED(CoCreateInstance(CLSID_CDBurn, NULL,CLSCTX_INPROC_SERVER,IID_ICDBurn,(LPVOID*)&pICDBurn))) { 
     if (pICDBurn->Burn(NULL) != S_OK) { 
      ret = 1; 
     } 
     pICDBurn->Release(); 
    } 
    else { 
     ret = 2; 
    } 
    return ret; 
} 
//============================================================================== 
bool GetCDRecordableInfo(long *FreeSpaceSize) 
{ 
    bool Result = false; 
    IDiscMaster *idm = NULL; 
    IDiscRecorder *idr = NULL; 
    IEnumDiscRecorders *pEnumDiscRecorders = NULL; 
    ULONG cnt; 
    long type; 
    long mtype; 
    long mflags; 
    MEDIAINFO mi; 

    try { 
     CoCreateInstance(CLSID_MSDiscMasterObj, 0, CLSCTX_ALL, IID_IDiscMaster, (void**)&idm); 
     idm->Open(); 
     idm->EnumDiscRecorders(&pEnumDiscRecorders); 
     pEnumDiscRecorders->Next(1, &idr, &cnt); 
     pEnumDiscRecorders->Release(); 

     idr->OpenExclusive(); 
     idr->GetRecorderType(&type); 
     idr->QueryMediaType(&mtype, &mflags); 
     idr->QueryMediaInfo(&mi.nSessions, &mi.nLastTrack, &mi.nStartAddress, &mi.nNextWritable, &mi.nFreeBlocks); 
     idr->Release(); 

     idm->Close(); 
     idm->Release(); 
     Result = true; 
    } 
    catch (...) { 
     Result = false; 
    } 

    if (Result == true) { 
     Result = false; 
     if (mtype == 0) { 
      // No Media inserted 
      Result = false; 
     } 
     else { 
      if ((mflags & 0x04) == 0x04) { 
       // Writable Media 
       Result = true; 
      } 
      else { 
       Result = false; 
      } 

      if (Result == true) { 
       *FreeSpaceSize = (mi.nFreeBlocks * 2048); 
      } 
      else { 
       *FreeSpaceSize = 0; 
      } 
     } 
    } 

    return Result; 
} 
+0

謝謝,這是完美的。 – QAZ 2008-09-19 13:56:35

-1

你應該可以使用shell的ICDBurn接口。回到XP日,MFC甚至沒有任何CD刻錄類。我會看看我能否爲你找到一些例子,但是從我看過這個過程已經有一段時間了。

4

爲了配合接受的答案,我們添加了這個輔助函數來編程更改動態燒傷目錄,因爲這是我們的一個要求。

typedef HMODULE (WINAPI * SHSETFOLDERPATHA)(int , HANDLE , DWORD , LPCTSTR); 

int SetBurnPath(char * cpPath) 
{ 
    SHSETFOLDERPATHA pSHSetFolderPath; 
    HANDLE hShell = LoadLibraryA("shell32.dll"); 
    if(hShell == NULL) 
     return -2; 

    DWORD dwOrdinal = 0x00000000 + 231; 

    pSHSetFolderPath = (SHSETFOLDERPATHA)GetProcAddress(hShell, (LPCSTR)dwOrdinal); 
    if(pSHSetFolderPath == NULL) 
     return -3; 

    if(pSHSetFolderPath(CSIDL_CDBURN_AREA, NULL, 0, cpPath) == S_OK) 
     return 0; 

    return -1; 
}