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