/* * PortBurn * Windows XP IMAPI implementation * * Authors: * Leland Lucius * * The following MSDN page was used as a guide: * http://msdn2.microsoft.com/en-us/library/aa366236.aspx * * License: LGPL */ #include "portburn.h" #define _WIN32_WINNT 0x0400 #include #include #include typedef struct { int ver; void *realhandle; } PBHandle; #define PBFUNC(r,f) \ extern r PortBurn_v1_ ## f; \ extern r PortBurn_v2_ ## f; PBFUNC(void *, Open()); PBFUNC(void, Close(void *handle)); PBFUNC(char *, LastError(void *handle)); PBFUNC(int, GetNumDevices(void *handle)); PBFUNC(char *, GetDeviceName(void *handle, int index)); PBFUNC(int, OpenDevice(void *handle, int index)); PBFUNC(int, CloseDevice(void *handle)); PBFUNC(int, EjectDevice(void *handle)); PBFUNC(int, StartErasing(void *handle, int type)); PBFUNC(int, GetEraseStatus(void *handle, float *out_fraction_complete)); PBFUNC(int, StartStaging(void *handle, const char *tmpdir)); PBFUNC(int, StartTrack(void *handle, const char *name)); PBFUNC(int, AddFrame(void *handle, short *buffer)); PBFUNC(int, EndTrack(void *handle)); PBFUNC(int, StartBurning(void *handle)); PBFUNC(int, CancelBurning(void *handle)); PBFUNC(int, GetStatus(void *handle, float *out_fraction_complete)); PBFUNC(int, GetOption(void *handle, int option, int *value)); PBFUNC(int, SetOption(void *handle, int option, int value)); PBFUNC(int, GetSupportedSpeeds(void *handle, int *cnt, int *option[])); PBFUNC(int, GetMediaState(void *handle, int *state)); enum { IMAPI_V1, IMAPI_V2, IMAPI_VERS }; struct { void *(*Open)(); void (*Close)(void *handle); char *(*LastError)(void *handle); int (*GetNumDevices)(void *handle); char *(*GetDeviceName)(void *handle, int index); int (*OpenDevice)(void *handle, int index); int (*CloseDevice)(void *handle); int (*EjectDevice)(void *handle); int (*StartErasing)(void *handle, int type); int (*GetEraseStatus)(void *handle, float *out_fraction_complete); int (*StartStaging)(void *handle, const char *tmpdir); int (*StartTrack)(void *handle, const char *name); int (*AddFrame)(void *handle, short *buffer); int (*EndTrack)(void *handle); int (*StartBurning)(void *handle); int (*CancelBurning)(void *handle); int (*GetStatus)(void *handle, float *out_fraction_complete); int (*GetOption)(void *handle, int option, int *value); int (*SetOption)(void *handle, int option, int value); int (*GetSupportedSpeeds)(void *handle, int *cnt, int *option[]); int (*GetMediaState)(void *handle, int *state); } vectors[IMAPI_VERS] = { { PortBurn_v1_Open, PortBurn_v1_Close, PortBurn_v1_LastError, PortBurn_v1_GetNumDevices, PortBurn_v1_GetDeviceName, PortBurn_v1_OpenDevice, PortBurn_v1_CloseDevice, PortBurn_v1_EjectDevice, PortBurn_v1_StartErasing, PortBurn_v1_GetEraseStatus, PortBurn_v1_StartStaging, PortBurn_v1_StartTrack, PortBurn_v1_AddFrame, PortBurn_v1_EndTrack, PortBurn_v1_StartBurning, PortBurn_v1_CancelBurning, PortBurn_v1_GetStatus, PortBurn_v1_GetOption, PortBurn_v1_SetOption, PortBurn_v1_GetSupportedSpeeds, PortBurn_v1_GetMediaState, }, { PortBurn_v2_Open, PortBurn_v2_Close, PortBurn_v2_LastError, PortBurn_v2_GetNumDevices, PortBurn_v2_GetDeviceName, PortBurn_v2_OpenDevice, PortBurn_v2_CloseDevice, PortBurn_v2_EjectDevice, PortBurn_v2_StartErasing, PortBurn_v2_GetEraseStatus, PortBurn_v2_StartStaging, PortBurn_v2_StartTrack, PortBurn_v2_AddFrame, PortBurn_v2_EndTrack, PortBurn_v2_StartBurning, PortBurn_v2_CancelBurning, PortBurn_v2_GetStatus, PortBurn_v2_GetOption, PortBurn_v2_SetOption, PortBurn_v2_GetSupportedSpeeds, PortBurn_v2_GetMediaState, } }; void *PortBurn_Open() { PBHandle *h; HRESULT hres; IDiscMaster *pV1; IDiscMaster2 *pV2; hres = CoInitializeEx(0, COINIT_APARTMENTTHREADED); if (FAILED(hres)) { return NULL; } h = (PBHandle *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PBHandle)); if (h == NULL) { CoUninitialize(); return NULL; } hres = CoCreateInstance(__uuidof(MsftDiscMaster2), NULL, CLSCTX_ALL, IID_IDiscMaster2, (void **)&pV2); if (FAILED(hres)) { hres = CoCreateInstance(__uuidof(MSDiscMasterObj), NULL, CLSCTX_ALL, IID_IDiscMaster, (void **)&pV1); if (FAILED(hres)) { HeapFree(GetProcessHeap(), 0, h); CoUninitialize(); return NULL; } pV1->Release(); h->ver = IMAPI_V1; } else { pV2->Release(); h->ver = IMAPI_V2; } //h->ver = IMAPI_V1; h->realhandle = vectors[h->ver].Open(); if (h->realhandle == NULL) { HeapFree(GetProcessHeap(), 0, h); CoUninitialize(); return NULL; } return h; } /* Cleanup */ void PortBurn_Close(void *handle) { PBHandle *h = (PBHandle *) handle; if (h == NULL) { return; } vectors[h->ver].Close(h->realhandle); HeapFree(GetProcessHeap(), 0, h); CoUninitialize(); } char *PortBurn_LastError(void *handle) { PBHandle *h = (PBHandle *) handle; if (h == NULL) { return NULL; } return vectors[h->ver].LastError(h->realhandle); } int PortBurn_GetNumDevices(void *handle) { PBHandle *h = (PBHandle *) handle; if (h == NULL) { return 0; } return vectors[h->ver].GetNumDevices(h->realhandle); } /* Get the name of the device with a given index. Only valid after a call to GetNumDevices. */ char *PortBurn_GetDeviceName(void *handle, int index) { PBHandle *h = (PBHandle *) handle; if (h == NULL) { return NULL; } return vectors[h->ver].GetDeviceName(h->realhandle, index); } int PortBurn_OpenDevice(void *handle, int index) { PBHandle *h = (PBHandle *) handle; if (h == NULL) { return pbErrNoHandle; } return vectors[h->ver].OpenDevice(h->realhandle, index); } int PortBurn_CloseDevice(void *handle) { PBHandle *h = (PBHandle *) handle; if (h == NULL) { return pbErrNoHandle; } return vectors[h->ver].CloseDevice(h->realhandle); } int PortBurn_EjectDevice(void *handle) { PBHandle *h = (PBHandle *) handle; if (h == NULL) { return pbErrNoHandle; } return vectors[h->ver].EjectDevice(h->realhandle); } int PortBurn_StartStaging(void *handle, const char *tmpdir) { PBHandle *h = (PBHandle *) handle; if (h == NULL) { return pbErrNoHandle; } return vectors[h->ver].StartStaging(h->realhandle, tmpdir); } int PortBurn_StartTrack(void *handle, const char *name) { PBHandle *h = (PBHandle *) handle; if (h == NULL) { return pbErrNoHandle; } return vectors[h->ver].StartTrack(h->realhandle, name); } int PortBurn_AddFrame(void *handle, short *buffer) { PBHandle *h = (PBHandle *) handle; if (h == NULL) { return pbErrNoHandle; } return vectors[h->ver].AddFrame(h->realhandle, buffer); } int PortBurn_EndTrack(void *handle) { PBHandle *h = (PBHandle *) handle; if (h == NULL) { return pbErrNoHandle; } return vectors[h->ver].EndTrack(h->realhandle); } int PortBurn_StartBurning(void *handle) { PBHandle *h = (PBHandle *) handle; if (h == NULL) { return pbErrNoHandle; } return vectors[h->ver].StartBurning(h->realhandle); } int PortBurn_CancelBurning(void *handle) { PBHandle *h = (PBHandle *) handle; if (h == NULL) { return pbErrNoHandle; } return vectors[h->ver].CancelBurning(h->realhandle); } int PortBurn_GetStatus(void *handle, float *out_fraction_complete) { PBHandle *h = (PBHandle *) handle; if (h == NULL) { return pbErrNoHandle; } return vectors[h->ver].GetStatus(h->realhandle, out_fraction_complete); } int PortBurn_GetOption(void *handle, int option, int *value) { PBHandle *h = (PBHandle *) handle; if (h == NULL) { return pbErrNoHandle; } return vectors[h->ver].GetOption(h->realhandle, option, value); } int PortBurn_SetOption(void *handle, int option, int value) { PBHandle *h = (PBHandle *) handle; if (h == NULL) { return pbErrNoHandle; } return vectors[h->ver].SetOption(h->realhandle, option, value); } int PortBurn_GetSpeeds(void *handle, int *cnt, int *speeds[]) { return -1; } /* Erase the media in the currently opened device */ int PortBurn_StartErasing(void *handle, int type) { PBHandle *h = (PBHandle *) handle; if (h == NULL) { return pbErrNoHandle; } return vectors[h->ver].StartErasing(h->realhandle, type); } int PortBurn_GetEraseStatus(void *handle, float *out_fraction_complete) { PBHandle *h = (PBHandle *) handle; if (h == NULL) { return pbErrNoHandle; } return vectors[h->ver].GetEraseStatus(h->realhandle, out_fraction_complete); } /* */ int PortBurn_GetMediaState(void *handle, int *state) { PBHandle *h = (PBHandle *) handle; if (h == NULL) { return pbErrNoHandle; } return vectors[h->ver].GetMediaState(h->realhandle, state); }