1 /*
2  * PortBurn
3  * Windows XP IMAPI implementation
4  *
5  * Authors:
6  *   Leland Lucius
7  *
8  * The following MSDN page was used as a guide:
9  *   http://msdn2.microsoft.com/en-us/library/aa366236.aspx
10  *
11  * License: LGPL
12  */
13 
14 #include "portburn.h"
15 
16 #define _WIN32_WINNT 0x0400
17 
18 #include <windows.h>
19 #include <imapi.h>
20 #include <imapi2.h>
21 
22 typedef struct {
23    int   ver;
24    void  *realhandle;
25 } PBHandle;
26 
27 #define PBFUNC(r,f)              \
28    extern r PortBurn_v1_ ## f;   \
29    extern r PortBurn_v2_ ## f;
30 
31 PBFUNC(void *, Open());
32 PBFUNC(void, Close(void *handle));
33 PBFUNC(char *, LastError(void *handle));
34 PBFUNC(int, GetNumDevices(void *handle));
35 PBFUNC(char *, GetDeviceName(void *handle, int index));
36 PBFUNC(int, OpenDevice(void *handle, int index));
37 PBFUNC(int, CloseDevice(void *handle));
38 PBFUNC(int, EjectDevice(void *handle));
39 PBFUNC(int, StartErasing(void *handle, int type));
40 PBFUNC(int, GetEraseStatus(void *handle, float *out_fraction_complete));
41 PBFUNC(int, StartStaging(void *handle, const char *tmpdir));
42 PBFUNC(int, StartTrack(void *handle, const char *name));
43 PBFUNC(int, AddFrame(void *handle, short *buffer));
44 PBFUNC(int, EndTrack(void *handle));
45 PBFUNC(int, StartBurning(void *handle));
46 PBFUNC(int, CancelBurning(void *handle));
47 PBFUNC(int, GetStatus(void *handle, float *out_fraction_complete));
48 PBFUNC(int, GetOption(void *handle, int option, int *value));
49 PBFUNC(int, SetOption(void *handle, int option, int value));
50 PBFUNC(int, GetSupportedSpeeds(void *handle, int *cnt, int *option[]));
51 PBFUNC(int, GetMediaState(void *handle, int *state));
52 
53 enum {
54    IMAPI_V1,
55    IMAPI_V2,
56    IMAPI_VERS
57 };
58 
59 struct
60 {
61    void *(*Open)();
62    void (*Close)(void *handle);
63    char *(*LastError)(void *handle);
64    int (*GetNumDevices)(void *handle);
65    char *(*GetDeviceName)(void *handle, int index);
66    int (*OpenDevice)(void *handle, int index);
67    int (*CloseDevice)(void *handle);
68    int (*EjectDevice)(void *handle);
69    int (*StartErasing)(void *handle, int type);
70    int (*GetEraseStatus)(void *handle, float *out_fraction_complete);
71    int (*StartStaging)(void *handle, const char *tmpdir);
72    int (*StartTrack)(void *handle, const char *name);
73    int (*AddFrame)(void *handle, short *buffer);
74    int (*EndTrack)(void *handle);
75    int (*StartBurning)(void *handle);
76    int (*CancelBurning)(void *handle);
77    int (*GetStatus)(void *handle, float *out_fraction_complete);
78    int (*GetOption)(void *handle, int option, int *value);
79    int (*SetOption)(void *handle, int option, int value);
80    int (*GetSupportedSpeeds)(void *handle, int *cnt, int *option[]);
81    int (*GetMediaState)(void *handle, int *state);
82 }
83 vectors[IMAPI_VERS] =
84 {
85    {
86       PortBurn_v1_Open,
87       PortBurn_v1_Close,
88       PortBurn_v1_LastError,
89       PortBurn_v1_GetNumDevices,
90       PortBurn_v1_GetDeviceName,
91       PortBurn_v1_OpenDevice,
92       PortBurn_v1_CloseDevice,
93       PortBurn_v1_EjectDevice,
94       PortBurn_v1_StartErasing,
95       PortBurn_v1_GetEraseStatus,
96       PortBurn_v1_StartStaging,
97       PortBurn_v1_StartTrack,
98       PortBurn_v1_AddFrame,
99       PortBurn_v1_EndTrack,
100       PortBurn_v1_StartBurning,
101       PortBurn_v1_CancelBurning,
102       PortBurn_v1_GetStatus,
103       PortBurn_v1_GetOption,
104       PortBurn_v1_SetOption,
105       PortBurn_v1_GetSupportedSpeeds,
106       PortBurn_v1_GetMediaState,
107    },
108    {
109       PortBurn_v2_Open,
110       PortBurn_v2_Close,
111       PortBurn_v2_LastError,
112       PortBurn_v2_GetNumDevices,
113       PortBurn_v2_GetDeviceName,
114       PortBurn_v2_OpenDevice,
115       PortBurn_v2_CloseDevice,
116       PortBurn_v2_EjectDevice,
117       PortBurn_v2_StartErasing,
118       PortBurn_v2_GetEraseStatus,
119       PortBurn_v2_StartStaging,
120       PortBurn_v2_StartTrack,
121       PortBurn_v2_AddFrame,
122       PortBurn_v2_EndTrack,
123       PortBurn_v2_StartBurning,
124       PortBurn_v2_CancelBurning,
125       PortBurn_v2_GetStatus,
126       PortBurn_v2_GetOption,
127       PortBurn_v2_SetOption,
128       PortBurn_v2_GetSupportedSpeeds,
129       PortBurn_v2_GetMediaState,
130    }
131 };
132 
PortBurn_Open()133 void *PortBurn_Open()
134 {
135    PBHandle *h;
136    HRESULT hres;
137    IDiscMaster *pV1;
138    IDiscMaster2 *pV2;
139 
140    hres = CoInitializeEx(0, COINIT_APARTMENTTHREADED);
141    if (FAILED(hres)) {
142       return NULL;
143    }
144 
145    h = (PBHandle *) HeapAlloc(GetProcessHeap(),
146                               HEAP_ZERO_MEMORY,
147                               sizeof(PBHandle));
148    if (h == NULL) {
149       CoUninitialize();
150       return NULL;
151    }
152 
153    hres = CoCreateInstance(__uuidof(MsftDiscMaster2),
154                            NULL,
155                            CLSCTX_ALL,
156                            IID_IDiscMaster2,
157                            (void **)&pV2);
158 
159    if (FAILED(hres)) {
160       hres = CoCreateInstance(__uuidof(MSDiscMasterObj),
161                               NULL,
162                               CLSCTX_ALL,
163                               IID_IDiscMaster,
164                               (void **)&pV1);
165       if (FAILED(hres)) {
166          HeapFree(GetProcessHeap(), 0, h);
167          CoUninitialize();
168          return NULL;
169       }
170       pV1->Release();
171       h->ver = IMAPI_V1;
172    }
173    else {
174       pV2->Release();
175       h->ver = IMAPI_V2;
176    }
177 
178 //h->ver = IMAPI_V1;
179 
180    h->realhandle = vectors[h->ver].Open();
181    if (h->realhandle == NULL) {
182          HeapFree(GetProcessHeap(), 0, h);
183          CoUninitialize();
184          return NULL;
185    }
186 
187    return h;
188 }
189 
190 /* Cleanup */
PortBurn_Close(void * handle)191 void PortBurn_Close(void *handle)
192 {
193    PBHandle *h = (PBHandle *) handle;
194 
195    if (h == NULL) {
196       return;
197    }
198 
199    vectors[h->ver].Close(h->realhandle);
200 
201    HeapFree(GetProcessHeap(), 0, h);
202 
203    CoUninitialize();
204 }
205 
PortBurn_LastError(void * handle)206 char *PortBurn_LastError(void *handle)
207 {
208    PBHandle *h = (PBHandle *) handle;
209 
210    if (h == NULL) {
211       return NULL;
212    }
213 
214    return vectors[h->ver].LastError(h->realhandle);
215 }
216 
PortBurn_GetNumDevices(void * handle)217 int PortBurn_GetNumDevices(void *handle)
218 {
219    PBHandle *h = (PBHandle *) handle;
220 
221    if (h == NULL) {
222       return 0;
223    }
224 
225    return vectors[h->ver].GetNumDevices(h->realhandle);
226 }
227 
228 /* Get the name of the device with a given index.  Only valid
229    after a call to GetNumDevices. */
PortBurn_GetDeviceName(void * handle,int index)230 char *PortBurn_GetDeviceName(void *handle, int index)
231 {
232    PBHandle *h = (PBHandle *) handle;
233 
234    if (h == NULL) {
235       return NULL;
236    }
237 
238    return vectors[h->ver].GetDeviceName(h->realhandle, index);
239 }
240 
PortBurn_OpenDevice(void * handle,int index)241 int PortBurn_OpenDevice(void *handle, int index)
242 {
243    PBHandle *h = (PBHandle *) handle;
244 
245    if (h == NULL) {
246       return pbErrNoHandle;
247    }
248 
249    return vectors[h->ver].OpenDevice(h->realhandle, index);
250 }
251 
PortBurn_CloseDevice(void * handle)252 int PortBurn_CloseDevice(void *handle)
253 {
254    PBHandle *h = (PBHandle *) handle;
255 
256    if (h == NULL) {
257       return pbErrNoHandle;
258    }
259 
260    return vectors[h->ver].CloseDevice(h->realhandle);
261 }
262 
PortBurn_EjectDevice(void * handle)263 int PortBurn_EjectDevice(void *handle)
264 {
265    PBHandle *h = (PBHandle *) handle;
266 
267    if (h == NULL) {
268       return pbErrNoHandle;
269    }
270 
271    return vectors[h->ver].EjectDevice(h->realhandle);
272 }
273 
PortBurn_StartStaging(void * handle,const char * tmpdir)274 int PortBurn_StartStaging(void *handle, const char *tmpdir)
275 {
276    PBHandle *h = (PBHandle *) handle;
277 
278    if (h == NULL) {
279       return pbErrNoHandle;
280    }
281 
282    return vectors[h->ver].StartStaging(h->realhandle, tmpdir);
283 }
284 
PortBurn_StartTrack(void * handle,const char * name)285 int PortBurn_StartTrack(void *handle, const char *name)
286 {
287    PBHandle *h = (PBHandle *) handle;
288 
289    if (h == NULL) {
290       return pbErrNoHandle;
291    }
292 
293    return vectors[h->ver].StartTrack(h->realhandle, name);
294 }
295 
PortBurn_AddFrame(void * handle,short * buffer)296 int PortBurn_AddFrame(void *handle, short *buffer)
297 {
298    PBHandle *h = (PBHandle *) handle;
299 
300    if (h == NULL) {
301       return pbErrNoHandle;
302    }
303 
304    return vectors[h->ver].AddFrame(h->realhandle, buffer);
305 }
306 
PortBurn_EndTrack(void * handle)307 int PortBurn_EndTrack(void *handle)
308 {
309    PBHandle *h = (PBHandle *) handle;
310 
311    if (h == NULL) {
312       return pbErrNoHandle;
313    }
314 
315    return vectors[h->ver].EndTrack(h->realhandle);
316 }
317 
PortBurn_StartBurning(void * handle)318 int PortBurn_StartBurning(void *handle)
319 {
320    PBHandle *h = (PBHandle *) handle;
321 
322    if (h == NULL) {
323       return pbErrNoHandle;
324    }
325 
326    return vectors[h->ver].StartBurning(h->realhandle);
327 }
328 
PortBurn_CancelBurning(void * handle)329 int PortBurn_CancelBurning(void *handle)
330 {
331    PBHandle *h = (PBHandle *) handle;
332 
333    if (h == NULL) {
334       return pbErrNoHandle;
335    }
336 
337    return vectors[h->ver].CancelBurning(h->realhandle);
338 }
339 
PortBurn_GetStatus(void * handle,float * out_fraction_complete)340 int PortBurn_GetStatus(void *handle, float *out_fraction_complete)
341 {
342    PBHandle *h = (PBHandle *) handle;
343 
344    if (h == NULL) {
345       return pbErrNoHandle;
346    }
347 
348    return vectors[h->ver].GetStatus(h->realhandle, out_fraction_complete);
349 }
350 
PortBurn_GetOption(void * handle,int option,int * value)351 int PortBurn_GetOption(void *handle, int option, int *value)
352 {
353    PBHandle *h = (PBHandle *) handle;
354 
355    if (h == NULL) {
356       return pbErrNoHandle;
357    }
358 
359    return vectors[h->ver].GetOption(h->realhandle, option, value);
360 }
361 
PortBurn_SetOption(void * handle,int option,int value)362 int PortBurn_SetOption(void *handle, int option, int value)
363 {
364    PBHandle *h = (PBHandle *) handle;
365 
366    if (h == NULL) {
367       return pbErrNoHandle;
368    }
369 
370    return vectors[h->ver].SetOption(h->realhandle, option, value);
371 }
372 
PortBurn_GetSpeeds(void * handle,int * cnt,int * speeds[])373 int PortBurn_GetSpeeds(void *handle, int *cnt, int *speeds[])
374 {
375    return -1;
376 }
377 
378 /* Erase the media in the currently opened device */
PortBurn_StartErasing(void * handle,int type)379 int PortBurn_StartErasing(void *handle, int type)
380 {
381    PBHandle *h = (PBHandle *) handle;
382 
383    if (h == NULL) {
384       return pbErrNoHandle;
385    }
386 
387    return vectors[h->ver].StartErasing(h->realhandle, type);
388 }
389 
PortBurn_GetEraseStatus(void * handle,float * out_fraction_complete)390 int PortBurn_GetEraseStatus(void *handle, float *out_fraction_complete)
391 {
392    PBHandle *h = (PBHandle *) handle;
393 
394    if (h == NULL) {
395       return pbErrNoHandle;
396    }
397 
398    return vectors[h->ver].GetEraseStatus(h->realhandle, out_fraction_complete);
399 }
400 
401 /* */
PortBurn_GetMediaState(void * handle,int * state)402 int PortBurn_GetMediaState(void *handle, int *state)
403 {
404    PBHandle *h = (PBHandle *) handle;
405 
406    if (h == NULL) {
407       return pbErrNoHandle;
408    }
409 
410    return vectors[h->ver].GetMediaState(h->realhandle, state);
411 }
412