2008-09-17 18 views
13

Necesitamos programar programáticamente archivos en CD en una aplicación C/C++ Windows XP/Vista que estamos desarrollando usando Borlands Turbo C++.Windows CD Burning API

¿Cuál es la forma más simple y mejor para hacer esto? Preferiríamos una API nativa de Windows (que no dependa de MFC) para no depender de ningún software/controlador de terceros si hay alguno disponible.

Respuesta

15

Se utilizó la siguiente:

Almacenar archivos en el directorio devuelto por GetBurnPath, a continuación, escribir usando Burn. GetCDRecordableInfo se utiliza para verificar cuándo el CD está listo.

#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

Gracias, eso es perfecto. – QAZ

+0

También funciona sin privilegios de administrador, gracias – elarmando

-1

Debería poder usar la interfaz ICDBurn de la carcasa. De vuelta en el día de XP, MFC ni siquiera tenía clases para la grabación de CD. Veré si puedo encontrar algunos ejemplos para ti, pero ha pasado un tiempo desde que miré esto.

4

Para complementar la respuesta aceptada, hemos añadido esta función auxiliar para cambiar mediante programación el directorio quemadura sobre la marcha ya que esto era un requisito de la nuestra.

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; 
}