ReactOS  0.4.13-dev-482-ge57f103
mci.c
Go to the documentation of this file.
1 /*
2  * MCI internal functions
3  *
4  * Copyright 1998/1999 Eric Pouech
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 /* TODO:
22  * - implement WINMM (32bit) multitasking and use it in all MCI drivers
23  * instead of the home grown one
24  * - 16bit mmTaskXXX functions are currently broken because the 16
25  * loader does not support binary command lines => provide Wine's
26  * own mmtask.tsk not using binary command line.
27  * - correctly handle the MCI_ALL_DEVICE_ID in functions.
28  * - finish mapping 16 <=> 32 of MCI structures and commands
29  * - implement auto-open feature (ie, when a string command is issued
30  * for a not yet opened device, MCI automatically opens it)
31  * - use a default registry setting to replace the [mci] section in
32  * configuration file (layout of info in registry should be compatible
33  * with all Windows' version - which use different layouts of course)
34  * - implement automatic open
35  * + only works on string interface, on regular devices (don't work on all
36  * nor custom devices)
37  * - command table handling isn't thread safe
38  */
39 
40 #include "winemm.h"
41 
42 #include <mmsystem.h>
43 #include <wownt32.h>
44 #include <digitalv.h>
45 
47 
48 /* First MCI valid device ID (0 means error) */
49 #define MCI_MAGIC 0x0001
50 
51 /* MCI settings */
52 static const WCHAR wszHklmMci [] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','M','C','I',0};
53 static const WCHAR wszNull [] = {0};
54 static const WCHAR wszAll [] = {'A','L','L',0};
55 static const WCHAR wszMci [] = {'M','C','I',0};
56 static const WCHAR wszOpen [] = {'o','p','e','n',0};
57 static const WCHAR wszSystemIni[] = {'s','y','s','t','e','m','.','i','n','i',0};
58 
60 
62 static UINT MCI_SetCommandTable(HGLOBAL hMem, UINT uDevType);
63 
64 /* dup a string and uppercase it */
65 static inline LPWSTR str_dup_upper( LPCWSTR str )
66 {
67  INT len = (strlenW(str) + 1) * sizeof(WCHAR);
68  LPWSTR p = HeapAlloc( GetProcessHeap(), 0, len );
69  if (p)
70  {
71  memcpy( p, str, len );
72  CharUpperW( p );
73  }
74  return p;
75 }
76 
77 /**************************************************************************
78  * MCI_GetDriver [internal]
79  */
81 {
82  LPWINE_MCIDRIVER wmd = 0;
83 
85  for (wmd = MciDrivers; wmd; wmd = wmd->lpNext) {
86  if (wmd->wDeviceID == wDevID)
87  break;
88  }
90  return wmd;
91 }
92 
93 /**************************************************************************
94  * MCI_GetDriverFromString [internal]
95  */
97 {
98  LPWINE_MCIDRIVER wmd;
99  UINT ret = 0;
100 
101  if (!lpstrName)
102  return 0;
103 
104  if (!strcmpiW(lpstrName, wszAll))
105  return MCI_ALL_DEVICE_ID;
106 
108  for (wmd = MciDrivers; wmd; wmd = wmd->lpNext) {
109  if (wmd->lpstrElementName && strcmpW(wmd->lpstrElementName, lpstrName) == 0) {
110  ret = wmd->wDeviceID;
111  break;
112  }
113  if (wmd->lpstrDeviceType && strcmpiW(wmd->lpstrDeviceType, lpstrName) == 0) {
114  ret = wmd->wDeviceID;
115  break;
116  }
117  if (wmd->lpstrAlias && strcmpiW(wmd->lpstrAlias, lpstrName) == 0) {
118  ret = wmd->wDeviceID;
119  break;
120  }
121  }
123 
124  return ret;
125 }
126 
127 /**************************************************************************
128  * MCI_MessageToString [internal]
129  */
130 const char* MCI_MessageToString(UINT wMsg)
131 {
132  static char buffer[100];
133 
134 #define CASE(s) case (s): return #s
135 
136  switch (wMsg) {
137  CASE(DRV_LOAD);
138  CASE(DRV_ENABLE);
139  CASE(DRV_OPEN);
140  CASE(DRV_CLOSE);
141  CASE(DRV_DISABLE);
142  CASE(DRV_FREE);
145  CASE(DRV_INSTALL);
146  CASE(DRV_REMOVE);
148  CASE(DRV_EXITAPPLICATION);
149  CASE(DRV_POWER);
150  CASE(MCI_BREAK);
151  CASE(MCI_CLOSE);
153  CASE(MCI_COPY);
154  CASE(MCI_CUE);
155  CASE(MCI_CUT);
156  CASE(MCI_DELETE);
157  CASE(MCI_ESCAPE);
158  CASE(MCI_FREEZE);
159  CASE(MCI_PAUSE);
160  CASE(MCI_PLAY);
162  CASE(MCI_INFO);
163  CASE(MCI_LOAD);
164  CASE(MCI_OPEN);
166  CASE(MCI_PASTE);
167  CASE(MCI_PUT);
168  CASE(MCI_REALIZE);
169  CASE(MCI_RECORD);
170  CASE(MCI_RESUME);
171  CASE(MCI_SAVE);
172  CASE(MCI_SEEK);
173  CASE(MCI_SET);
174  CASE(MCI_SPIN);
175  CASE(MCI_STATUS);
176  CASE(MCI_STEP);
177  CASE(MCI_STOP);
178  CASE(MCI_SYSINFO);
180  CASE(MCI_UPDATE);
181  CASE(MCI_WHERE);
182  CASE(MCI_WINDOW);
183  /* constants for digital video */
184  CASE(MCI_CAPTURE);
185  CASE(MCI_MONITOR);
186  CASE(MCI_RESERVE);
188  CASE(MCI_SIGNAL);
190  CASE(MCI_QUALITY);
191  CASE(MCI_LIST);
192  CASE(MCI_UNDO);
194  CASE(MCI_RESTORE);
195 #undef CASE
196  default:
197  sprintf(buffer, "MCI_<<%04X>>", wMsg);
198  return buffer;
199  }
200 }
201 
203 {
204  LPWSTR ret;
205  INT len;
206 
207  if (!str) return NULL;
208  len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
209  ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
210  if (ret) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
211  return ret;
212 }
213 
215 {
216  LPSTR ret;
217  INT len;
218 
219  if (!str) return NULL;
220  len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
221  ret = HeapAlloc( GetProcessHeap(), 0, len );
222  if (ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
223  return ret;
224 }
225 
226 static int MCI_MapMsgAtoW(UINT msg, DWORD_PTR dwParam1, DWORD_PTR *dwParam2)
227 {
228  if (msg < DRV_RESERVED) return 0;
229 
230  switch (msg)
231  {
232  case MCI_CLOSE:
233  case MCI_CONFIGURE:
234  case MCI_PLAY:
235  case MCI_SEEK:
236  case MCI_STOP:
237  case MCI_PAUSE:
238  case MCI_GETDEVCAPS:
239  case MCI_SPIN:
240  case MCI_SET:
241  case MCI_STEP:
242  case MCI_RECORD:
243  case MCI_BREAK:
244  case MCI_SOUND:
245  case MCI_STATUS:
246  case MCI_CUE:
247  case MCI_REALIZE:
248  case MCI_PUT:
249  case MCI_WHERE:
250  case MCI_FREEZE:
251  case MCI_UNFREEZE:
252  case MCI_CUT:
253  case MCI_COPY:
254  case MCI_PASTE:
255  case MCI_UPDATE:
256  case MCI_RESUME:
257  case MCI_DELETE:
258  case MCI_MONITOR:
259  case MCI_SETAUDIO:
260  case MCI_SIGNAL:
261  case MCI_SETVIDEO:
262  case MCI_LIST:
263  return 0;
264 
265  case MCI_OPEN:
266  {
267  MCI_OPEN_PARMSA *mci_openA = (MCI_OPEN_PARMSA*)*dwParam2;
268  MCI_OPEN_PARMSW *mci_openW;
269  DWORD_PTR *ptr;
270 
271  ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD_PTR) + sizeof(*mci_openW) + 2 * sizeof(DWORD));
272  if (!ptr) return -1;
273 
274  *ptr++ = *dwParam2; /* save the previous pointer */
275  *dwParam2 = (DWORD_PTR)ptr;
276  mci_openW = (MCI_OPEN_PARMSW *)ptr;
277 
278  if (dwParam1 & MCI_NOTIFY)
279  mci_openW->dwCallback = mci_openA->dwCallback;
280 
281  if (dwParam1 & MCI_OPEN_TYPE)
282  {
283  if (dwParam1 & MCI_OPEN_TYPE_ID)
284  mci_openW->lpstrDeviceType = (LPCWSTR)mci_openA->lpstrDeviceType;
285  else
286  mci_openW->lpstrDeviceType = MCI_strdupAtoW(mci_openA->lpstrDeviceType);
287  }
288  if (dwParam1 & MCI_OPEN_ELEMENT)
289  {
290  if (dwParam1 & MCI_OPEN_ELEMENT_ID)
291  mci_openW->lpstrElementName = (LPCWSTR)mci_openA->lpstrElementName;
292  else
293  mci_openW->lpstrElementName = MCI_strdupAtoW(mci_openA->lpstrElementName);
294  }
295  if (dwParam1 & MCI_OPEN_ALIAS)
296  mci_openW->lpstrAlias = MCI_strdupAtoW(mci_openA->lpstrAlias);
297  /* FIXME: this is only needed for specific types of MCI devices, and
298  * may cause a segfault if the two DWORD:s don't exist at the end of
299  * mci_openA
300  */
301  memcpy(mci_openW + 1, mci_openA + 1, 2 * sizeof(DWORD));
302  }
303  return 1;
304 
305  case MCI_WINDOW:
306  if (dwParam1 & MCI_ANIM_WINDOW_TEXT)
307  {
308  MCI_ANIM_WINDOW_PARMSA *mci_windowA = (MCI_ANIM_WINDOW_PARMSA *)*dwParam2;
309  MCI_ANIM_WINDOW_PARMSW *mci_windowW;
310 
311  mci_windowW = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_windowW));
312  if (!mci_windowW) return -1;
313 
314  *dwParam2 = (DWORD_PTR)mci_windowW;
315 
316  mci_windowW->lpstrText = MCI_strdupAtoW(mci_windowA->lpstrText);
317 
318  if (dwParam1 & MCI_NOTIFY)
319  mci_windowW->dwCallback = mci_windowA->dwCallback;
320  if (dwParam1 & MCI_ANIM_WINDOW_HWND)
321  mci_windowW->hWnd = mci_windowA->hWnd;
322  if (dwParam1 & MCI_ANIM_WINDOW_STATE)
323  mci_windowW->nCmdShow = mci_windowA->nCmdShow;
324 
325  return 1;
326  }
327  return 0;
328 
329  case MCI_SYSINFO:
330  {
331  MCI_SYSINFO_PARMSA *mci_sysinfoA = (MCI_SYSINFO_PARMSA *)*dwParam2;
332  MCI_SYSINFO_PARMSW *mci_sysinfoW;
333  DWORD_PTR *ptr;
334 
335  ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_sysinfoW) + sizeof(DWORD_PTR));
336  if (!ptr) return -1;
337 
338  *ptr++ = *dwParam2; /* save the previous pointer */
339  *dwParam2 = (DWORD_PTR)ptr;
340  mci_sysinfoW = (MCI_SYSINFO_PARMSW *)ptr;
341 
342  if (dwParam1 & MCI_NOTIFY)
343  mci_sysinfoW->dwCallback = mci_sysinfoA->dwCallback;
344 
345  mci_sysinfoW->dwRetSize = mci_sysinfoA->dwRetSize;
346  mci_sysinfoW->lpstrReturn = HeapAlloc(GetProcessHeap(), 0, mci_sysinfoW->dwRetSize);
347  mci_sysinfoW->dwNumber = mci_sysinfoA->dwNumber;
348  mci_sysinfoW->wDeviceType = mci_sysinfoA->wDeviceType;
349  return 1;
350  }
351  case MCI_INFO:
352  {
353  MCI_INFO_PARMSA *mci_infoA = (MCI_INFO_PARMSA *)*dwParam2;
354  MCI_INFO_PARMSW *mci_infoW;
355  DWORD_PTR *ptr;
356 
357  ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_infoW) + sizeof(DWORD_PTR));
358  if (!ptr) return -1;
359 
360  *ptr++ = *dwParam2; /* save the previous pointer */
361  *dwParam2 = (DWORD_PTR)ptr;
362  mci_infoW = (MCI_INFO_PARMSW *)ptr;
363 
364  if (dwParam1 & MCI_NOTIFY)
365  mci_infoW->dwCallback = mci_infoA->dwCallback;
366 
367  mci_infoW->dwRetSize = mci_infoA->dwRetSize * sizeof(WCHAR); /* it's not the same as SYSINFO !!! */
368  mci_infoW->lpstrReturn = HeapAlloc(GetProcessHeap(), 0, mci_infoW->dwRetSize);
369  return 1;
370  }
371  case MCI_SAVE:
372  {
373  MCI_SAVE_PARMSA *mci_saveA = (MCI_SAVE_PARMSA *)*dwParam2;
374  MCI_SAVE_PARMSW *mci_saveW;
375 
376  mci_saveW = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_saveW));
377  if (!mci_saveW) return -1;
378 
379  *dwParam2 = (DWORD_PTR)mci_saveW;
380  if (dwParam1 & MCI_NOTIFY)
381  mci_saveW->dwCallback = mci_saveA->dwCallback;
382  mci_saveW->lpfilename = MCI_strdupAtoW(mci_saveA->lpfilename);
383  return 1;
384  }
385  case MCI_LOAD:
386  {
387  MCI_LOAD_PARMSA *mci_loadA = (MCI_LOAD_PARMSA *)*dwParam2;
388  MCI_LOAD_PARMSW *mci_loadW;
389 
390  mci_loadW = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_loadW));
391  if (!mci_loadW) return -1;
392 
393  *dwParam2 = (DWORD_PTR)mci_loadW;
394  if (dwParam1 & MCI_NOTIFY)
395  mci_loadW->dwCallback = mci_loadA->dwCallback;
396  mci_loadW->lpfilename = MCI_strdupAtoW(mci_loadA->lpfilename);
397  return 1;
398  }
399 
400  case MCI_ESCAPE:
401  {
402  MCI_VD_ESCAPE_PARMSA *mci_vd_escapeA = (MCI_VD_ESCAPE_PARMSA *)*dwParam2;
403  MCI_VD_ESCAPE_PARMSW *mci_vd_escapeW;
404 
405  mci_vd_escapeW = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_vd_escapeW));
406  if (!mci_vd_escapeW) return -1;
407 
408  *dwParam2 = (DWORD_PTR)mci_vd_escapeW;
409  if (dwParam1 & MCI_NOTIFY)
410  mci_vd_escapeW->dwCallback = mci_vd_escapeA->dwCallback;
411  mci_vd_escapeW->lpstrCommand = MCI_strdupAtoW(mci_vd_escapeA->lpstrCommand);
412  return 1;
413  }
414  default:
415  FIXME("Message %s needs translation\n", MCI_MessageToString(msg));
416  return -1;
417  }
418 }
419 
420 static DWORD MCI_UnmapMsgAtoW(UINT msg, DWORD_PTR dwParam1, DWORD_PTR dwParam2,
421  DWORD result)
422 {
423  switch (msg)
424  {
425  case MCI_OPEN:
426  {
427  DWORD_PTR *ptr = (DWORD_PTR *)dwParam2 - 1;
428  MCI_OPEN_PARMSA *mci_openA = (MCI_OPEN_PARMSA *)*ptr;
429  MCI_OPEN_PARMSW *mci_openW = (MCI_OPEN_PARMSW *)(ptr + 1);
430 
431  mci_openA->wDeviceID = mci_openW->wDeviceID;
432 
433  if (dwParam1 & MCI_OPEN_TYPE)
434  {
435  if (!(dwParam1 & MCI_OPEN_TYPE_ID))
436  HeapFree(GetProcessHeap(), 0, (LPWSTR)mci_openW->lpstrDeviceType);
437  }
438  if (dwParam1 & MCI_OPEN_ELEMENT)
439  {
440  if (!(dwParam1 & MCI_OPEN_ELEMENT_ID))
441  HeapFree(GetProcessHeap(), 0, (LPWSTR)mci_openW->lpstrElementName);
442  }
443  if (dwParam1 & MCI_OPEN_ALIAS)
444  HeapFree(GetProcessHeap(), 0, (LPWSTR)mci_openW->lpstrAlias);
445  HeapFree(GetProcessHeap(), 0, ptr);
446  }
447  break;
448  case MCI_WINDOW:
449  if (dwParam1 & MCI_ANIM_WINDOW_TEXT)
450  {
451  MCI_ANIM_WINDOW_PARMSW *mci_windowW = (MCI_ANIM_WINDOW_PARMSW *)dwParam2;
452 
453  HeapFree(GetProcessHeap(), 0, (void*)mci_windowW->lpstrText);
454  HeapFree(GetProcessHeap(), 0, mci_windowW);
455  }
456  break;
457 
458  case MCI_SYSINFO:
459  {
460  DWORD_PTR *ptr = (DWORD_PTR *)dwParam2 - 1;
461  MCI_SYSINFO_PARMSA *mci_sysinfoA = (MCI_SYSINFO_PARMSA *)*ptr;
462  MCI_SYSINFO_PARMSW *mci_sysinfoW = (MCI_SYSINFO_PARMSW *)(ptr + 1);
463 
464  if (!result)
465  {
466  mci_sysinfoA->dwNumber = mci_sysinfoW->dwNumber;
467  mci_sysinfoA->wDeviceType = mci_sysinfoW->wDeviceType;
468  if (dwParam1 & MCI_SYSINFO_QUANTITY)
469  *(DWORD*)mci_sysinfoA->lpstrReturn = *(DWORD*)mci_sysinfoW->lpstrReturn;
470  else
472  mci_sysinfoW->lpstrReturn, mci_sysinfoW->dwRetSize,
473  mci_sysinfoA->lpstrReturn, mci_sysinfoA->dwRetSize,
474  NULL, NULL);
475  }
476 
477  HeapFree(GetProcessHeap(), 0, mci_sysinfoW->lpstrReturn);
478  HeapFree(GetProcessHeap(), 0, ptr);
479  }
480  break;
481  case MCI_INFO:
482  {
483  DWORD_PTR *ptr = (DWORD_PTR *)dwParam2 - 1;
484  MCI_INFO_PARMSA *mci_infoA = (MCI_INFO_PARMSA *)*ptr;
485  MCI_INFO_PARMSW *mci_infoW = (MCI_INFO_PARMSW *)(ptr + 1);
486 
487  if (!result)
488  {
490  mci_infoW->lpstrReturn, mci_infoW->dwRetSize / sizeof(WCHAR),
491  mci_infoA->lpstrReturn, mci_infoA->dwRetSize,
492  NULL, NULL);
493  }
494 
495  HeapFree(GetProcessHeap(), 0, mci_infoW->lpstrReturn);
496  HeapFree(GetProcessHeap(), 0, ptr);
497  }
498  break;
499  case MCI_SAVE:
500  {
501  MCI_SAVE_PARMSW *mci_saveW = (MCI_SAVE_PARMSW *)dwParam2;
502 
503  HeapFree(GetProcessHeap(), 0, (void*)mci_saveW->lpfilename);
504  HeapFree(GetProcessHeap(), 0, mci_saveW);
505  }
506  break;
507  case MCI_LOAD:
508  {
509  MCI_LOAD_PARMSW *mci_loadW = (MCI_LOAD_PARMSW *)dwParam2;
510 
511  HeapFree(GetProcessHeap(), 0, (void*)mci_loadW->lpfilename);
512  HeapFree(GetProcessHeap(), 0, mci_loadW);
513  }
514  break;
515  case MCI_ESCAPE:
516  {
517  MCI_VD_ESCAPE_PARMSW *mci_vd_escapeW = (MCI_VD_ESCAPE_PARMSW *)dwParam2;
518 
519  HeapFree(GetProcessHeap(), 0, (void*)mci_vd_escapeW->lpstrCommand);
520  HeapFree(GetProcessHeap(), 0, mci_vd_escapeW);
521  }
522  break;
523 
524  default:
525  FIXME("Message %s needs unmapping\n", MCI_MessageToString(msg));
526  break;
527  }
528 
529  return result;
530 }
531 
532 /**************************************************************************
533  * MCI_GetDevTypeFromFileName [internal]
534  */
536 {
537  LPCWSTR tmp;
538  HKEY hKey;
539  static const WCHAR keyW[] = {'S','O','F','T','W','A','R','E','\\','M','i','c','r','o','s','o','f','t','\\',
540  'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
541  'M','C','I',' ','E','x','t','e','n','s','i','o','n','s',0};
542  if ((tmp = strrchrW(fileName, '.'))) {
544  0, KEY_QUERY_VALUE, &hKey ) == ERROR_SUCCESS) {
545  DWORD dwLen = len;
546  LONG lRet = RegQueryValueExW( hKey, tmp + 1, 0, 0, (void*)buf, &dwLen );
547  RegCloseKey( hKey );
548  if (lRet == ERROR_SUCCESS) return 0;
549  }
550  TRACE("No ...\\MCI Extensions entry for %s found.\n", debugstr_w(tmp));
551  }
553 }
554 
555 #define MAX_MCICMDTABLE 20
556 #define MCI_COMMAND_TABLE_NOT_LOADED 0xFFFE
557 
558 typedef struct tagWINE_MCICMDTABLE {
561  const BYTE* lpTable;
562  UINT nVerbs; /* number of verbs in command table */
563  LPCWSTR* aVerbs; /* array of verbs to speed up the verb look up process */
565 
567 
568 /**************************************************************************
569  * MCI_IsCommandTableValid [internal]
570  */
572 {
573  const BYTE* lmem;
574  LPCWSTR str;
575  DWORD flg;
576  WORD eid;
577  int idx = 0;
578  BOOL inCst = FALSE;
579 
580  TRACE("Dumping cmdTbl=%d [lpTable=%p devType=%d]\n",
581  uTbl, S_MciCmdTable[uTbl].lpTable, S_MciCmdTable[uTbl].uDevType);
582 
583  if (uTbl >= MAX_MCICMDTABLE || !S_MciCmdTable[uTbl].lpTable)
584  return FALSE;
585 
586  lmem = S_MciCmdTable[uTbl].lpTable;
587  do {
588  str = (LPCWSTR)lmem;
589  lmem += (strlenW(str) + 1) * sizeof(WCHAR);
590  flg = *(const DWORD*)lmem;
591  eid = *(const WORD*)(lmem + sizeof(DWORD));
592  lmem += sizeof(DWORD) + sizeof(WORD);
593  idx ++;
594  /* TRACE("cmd=%s %08lx %04x\n", debugstr_w(str), flg, eid); */
595  switch (eid) {
596  case MCI_COMMAND_HEAD: if (!*str || !flg) return FALSE; idx = 0; break; /* check unicity of str in table */
597  case MCI_STRING: if (inCst) return FALSE; break;
598  case MCI_INTEGER: if (!*str) return FALSE; break;
599  case MCI_END_COMMAND: if (*str || flg || idx == 0) return FALSE; idx = 0; break;
600  case MCI_RETURN: if (*str || idx != 1) return FALSE; break;
601  case MCI_FLAG: if (!*str) return FALSE; break;
602  case MCI_END_COMMAND_LIST: if (*str || flg) return FALSE; idx = 0; break;
603  case MCI_RECT: if (!*str || inCst) return FALSE; break;
604  case MCI_CONSTANT: if (inCst) return FALSE; inCst = TRUE; break;
605  case MCI_END_CONSTANT: if (*str || flg || !inCst) return FALSE; inCst = FALSE; break;
606  default: return FALSE;
607  }
608  } while (eid != MCI_END_COMMAND_LIST);
609  return TRUE;
610 }
611 
612 /**************************************************************************
613  * MCI_DumpCommandTable [internal]
614  */
616 {
617  const BYTE* lmem;
618  LPCWSTR str;
619  DWORD flg;
620  WORD eid;
621 
622  if (!MCI_IsCommandTableValid(uTbl)) {
623  ERR("Ooops: %d is not valid\n", uTbl);
624  return FALSE;
625  }
626 
627  lmem = S_MciCmdTable[uTbl].lpTable;
628  do {
629  do {
630  str = (LPCWSTR)lmem;
631  lmem += (strlenW(str) + 1) * sizeof(WCHAR);
632  flg = *(const DWORD*)lmem;
633  eid = *(const WORD*)(lmem + sizeof(DWORD));
634  /* TRACE("cmd=%s %08lx %04x\n", debugstr_w(str), flg, eid); */
635  lmem += sizeof(DWORD) + sizeof(WORD);
636  } while (eid != MCI_END_COMMAND && eid != MCI_END_COMMAND_LIST);
637  /* EPP TRACE(" => end of command%s\n", (eid == MCI_END_COMMAND_LIST) ? " list" : ""); */
638  } while (eid != MCI_END_COMMAND_LIST);
639  return TRUE;
640 }
641 
642 
643 /**************************************************************************
644  * MCI_GetCommandTable [internal]
645  */
646 static UINT MCI_GetCommandTable(UINT uDevType)
647 {
648  UINT uTbl;
649  WCHAR buf[32];
650  LPCWSTR str = NULL;
651 
652  /* first look up existing for existing devType */
653  for (uTbl = 0; uTbl < MAX_MCICMDTABLE; uTbl++) {
654  if (S_MciCmdTable[uTbl].lpTable && S_MciCmdTable[uTbl].uDevType == uDevType)
655  return uTbl;
656  }
657 
658  /* well try to load id */
659  if (uDevType >= MCI_DEVTYPE_FIRST && uDevType <= MCI_DEVTYPE_LAST) {
660  if (LoadStringW(hWinMM32Instance, uDevType, buf, sizeof(buf) / sizeof(WCHAR))) {
661  str = buf;
662  }
663  } else if (uDevType == 0) {
664  static const WCHAR wszCore[] = {'C','O','R','E',0};
665  str = wszCore;
666  }
667  uTbl = MCI_NO_COMMAND_TABLE;
668  if (str) {
670  HANDLE hMem = 0;
671 
672  if (hRsrc) hMem = LoadResource(hWinMM32Instance, hRsrc);
673  if (hMem) {
674  uTbl = MCI_SetCommandTable(hMem, uDevType);
675  } else {
676  WARN("No command table found in resource %p[%s]\n",
678  }
679  }
680  TRACE("=> %d\n", uTbl);
681  return uTbl;
682 }
683 
684 /**************************************************************************
685  * MCI_SetCommandTable [internal]
686  */
687 static UINT MCI_SetCommandTable(HGLOBAL hMem, UINT uDevType)
688 {
689  int uTbl;
690  static BOOL bInitDone = FALSE;
691 
692  /* <HACK>
693  * The CORE command table must be loaded first, so that MCI_GetCommandTable()
694  * can be called with 0 as a uDevType to retrieve it.
695  * </HACK>
696  */
697  if (!bInitDone) {
698  bInitDone = TRUE;
700  }
701  TRACE("(%p, %u)\n", hMem, uDevType);
702  for (uTbl = 0; uTbl < MAX_MCICMDTABLE; uTbl++) {
703  if (!S_MciCmdTable[uTbl].lpTable) {
704  const BYTE* lmem;
705  LPCWSTR str;
706  WORD eid;
707  WORD count;
708 
709  S_MciCmdTable[uTbl].uDevType = uDevType;
710  S_MciCmdTable[uTbl].lpTable = LockResource(hMem);
711  S_MciCmdTable[uTbl].hMem = hMem;
712 
713  if (TRACE_ON(mci)) {
714  MCI_DumpCommandTable(uTbl);
715  }
716 
717  /* create the verbs table */
718  /* get # of entries */
719  lmem = S_MciCmdTable[uTbl].lpTable;
720  count = 0;
721  do {
722  str = (LPCWSTR)lmem;
723  lmem += (strlenW(str) + 1) * sizeof(WCHAR);
724  eid = *(const WORD*)(lmem + sizeof(DWORD));
725  lmem += sizeof(DWORD) + sizeof(WORD);
726  if (eid == MCI_COMMAND_HEAD)
727  count++;
728  } while (eid != MCI_END_COMMAND_LIST);
729 
730  S_MciCmdTable[uTbl].aVerbs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(LPCWSTR));
731  S_MciCmdTable[uTbl].nVerbs = count;
732 
733  lmem = S_MciCmdTable[uTbl].lpTable;
734  count = 0;
735  do {
736  str = (LPCWSTR)lmem;
737  lmem += (strlenW(str) + 1) * sizeof(WCHAR);
738  eid = *(const WORD*)(lmem + sizeof(DWORD));
739  lmem += sizeof(DWORD) + sizeof(WORD);
740  if (eid == MCI_COMMAND_HEAD)
741  S_MciCmdTable[uTbl].aVerbs[count++] = str;
742  } while (eid != MCI_END_COMMAND_LIST);
743  /* assert(count == S_MciCmdTable[uTbl].nVerbs); */
744  return uTbl;
745  }
746  }
747 
748  return MCI_NO_COMMAND_TABLE;
749 }
750 
751 /**************************************************************************
752  * MCI_UnLoadMciDriver [internal]
753  */
755 {
756  LPWINE_MCIDRIVER* tmp;
757 
758  if (!wmd)
759  return TRUE;
760 
761  CloseDriver(wmd->hDriver, 0, 0);
762 
763  if (wmd->dwPrivate != 0)
764  WARN("Unloading mci driver with non nul dwPrivate field\n");
765 
767  for (tmp = &MciDrivers; *tmp; tmp = &(*tmp)->lpNext) {
768  if (*tmp == wmd) {
769  *tmp = wmd->lpNext;
770  break;
771  }
772  }
774 
776  HeapFree(GetProcessHeap(), 0, wmd->lpstrAlias);
778 
779  HeapFree(GetProcessHeap(), 0, wmd);
780  return TRUE;
781 }
782 
783 /**************************************************************************
784  * MCI_OpenMciDriver [internal]
785  */
787 {
788  WCHAR libName[128];
789 
790  if (!DRIVER_GetLibName(drvTyp, wszMci, libName, sizeof(libName)))
791  return FALSE;
792 
793  /* First load driver */
794  wmd->hDriver = (HDRVR)DRIVER_TryOpenDriver32(libName, lp);
795  return wmd->hDriver != NULL;
796 }
797 
798 /**************************************************************************
799  * MCI_LoadMciDriver [internal]
800  */
802 {
803  LPWSTR strDevTyp = str_dup_upper(_strDevTyp);
806  DWORD dwRet = 0;
807 
808  if (!wmd || !strDevTyp) {
809  dwRet = MCIERR_OUT_OF_MEMORY;
810  goto errCleanUp;
811  }
812 
814  wmd->dwYieldData = VK_CANCEL;
816 
818  /* wmd must be inserted in list before sending opening the driver, because it
819  * may want to lookup at wDevID
820  */
821  wmd->lpNext = MciDrivers;
822  MciDrivers = wmd;
823 
824  for (modp.wDeviceID = MCI_MAGIC;
825  MCI_GetDriver(modp.wDeviceID) != 0;
826  modp.wDeviceID++);
827 
828  wmd->wDeviceID = modp.wDeviceID;
829 
831 
832  TRACE("wDevID=%04X\n", modp.wDeviceID);
833 
834  modp.lpstrParams = NULL;
835 
836  if (!MCI_OpenMciDriver(wmd, strDevTyp, (DWORD_PTR)&modp)) {
837  /* silence warning if all is used... some bogus program use commands like
838  * 'open all'...
839  */
840  if (strcmpiW(strDevTyp, wszAll) == 0) {
841  dwRet = MCIERR_CANNOT_USE_ALL;
842  } else {
843  FIXME("Couldn't load driver for type %s.\n",
844  debugstr_w(strDevTyp));
846  }
847  goto errCleanUp;
848  }
849 
850  /* FIXME: should also check that module's description is of the form
851  * MODULENAME:[MCI] comment
852  */
853 
854  /* some drivers will return 0x0000FFFF, some others 0xFFFFFFFF */
855  wmd->uSpecificCmdTable = LOWORD(modp.wCustomCommandTable);
857 
858  TRACE("Loaded driver %p (%s), type is %d, cmdTable=%08x\n",
859  wmd->hDriver, debugstr_w(strDevTyp), modp.wType, modp.wCustomCommandTable);
860 
861  wmd->lpstrDeviceType = strDevTyp;
862  wmd->wType = modp.wType;
863 
864  TRACE("mcidev=%d, uDevTyp=%04X wDeviceID=%04X !\n",
865  modp.wDeviceID, modp.wType, modp.wDeviceID);
866  *lpwmd = wmd;
867  return 0;
868 errCleanUp:
869  MCI_UnLoadMciDriver(wmd);
870  HeapFree(GetProcessHeap(), 0, strDevTyp);
871  *lpwmd = 0;
872  return dwRet;
873 }
874 
875 /**************************************************************************
876  * MCI_SendCommandFrom32 [internal]
877  */
878 static DWORD MCI_SendCommandFrom32(MCIDEVICEID wDevID, UINT16 wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
879 {
881  LPWINE_MCIDRIVER wmd = MCI_GetDriver(wDevID);
882 
883  if (wmd) {
884  dwRet = SendDriverMessage(wmd->hDriver, wMsg, dwParam1, dwParam2);
885  }
886  return dwRet;
887 }
888 
889 /**************************************************************************
890  * MCI_FinishOpen [internal]
891  */
893  DWORD dwParam)
894 {
895  if (dwParam & MCI_OPEN_ELEMENT)
896  {
897  wmd->lpstrElementName = HeapAlloc(GetProcessHeap(),0,(strlenW(lpParms->lpstrElementName)+1) * sizeof(WCHAR));
898  strcpyW( wmd->lpstrElementName, lpParms->lpstrElementName );
899  }
900  if (dwParam & MCI_OPEN_ALIAS)
901  {
902  wmd->lpstrAlias = HeapAlloc(GetProcessHeap(), 0, (strlenW(lpParms->lpstrAlias)+1) * sizeof(WCHAR));
903  strcpyW( wmd->lpstrAlias, lpParms->lpstrAlias);
904  }
905  lpParms->wDeviceID = wmd->wDeviceID;
906 
907  return MCI_SendCommandFrom32(wmd->wDeviceID, MCI_OPEN_DRIVER, dwParam,
908  (DWORD_PTR)lpParms);
909 }
910 
911 /**************************************************************************
912  * MCI_FindCommand [internal]
913  */
915 {
916  UINT idx;
917 
918  if (uTbl >= MAX_MCICMDTABLE || !S_MciCmdTable[uTbl].lpTable)
919  return NULL;
920 
921  /* another improvement would be to have the aVerbs array sorted,
922  * so that we could use a dichotomic search on it, rather than this dumb
923  * array look up
924  */
925  for (idx = 0; idx < S_MciCmdTable[uTbl].nVerbs; idx++) {
926  if (strcmpiW(S_MciCmdTable[uTbl].aVerbs[idx], verb) == 0)
927  return S_MciCmdTable[uTbl].aVerbs[idx];
928  }
929 
930  return NULL;
931 }
932 
933 /**************************************************************************
934  * MCI_GetReturnType [internal]
935  */
937 {
938  lpCmd = (LPCWSTR)((const BYTE*)(lpCmd + strlenW(lpCmd) + 1) + sizeof(DWORD) + sizeof(WORD));
939  if (*lpCmd == '\0' && *(const WORD*)((const BYTE*)(lpCmd + 1) + sizeof(DWORD)) == MCI_RETURN) {
940  return *(const DWORD*)(lpCmd + 1);
941  }
942  return 0L;
943 }
944 
945 /**************************************************************************
946  * MCI_GetMessage [internal]
947  */
949 {
950  return (WORD)*(const DWORD*)(lpCmd + strlenW(lpCmd) + 1);
951 }
952 
953 /**************************************************************************
954  * MCI_GetDWord [internal]
955  */
957 {
958  DWORD val;
959  LPWSTR ret;
960 
961  val = strtoulW(*ptr, &ret, 0);
962 
963  switch (*ret) {
964  case '\0': break;
965  case ' ': ret++; break;
966  default: return FALSE;
967  }
968 
969  *data |= val;
970  *ptr = ret;
971  return TRUE;
972 }
973 
974 /**************************************************************************
975  * MCI_GetString [internal]
976  */
978 {
979  LPWSTR ptr = *args;
980 
981  /* see if we have a quoted string */
982  if (*ptr == '"') {
983  ptr = strchrW(*str = ptr + 1, '"');
984  if (!ptr) return MCIERR_NO_CLOSING_QUOTE;
985  /* FIXME: shall we escape \" from string ?? */
986  if (ptr[-1] == '\\') TRACE("Ooops: un-escaped \"\n");
987  *ptr++ = '\0'; /* remove trailing " */
988  if (*ptr != ' ' && *ptr != '\0') return MCIERR_EXTRA_CHARACTERS;
989  } else {
990  ptr = strchrW(ptr, ' ');
991 
992  if (ptr) {
993  *ptr++ = '\0';
994  } else {
995  ptr = *args + strlenW(*args);
996  }
997  *str = *args;
998  }
999 
1000  *args = ptr;
1001  return 0;
1002 }
1003 
1004 #define MCI_DATA_SIZE 16
1005 
1006 /**************************************************************************
1007  * MCI_ParseOptArgs [internal]
1008  */
1009 static DWORD MCI_ParseOptArgs(DWORD_PTR *data, int _offset, LPCWSTR lpCmd,
1011 {
1012  int len, offset;
1013  const char* lmem;
1014  LPCWSTR str;
1015  DWORD dwRet, flg, cflg = 0;
1016  WORD eid;
1017  BOOL inCst, found;
1018 
1019  /* loop on arguments */
1020  while (*args) {
1021  lmem = (const char*)lpCmd;
1022  found = inCst = FALSE;
1023  offset = _offset;
1024 
1025  /* skip any leading white space(s) */
1026  while (*args == ' ') args++;
1027  TRACE("args=%s offset=%d\n", debugstr_w(args), offset);
1028 
1029  do { /* loop on options for command table for the requested verb */
1030  str = (LPCWSTR)lmem;
1031  lmem += ((len = strlenW(str)) + 1) * sizeof(WCHAR);
1032  flg = *(const DWORD*)lmem;
1033  eid = *(const WORD*)(lmem + sizeof(DWORD));
1034  lmem += sizeof(DWORD) + sizeof(WORD);
1035  /* TRACE("\tcmd=%s inCst=%c eid=%04x\n", debugstr_w(str), inCst ? 'Y' : 'N', eid); */
1036 
1037  switch (eid) {
1038  case MCI_CONSTANT:
1039  inCst = TRUE; cflg = flg; break;
1040  case MCI_END_CONSTANT:
1041  /* there may be additional integral values after flag in constant */
1042  if (inCst && MCI_GetDWord(&(data[offset]), &args)) {
1043  *dwFlags |= cflg;
1044  }
1045  inCst = FALSE; cflg = 0;
1046  break;
1047  }
1048 
1049  if (strncmpiW(args, str, len) == 0 &&
1050  ((eid == MCI_STRING && len == 0) || args[len] == 0 || args[len] == ' ')) {
1051  /* store good values into data[] */
1052  args += len;
1053  while (*args == ' ') args++;
1054  found = TRUE;
1055 
1056  switch (eid) {
1057  case MCI_COMMAND_HEAD:
1058  case MCI_RETURN:
1059  case MCI_END_COMMAND:
1060  case MCI_END_COMMAND_LIST:
1061  case MCI_CONSTANT: /* done above */
1062  case MCI_END_CONSTANT: /* done above */
1063  break;
1064  case MCI_FLAG:
1065  *dwFlags |= flg;
1066  break;
1067  case MCI_INTEGER:
1068  if (inCst) {
1069  data[offset] |= flg;
1070  *dwFlags |= cflg;
1071  inCst = FALSE;
1072  } else {
1073  *dwFlags |= flg;
1074  if (!MCI_GetDWord(&(data[offset]), &args)) {
1075  return MCIERR_BAD_INTEGER;
1076  }
1077  }
1078  break;
1079  case MCI_RECT:
1080  /* store rect in data (offset..offset+3) */
1081  *dwFlags |= flg;
1082  if (!MCI_GetDWord(&(data[offset+0]), &args) ||
1083  !MCI_GetDWord(&(data[offset+1]), &args) ||
1084  !MCI_GetDWord(&(data[offset+2]), &args) ||
1085  !MCI_GetDWord(&(data[offset+3]), &args)) {
1086  ERR("Bad rect %s\n", debugstr_w(args));
1087  return MCIERR_BAD_INTEGER;
1088  }
1089  break;
1090  case MCI_STRING:
1091  *dwFlags |= flg;
1092  if ((dwRet = MCI_GetString((LPWSTR*)&data[offset], &args)))
1093  return dwRet;
1094  break;
1095  default: ERR("oops\n");
1096  }
1097  /* exit inside while loop, except if just entered in constant area definition */
1098  if (!inCst || eid != MCI_CONSTANT) eid = MCI_END_COMMAND;
1099  } else {
1100  /* have offset incremented if needed */
1101  switch (eid) {
1102  case MCI_COMMAND_HEAD:
1103  case MCI_RETURN:
1104  case MCI_END_COMMAND:
1105  case MCI_END_COMMAND_LIST:
1106  case MCI_CONSTANT:
1107  case MCI_FLAG: break;
1108  case MCI_INTEGER: if (!inCst) offset++; break;
1109  case MCI_END_CONSTANT:
1110  case MCI_STRING: offset++; break;
1111  case MCI_RECT: offset += 4; break;
1112  default: ERR("oops\n");
1113  }
1114  }
1115  } while (eid != MCI_END_COMMAND);
1116  if (!found) {
1117  WARN("Optarg %s not found\n", debugstr_w(args));
1119  }
1120  if (offset == MCI_DATA_SIZE) {
1121  ERR("Internal data[] buffer overflow\n");
1122  return MCIERR_PARSER_INTERNAL;
1123  }
1124  }
1125  return 0;
1126 }
1127 
1128 /**************************************************************************
1129  * MCI_HandleReturnValues [internal]
1130  */
1132  DWORD_PTR *data, LPWSTR lpstrRet, UINT uRetLen)
1133 {
1134  static const WCHAR wszLd [] = {'%','l','d',0};
1135  static const WCHAR wszLd4 [] = {'%','l','d',' ','%','l','d',' ','%','l','d',' ','%','l','d',0};
1136  static const WCHAR wszCol3[] = {'%','d',':','%','d',':','%','d',0};
1137  static const WCHAR wszCol4[] = {'%','d',':','%','d',':','%','d',':','%','d',0};
1138 
1139  if (lpstrRet) {
1140  switch (retType) {
1141  case 0: /* nothing to return */
1142  break;
1143  case MCI_INTEGER:
1144  switch (dwRet & 0xFFFF0000ul) {
1145  case 0:
1146  case MCI_INTEGER_RETURNED:
1147  snprintfW(lpstrRet, uRetLen, wszLd, data[1]);
1148  break;
1149  case MCI_RESOURCE_RETURNED:
1150  /* return string which ID is HIWORD(data[1]),
1151  * string is loaded from mmsystem.dll */
1152  LoadStringW(hWinMM32Instance, HIWORD(data[1]), lpstrRet, uRetLen);
1153  break;
1155  /* return string which ID is HIWORD(data[1]),
1156  * string is loaded from driver */
1157  /* FIXME: this is wrong for a 16 bit handle */
1159  HIWORD(data[1]), lpstrRet, uRetLen);
1160  break;
1161  case MCI_COLONIZED3_RETURN:
1162  snprintfW(lpstrRet, uRetLen, wszCol3,
1163  LOBYTE(LOWORD(data[1])), HIBYTE(LOWORD(data[1])),
1164  LOBYTE(HIWORD(data[1])));
1165  break;
1166  case MCI_COLONIZED4_RETURN:
1167  snprintfW(lpstrRet, uRetLen, wszCol4,
1168  LOBYTE(LOWORD(data[1])), HIBYTE(LOWORD(data[1])),
1169  LOBYTE(HIWORD(data[1])), HIBYTE(HIWORD(data[1])));
1170  break;
1171  default: ERR("Ooops (%04X)\n", HIWORD(dwRet));
1172  }
1173  break;
1174  case MCI_STRING:
1175  switch (dwRet & 0xFFFF0000ul) {
1176  case 0:
1177  /* nothing to do data[1] == lpstrRet */
1178  break;
1179  case MCI_INTEGER_RETURNED:
1180  data[1] = *(LPDWORD)lpstrRet;
1181  snprintfW(lpstrRet, uRetLen, wszLd, data[1]);
1182  break;
1183  default:
1184  WARN("Oooch. MCI_STRING and HIWORD(dwRet)=%04x\n", HIWORD(dwRet));
1185  break;
1186  }
1187  break;
1188  case MCI_RECT:
1189  if (dwRet & 0xFFFF0000ul)
1190  WARN("Oooch. MCI_STRING and HIWORD(dwRet)=%04x\n", HIWORD(dwRet));
1191  snprintfW(lpstrRet, uRetLen, wszLd4,
1192  data[1], data[2], data[3], data[4]);
1193  break;
1194  default: ERR("oops\n");
1195  }
1196  }
1197  return LOWORD(dwRet);
1198 }
1199 
1200 /**************************************************************************
1201  * mciSendStringW [WINMM.@]
1202  */
1203 DWORD WINAPI mciSendStringW(LPCWSTR lpstrCommand, LPWSTR lpstrRet,
1204  UINT uRetLen, HWND hwndCallback)
1205 {
1206  LPWSTR verb, dev, args;
1207  LPWINE_MCIDRIVER wmd = 0;
1208  DWORD dwFlags = 0, dwRet = 0;
1209  int offset = 0;
1211  DWORD retType;
1212  LPCWSTR lpCmd = 0;
1213  LPWSTR devAlias = NULL;
1214  static const WCHAR wszNew[] = {'n','e','w',0};
1215  static const WCHAR wszSAliasS[] = {' ','a','l','i','a','s',' ',0};
1216  static const WCHAR wszTypeS[] = {'t','y','p','e',' ',0};
1217 
1218  TRACE("(%s, %p, %d, %p)\n",
1219  debugstr_w(lpstrCommand), lpstrRet, uRetLen, hwndCallback);
1220 
1221  /* format is <command> <device> <optargs> */
1222  if (!(verb = HeapAlloc(GetProcessHeap(), 0, (strlenW(lpstrCommand)+1) * sizeof(WCHAR))))
1223  return MCIERR_OUT_OF_MEMORY;
1224  strcpyW( verb, lpstrCommand );
1225  CharLowerW(verb);
1226 
1227  memset(data, 0, sizeof(data));
1228 
1229  if (!(args = strchrW(verb, ' '))) {
1231  goto errCleanUp;
1232  }
1233  *args++ = '\0';
1234  if ((dwRet = MCI_GetString(&dev, &args))) {
1235  goto errCleanUp;
1236  }
1237 
1238  /* Determine devType from open */
1239  if (!strcmpW(verb, wszOpen)) {
1240  LPWSTR devType, tmp;
1241  WCHAR buf[128];
1242 
1243  /* case dev == 'new' has to be handled */
1244  if (!strcmpW(dev, wszNew)) {
1245  dev = 0;
1246  if ((devType = strstrW(args, wszTypeS)) != NULL) {
1247  devType += 5;
1248  tmp = strchrW(devType, ' ');
1249  if (tmp) *tmp = '\0';
1250  devType = str_dup_upper(devType);
1251  if (tmp) *tmp = ' ';
1252  /* dwFlags and data[2] will be correctly set in ParseOpt loop */
1253  } else {
1254  WARN("open new requires device type\n");
1256  goto errCleanUp;
1257  }
1258  } else if ((devType = strchrW(dev, '!')) != NULL) {
1259  *devType++ = '\0';
1260  tmp = devType; devType = dev; dev = tmp;
1261 
1263  data[2] = (DWORD_PTR)devType;
1264  devType = str_dup_upper(devType);
1266  data[3] = (DWORD_PTR)dev;
1267  } else if (DRIVER_GetLibName(dev, wszMci, buf, sizeof(buf))) {
1268  /* this is the name of a mci driver's type */
1269  tmp = strchrW(dev, ' ');
1270  if (tmp) *tmp = '\0';
1271  data[2] = (DWORD_PTR)dev;
1272  devType = str_dup_upper(dev);
1273  if (tmp) *tmp = ' ';
1275  } else {
1276  if ((devType = strstrW(args, wszTypeS)) != NULL) {
1277  devType += 5;
1278  tmp = strchrW(devType, ' ');
1279  if (tmp) *tmp = '\0';
1280  devType = str_dup_upper(devType);
1281  if (tmp) *tmp = ' ';
1282  /* dwFlags and data[2] will be correctly set in ParseOpt loop */
1283  } else {
1284  if ((dwRet = MCI_GetDevTypeFromFileName(dev, buf, sizeof(buf))))
1285  goto errCleanUp;
1286 
1287  devType = str_dup_upper(buf);
1288  }
1290  data[3] = (DWORD_PTR)dev;
1291  }
1292  if ((devAlias = strstrW(args, wszSAliasS))) {
1293  WCHAR* tmp2;
1294  devAlias += 7;
1295  if (!(tmp = strchrW(devAlias,' '))) tmp = devAlias + strlenW(devAlias);
1296  if (tmp) *tmp = '\0';
1297  tmp2 = HeapAlloc(GetProcessHeap(), 0, (tmp - devAlias + 1) * sizeof(WCHAR) );
1298  memcpy( tmp2, devAlias, (tmp - devAlias) * sizeof(WCHAR) );
1299  tmp2[tmp - devAlias] = 0;
1300  data[4] = (DWORD_PTR)tmp2;
1301  /* should be done in regular options parsing */
1302  /* dwFlags |= MCI_OPEN_ALIAS; */
1303  } else if (dev == 0) {
1304  /* "open new" requires alias */
1305  dwRet = MCIERR_NEW_REQUIRES_ALIAS;
1306  goto errCleanUp;
1307  }
1308 
1309  dwRet = MCI_LoadMciDriver(devType, &wmd);
1310  if (dwRet == MCIERR_DEVICE_NOT_INSTALLED)
1312  HeapFree(GetProcessHeap(), 0, devType);
1313  if (dwRet) {
1314  MCI_UnLoadMciDriver(wmd);
1315  goto errCleanUp;
1316  }
1317  } else if (!(wmd = MCI_GetDriver(mciGetDeviceIDW(dev)))) {
1318  /* auto open */
1319  static const WCHAR wszOpenWait[] = {'o','p','e','n',' ','%','s',' ','w','a','i','t',0};
1320  WCHAR buf[128];
1321  sprintfW(buf, wszOpenWait, dev);
1322 
1323  if ((dwRet = mciSendStringW(buf, NULL, 0, 0)) != 0)
1324  goto errCleanUp;
1325 
1327  if (!wmd) {
1328  /* FIXME: memory leak, MCI driver is not closed */
1329  dwRet = MCIERR_INVALID_DEVICE_ID;
1330  goto errCleanUp;
1331  }
1332  }
1333 
1334  /* get the verb in the different command tables */
1335  if (wmd) {
1336  /* try the device specific command table */
1337  lpCmd = MCI_FindCommand(wmd->uSpecificCmdTable, verb);
1338  if (!lpCmd) {
1339  /* try the type specific command table */
1342  if (wmd->uTypeCmdTable != MCI_NO_COMMAND_TABLE)
1343  lpCmd = MCI_FindCommand(wmd->uTypeCmdTable, verb);
1344  }
1345  }
1346  /* try core command table */
1347  if (!lpCmd) lpCmd = MCI_FindCommand(MCI_GetCommandTable(0), verb);
1348 
1349  if (!lpCmd) {
1350  TRACE("Command %s not found!\n", debugstr_w(verb));
1352  goto errCleanUp;
1353  }
1354 
1355  /* set return information */
1356  switch (retType = MCI_GetReturnType(lpCmd)) {
1357  case 0: offset = 1; break;
1358  case MCI_INTEGER: offset = 2; break;
1359  case MCI_STRING: data[1] = (DWORD_PTR)lpstrRet; data[2] = uRetLen; offset = 3; break;
1360  case MCI_RECT: offset = 5; break;
1361  default: ERR("oops\n");
1362  }
1363 
1364  TRACE("verb=%s on dev=%s; offset=%d\n",
1365  debugstr_w(verb), debugstr_w(dev), offset);
1366 
1367  if ((dwRet = MCI_ParseOptArgs(data, offset, lpCmd, args, &dwFlags)))
1368  goto errCleanUp;
1369 
1370  /* set up call back */
1371  if (dwFlags & MCI_NOTIFY) {
1372  data[0] = (DWORD_PTR)hwndCallback;
1373  }
1374 
1375  /* FIXME: the command should get it's own notification window set up and
1376  * ask for device closing while processing the notification mechanism
1377  */
1378  if (lpstrRet && uRetLen) *lpstrRet = '\0';
1379 
1380  TRACE("[%d, %s, %08x, %08x/%s %08x/%s %08x/%s %08x/%s %08x/%s %08x/%s]\n",
1382  data[0], debugstr_w((WCHAR *)data[0]), data[1], debugstr_w((WCHAR *)data[1]),
1383  data[2], debugstr_w((WCHAR *)data[2]), data[3], debugstr_w((WCHAR *)data[3]),
1384  data[4], debugstr_w((WCHAR *)data[4]), data[5], debugstr_w((WCHAR *)data[5]));
1385 
1386  if (strcmpW(verb, wszOpen) == 0) {
1387  if ((dwRet = MCI_FinishOpen(wmd, (LPMCI_OPEN_PARMSW)data, dwFlags)))
1388  MCI_UnLoadMciDriver(wmd);
1389  /* FIXME: notification is not properly shared across two opens */
1390  } else {
1391  dwRet = MCI_SendCommand(wmd->wDeviceID, MCI_GetMessage(lpCmd), dwFlags, (DWORD_PTR)data);
1392  }
1393  TRACE("=> 1/ %x (%s)\n", dwRet, debugstr_w(lpstrRet));
1394  dwRet = MCI_HandleReturnValues(dwRet, wmd, retType, data, lpstrRet, uRetLen);
1395  TRACE("=> 2/ %x (%s)\n", dwRet, debugstr_w(lpstrRet));
1396 
1397 errCleanUp:
1398  HeapFree(GetProcessHeap(), 0, verb);
1399  return dwRet;
1400 }
1401 
1402 /**************************************************************************
1403  * mciSendStringA [WINMM.@]
1404  */
1405 DWORD WINAPI mciSendStringA(LPCSTR lpstrCommand, LPSTR lpstrRet,
1406  UINT uRetLen, HWND hwndCallback)
1407 {
1408  LPWSTR lpwstrCommand;
1409  LPWSTR lpwstrRet = NULL;
1410  UINT ret;
1411  INT len;
1412 
1413  /* FIXME: is there something to do with lpstrReturnString ? */
1414  len = MultiByteToWideChar( CP_ACP, 0, lpstrCommand, -1, NULL, 0 );
1415  lpwstrCommand = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1416  MultiByteToWideChar( CP_ACP, 0, lpstrCommand, -1, lpwstrCommand, len );
1417  if (lpstrRet)
1418  {
1419  lpwstrRet = HeapAlloc(GetProcessHeap(), 0, uRetLen * sizeof(WCHAR));
1420  if (!lpwstrRet) {
1421  WARN("no memory\n");
1422  HeapFree( GetProcessHeap(), 0, lpwstrCommand );
1423  return MCIERR_OUT_OF_MEMORY;
1424  }
1425  }
1426  ret = mciSendStringW(lpwstrCommand, lpwstrRet, uRetLen, hwndCallback);
1427  if (!ret && lpwstrRet)
1428  WideCharToMultiByte( CP_ACP, 0, lpwstrRet, -1, lpstrRet, uRetLen, NULL, NULL );
1429  HeapFree(GetProcessHeap(), 0, lpwstrCommand);
1430  HeapFree(GetProcessHeap(), 0, lpwstrRet);
1431  return ret;
1432 }
1433 
1434 /**************************************************************************
1435  * mciExecute [WINMM.@]
1436  */
1438 {
1439  char strRet[256];
1440  DWORD ret;
1441 
1442  TRACE("(%s)!\n", lpstrCommand);
1443 
1444  ret = mciSendStringA(lpstrCommand, strRet, sizeof(strRet), 0);
1445  if (ret != 0) {
1446  if (!mciGetErrorStringA(ret, strRet, sizeof(strRet))) {
1447  sprintf(strRet, "Unknown MCI error (%lu)", ret);
1448  }
1449  MessageBoxA(0, strRet, "Error in mciExecute()", MB_OK);
1450  }
1451  /* FIXME: what shall I return ? */
1452  return TRUE;
1453 }
1454 
1455 /**************************************************************************
1456  * mciLoadCommandResource [WINMM.@]
1457  *
1458  * Strangely, this function only exists as a UNICODE one.
1459  */
1461 {
1463  HRSRC hRsrc = 0;
1464  HGLOBAL hMem;
1465 
1466  TRACE("(%p, %s, %d)!\n", hInst, debugstr_w(resNameW), type);
1467 
1468  /* if a file named "resname.mci" exits, then load resource "resname" from it
1469  * otherwise directly from driver
1470  * We don't support it (who uses this feature ?), but we check anyway
1471  */
1472  if (!type) {
1473 #if 0
1474  /* FIXME: we should put this back into order, but I never found a program
1475  * actually using this feature, so we may not need it
1476  */
1477  char buf[128];
1478  OFSTRUCT ofs;
1479 
1480  strcat(strcpy(buf, resname), ".mci");
1481  if (OpenFile(buf, &ofs, OF_EXIST) != HFILE_ERROR) {
1482  FIXME("NIY: command table to be loaded from '%s'\n", ofs.szPathName);
1483  }
1484 #endif
1485  }
1486  if ((hRsrc = FindResourceW(hInst, resNameW, (LPWSTR)RT_RCDATA)) &&
1487  (hMem = LoadResource(hInst, hRsrc))) {
1488  ret = MCI_SetCommandTable(hMem, type);
1489  FreeResource(hMem);
1490  }
1491  else WARN("No command table found in module for %s\n", debugstr_w(resNameW));
1492 
1493  TRACE("=> %04x\n", ret);
1494  return ret;
1495 }
1496 
1497 /**************************************************************************
1498  * mciFreeCommandResource [WINMM.@]
1499  */
1501 {
1502  TRACE("(%08x)!\n", uTable);
1503 
1504  if (uTable >= MAX_MCICMDTABLE || !S_MciCmdTable[uTable].lpTable)
1505  return FALSE;
1506 
1507  FreeResource(S_MciCmdTable[uTable].hMem);
1508  S_MciCmdTable[uTable].hMem = NULL;
1509  S_MciCmdTable[uTable].lpTable = NULL;
1510  HeapFree(GetProcessHeap(), 0, S_MciCmdTable[uTable].aVerbs);
1511  S_MciCmdTable[uTable].aVerbs = 0;
1512  S_MciCmdTable[uTable].nVerbs = 0;
1513  return TRUE;
1514 }
1515 
1516 /**************************************************************************
1517  * MCI_Open [internal]
1518  */
1519 static DWORD MCI_Open(DWORD dwParam, LPMCI_OPEN_PARMSW lpParms)
1520 {
1521  WCHAR strDevTyp[128];
1522  DWORD dwRet;
1523  LPWINE_MCIDRIVER wmd = NULL;
1524 
1525  TRACE("(%08X, %p)\n", dwParam, lpParms);
1526  if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1527 
1528  /* only two low bytes are generic, the other ones are dev type specific */
1529 #define WINE_MCIDRIVER_SUPP (0xFFFF0000|MCI_OPEN_SHAREABLE|MCI_OPEN_ELEMENT| \
1530  MCI_OPEN_ALIAS|MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID| \
1531  MCI_NOTIFY|MCI_WAIT)
1532  if ((dwParam & ~WINE_MCIDRIVER_SUPP) != 0) {
1533  FIXME("Unsupported yet dwFlags=%08lX\n", dwParam & ~WINE_MCIDRIVER_SUPP);
1534  }
1535 #undef WINE_MCIDRIVER_SUPP
1536 
1537  strDevTyp[0] = 0;
1538 
1539  if (dwParam & MCI_OPEN_TYPE) {
1540  if (dwParam & MCI_OPEN_TYPE_ID) {
1541  WORD uDevType = LOWORD(lpParms->lpstrDeviceType);
1542 
1543  if (uDevType < MCI_DEVTYPE_FIRST ||
1544  uDevType > MCI_DEVTYPE_LAST ||
1545  !LoadStringW(hWinMM32Instance, uDevType,
1546  strDevTyp, sizeof(strDevTyp) / sizeof(WCHAR))) {
1547  dwRet = MCIERR_BAD_INTEGER;
1548  goto errCleanUp;
1549  }
1550  } else {
1551  LPWSTR ptr;
1552  if (lpParms->lpstrDeviceType == NULL) {
1554  goto errCleanUp;
1555  }
1556  strcpyW(strDevTyp, lpParms->lpstrDeviceType);
1557  ptr = strchrW(strDevTyp, '!');
1558  if (ptr) {
1559  /* this behavior is not documented in windows. However, since, in
1560  * some occasions, MCI_OPEN handling is translated by WinMM into
1561  * a call to mciSendString("open <type>"); this code shall be correct
1562  */
1563  if (dwParam & MCI_OPEN_ELEMENT) {
1564  ERR("Both MCI_OPEN_ELEMENT(%s) and %s are used\n",
1565  debugstr_w(lpParms->lpstrElementName),
1566  debugstr_w(strDevTyp));
1568  goto errCleanUp;
1569  }
1570  dwParam |= MCI_OPEN_ELEMENT;
1571  *ptr++ = 0;
1572  /* FIXME: not a good idea to write in user supplied buffer */
1573  lpParms->lpstrElementName = ptr;
1574  }
1575 
1576  }
1577  TRACE("devType=%s !\n", debugstr_w(strDevTyp));
1578  }
1579 
1580  if (dwParam & MCI_OPEN_ELEMENT) {
1581  TRACE("lpstrElementName=%s\n", debugstr_w(lpParms->lpstrElementName));
1582 
1583  if (dwParam & MCI_OPEN_ELEMENT_ID) {
1584  FIXME("Unsupported yet flag MCI_OPEN_ELEMENT_ID\n");
1586  goto errCleanUp;
1587  }
1588 
1589  if (!lpParms->lpstrElementName) {
1591  goto errCleanUp;
1592  }
1593 
1594  /* type, if given as a parameter, supersedes file extension */
1595  if (!strDevTyp[0] &&
1597  strDevTyp, sizeof(strDevTyp))) {
1598  static const WCHAR wszCdAudio[] = {'C','D','A','U','D','I','O',0};
1599  if (GetDriveTypeW(lpParms->lpstrElementName) != DRIVE_CDROM) {
1601  goto errCleanUp;
1602  }
1603  /* FIXME: this will not work if several CDROM drives are installed on the machine */
1604  strcpyW(strDevTyp, wszCdAudio);
1605  }
1606  }
1607 
1608  if (strDevTyp[0] == 0) {
1609  FIXME("Couldn't load driver\n");
1611  goto errCleanUp;
1612  }
1613 
1614  if (dwParam & MCI_OPEN_ALIAS) {
1615  TRACE("Alias=%s !\n", debugstr_w(lpParms->lpstrAlias));
1616  if (!lpParms->lpstrAlias) {
1618  goto errCleanUp;
1619  }
1620  }
1621 
1622  if ((dwRet = MCI_LoadMciDriver(strDevTyp, &wmd))) {
1623  goto errCleanUp;
1624  }
1625 
1626  if ((dwRet = MCI_FinishOpen(wmd, lpParms, dwParam))) {
1627  TRACE("Failed to open driver (MCI_OPEN_DRIVER) [%08x], closing\n", dwRet);
1628  /* FIXME: is dwRet the correct ret code ? */
1629  goto errCleanUp;
1630  }
1631 
1632  /* only handled devices fall through */
1633  TRACE("wDevID=%04X wDeviceID=%d dwRet=%d\n", wmd->wDeviceID, lpParms->wDeviceID, dwRet);
1634 
1635  if (dwParam & MCI_NOTIFY)
1637 
1638  return 0;
1639 errCleanUp:
1640  if (wmd) MCI_UnLoadMciDriver(wmd);
1641 
1642  if (dwParam & MCI_NOTIFY)
1644  return dwRet;
1645 }
1646 
1647 /**************************************************************************
1648  * MCI_Close [internal]
1649  */
1650 static DWORD MCI_Close(UINT wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
1651 {
1652  DWORD dwRet;
1653  LPWINE_MCIDRIVER wmd;
1654 
1655  TRACE("(%04x, %08X, %p)\n", wDevID, dwParam, lpParms);
1656 
1657  /* Every device must handle MCI_NOTIFY on its own. */
1658  if ((UINT16)wDevID == (UINT16)MCI_ALL_DEVICE_ID) {
1659  /* FIXME: shall I notify once after all is done, or for
1660  * each of the open drivers ? if the latest, which notif
1661  * to return when only one fails ?
1662  */
1663  while (MciDrivers) {
1664  /* Retrieve the device ID under lock, but send the message without,
1665  * the driver might be calling some winmm functions from another
1666  * thread before being fully stopped.
1667  */
1669  if (!MciDrivers)
1670  {
1672  break;
1673  }
1674  wDevID = MciDrivers->wDeviceID;
1676  MCI_Close(wDevID, dwParam, lpParms);
1677  }
1678  return 0;
1679  }
1680 
1681  if (!(wmd = MCI_GetDriver(wDevID))) {
1682  return MCIERR_INVALID_DEVICE_ID;
1683  }
1684 
1685  dwRet = MCI_SendCommandFrom32(wDevID, MCI_CLOSE_DRIVER, dwParam, (DWORD_PTR)lpParms);
1686 
1687  MCI_UnLoadMciDriver(wmd);
1688 
1689  if (dwParam & MCI_NOTIFY)
1690  mciDriverNotify(lpParms ? (HWND)lpParms->dwCallback : 0,
1691  wDevID,
1693 
1694  return dwRet;
1695 }
1696 
1697 /**************************************************************************
1698  * MCI_WriteString [internal]
1699  */
1700 static DWORD MCI_WriteString(LPWSTR lpDstStr, DWORD dstSize, LPCWSTR lpSrcStr)
1701 {
1702  DWORD ret = 0;
1703 
1704  if (lpSrcStr) {
1705  dstSize /= sizeof(WCHAR);
1706  if (dstSize <= strlenW(lpSrcStr)) {
1707  lstrcpynW(lpDstStr, lpSrcStr, dstSize - 1);
1709  } else {
1710  strcpyW(lpDstStr, lpSrcStr);
1711  }
1712  } else {
1713  *lpDstStr = 0;
1714  }
1715  return ret;
1716 }
1717 
1718 /**************************************************************************
1719  * MCI_Sysinfo [internal]
1720  */
1722 {
1723  DWORD ret = MCIERR_INVALID_DEVICE_ID, cnt = 0;
1724  WCHAR buf[2048], *s, *p;
1725  LPWINE_MCIDRIVER wmd;
1726  HKEY hKey;
1727 
1728  if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1729  if (lpParms->lpstrReturn == NULL) return MCIERR_PARAM_OVERFLOW;
1730 
1731  TRACE("(%08x, %08X, %p[num=%d, wDevTyp=%u])\n",
1732  uDevID, dwFlags, lpParms, lpParms->dwNumber, lpParms->wDeviceType);
1733  if ((WORD)MCI_ALL_DEVICE_ID == LOWORD(uDevID))
1734  uDevID = MCI_ALL_DEVICE_ID; /* Be compatible with Win9x */
1735 
1737  case MCI_SYSINFO_QUANTITY:
1738  if (lpParms->dwRetSize < sizeof(DWORD))
1739  return MCIERR_PARAM_OVERFLOW;
1740  /* Win9x returns 0 for 0 < uDevID < (UINT16)MCI_ALL_DEVICE_ID */
1741  if (uDevID == MCI_ALL_DEVICE_ID) {
1742  /* wDeviceType == MCI_ALL_DEVICE_ID is not recognized. */
1743  if (dwFlags & MCI_SYSINFO_OPEN) {
1744  TRACE("MCI_SYSINFO_QUANTITY: # of open MCI drivers\n");
1746  for (wmd = MciDrivers; wmd; wmd = wmd->lpNext) {
1747  cnt++;
1748  }
1750  } else {
1751  TRACE("MCI_SYSINFO_QUANTITY: # of installed MCI drivers\n");
1753  0, KEY_QUERY_VALUE, &hKey ) == ERROR_SUCCESS) {
1754  RegQueryInfoKeyW( hKey, 0, 0, 0, &cnt, 0, 0, 0, 0, 0, 0, 0);
1755  RegCloseKey( hKey );
1756  }
1757  if (GetPrivateProfileStringW(wszMci, 0, wszNull, buf, sizeof(buf) / sizeof(buf[0]), wszSystemIni))
1758  for (s = buf; *s; s += strlenW(s) + 1) cnt++;
1759  }
1760  } else {
1761  if (dwFlags & MCI_SYSINFO_OPEN) {
1762  TRACE("MCI_SYSINFO_QUANTITY: # of open MCI drivers of type %d\n", lpParms->wDeviceType);
1764  for (wmd = MciDrivers; wmd; wmd = wmd->lpNext) {
1765  if (wmd->wType == lpParms->wDeviceType) cnt++;
1766  }
1768  } else {
1769  TRACE("MCI_SYSINFO_QUANTITY: # of installed MCI drivers of type %d\n", lpParms->wDeviceType);
1770  FIXME("Don't know how to get # of MCI devices of a given type\n");
1771  /* name = LoadStringW(hWinMM32Instance, LOWORD(lpParms->wDeviceType))
1772  * then lookup registry and/or system.ini for name, ignoring digits suffix */
1773  switch (LOWORD(lpParms->wDeviceType)) {
1774  case MCI_DEVTYPE_CD_AUDIO:
1776  case MCI_DEVTYPE_SEQUENCER:
1777  cnt = 1;
1778  break;
1779  default: /* "digitalvideo" gets 0 because it's not in the registry */
1780  cnt = 0;
1781  }
1782  }
1783  }
1784  *(DWORD*)lpParms->lpstrReturn = cnt;
1785  TRACE("(%d) => '%d'\n", lpParms->dwNumber, *(DWORD*)lpParms->lpstrReturn);
1787  /* return ret; Only Win9x sends a notification in this case. */
1788  break;
1790  TRACE("MCI_SYSINFO_INSTALLNAME\n");
1791  if ((wmd = MCI_GetDriver(uDevID))) {
1792  ret = MCI_WriteString(lpParms->lpstrReturn, lpParms->dwRetSize,
1793  wmd->lpstrDeviceType);
1794  } else {
1795  ret = (uDevID == MCI_ALL_DEVICE_ID)
1797  }
1798  TRACE("(%d) => %s\n", lpParms->dwNumber, debugstr_w(lpParms->lpstrReturn));
1799  break;
1800  case MCI_SYSINFO_NAME:
1801  s = NULL;
1802  if (dwFlags & MCI_SYSINFO_OPEN) {
1803  /* Win9x returns 0 for 0 < uDevID < (UINT16)MCI_ALL_DEVICE_ID */
1804  TRACE("MCI_SYSINFO_NAME: nth alias of type %d\n",
1805  uDevID == MCI_ALL_DEVICE_ID ? MCI_ALL_DEVICE_ID : lpParms->wDeviceType);
1807  for (wmd = MciDrivers; wmd; wmd = wmd->lpNext) {
1808  /* wDeviceType == MCI_ALL_DEVICE_ID is not recognized. */
1809  if (uDevID == MCI_ALL_DEVICE_ID ||
1810  lpParms->wDeviceType == wmd->wType) {
1811  cnt++;
1812  if (cnt == lpParms->dwNumber) {
1813  s = wmd->lpstrAlias;
1814  break;
1815  }
1816  }
1817  }
1819  ret = s ? MCI_WriteString(lpParms->lpstrReturn, lpParms->dwRetSize, s) : MCIERR_OUTOFRANGE;
1820  } else if (MCI_ALL_DEVICE_ID == uDevID) {
1821  TRACE("MCI_SYSINFO_NAME: device #%d\n", lpParms->dwNumber);
1823  KEY_QUERY_VALUE, &hKey ) == ERROR_SUCCESS) {
1824  if (RegQueryInfoKeyW( hKey, 0, 0, 0, &cnt,
1825  0, 0, 0, 0, 0, 0, 0) == ERROR_SUCCESS &&
1826  lpParms->dwNumber <= cnt) {
1827  DWORD bufLen = sizeof(buf)/sizeof(buf[0]);
1828  if (RegEnumKeyExW(hKey, lpParms->dwNumber - 1,
1829  buf, &bufLen, 0, 0, 0, 0) == ERROR_SUCCESS)
1830  s = buf;
1831  }
1832  RegCloseKey( hKey );
1833  }
1834  if (!s) {
1835  if (GetPrivateProfileStringW(wszMci, 0, wszNull, buf, sizeof(buf) / sizeof(buf[0]), wszSystemIni)) {
1836  for (p = buf; *p; p += strlenW(p) + 1, cnt++) {
1837  TRACE("%d: %s\n", cnt, debugstr_w(p));
1838  if (cnt == lpParms->dwNumber - 1) {
1839  s = p;
1840  break;
1841  }
1842  }
1843  }
1844  }
1845  ret = s ? MCI_WriteString(lpParms->lpstrReturn, lpParms->dwRetSize, s) : MCIERR_OUTOFRANGE;
1846  } else {
1847  FIXME("MCI_SYSINFO_NAME: nth device of type %d\n", lpParms->wDeviceType);
1848  /* Cheating: what is asked for is the nth device from the registry. */
1849  if (1 != lpParms->dwNumber || /* Handle only one of each kind. */
1850  lpParms->wDeviceType < MCI_DEVTYPE_FIRST || lpParms->wDeviceType > MCI_DEVTYPE_LAST)
1852  else {
1854  lpParms->lpstrReturn, lpParms->dwRetSize);
1855  ret = 0;
1856  }
1857  }
1858  TRACE("(%d) => %s\n", lpParms->dwNumber, debugstr_w(lpParms->lpstrReturn));
1859  break;
1860  default:
1861  TRACE("Unsupported flag value=%08x\n", dwFlags);
1863  }
1864  if ((dwFlags & MCI_NOTIFY) && HRESULT_CODE(ret)==0)
1866  return ret;
1867 }
1868 
1869 /**************************************************************************
1870  * MCI_Break [internal]
1871  */
1873 {
1874  DWORD dwRet = 0;
1875 
1876  if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1877 
1878  if (dwFlags & MCI_NOTIFY)
1879  mciDriverNotify((HWND)lpParms->dwCallback, wDevID,
1880  (dwRet == 0) ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE);
1881 
1882  return dwRet;
1883 }
1884 
1885 /**************************************************************************
1886  * MCI_Sound [internal]
1887  */
1888 static DWORD MCI_Sound(UINT wDevID, DWORD dwFlags, LPMCI_SOUND_PARMSW lpParms)
1889 {
1890  DWORD dwRet = 0;
1891 
1892  if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1893 
1894  if (dwFlags & MCI_SOUND_NAME)
1895  dwRet = sndPlaySoundW(lpParms->lpstrSoundName, SND_SYNC) ? MMSYSERR_NOERROR : MMSYSERR_ERROR;
1896  else
1897  dwRet = MMSYSERR_ERROR; /* what should be done ??? */
1898  if (dwFlags & MCI_NOTIFY)
1899  mciDriverNotify((HWND)lpParms->dwCallback, wDevID,
1900  (dwRet == 0) ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE);
1901 
1902  return dwRet;
1903 }
1904 
1905 /**************************************************************************
1906  * MCI_SendCommand [internal]
1907  */
1908 DWORD MCI_SendCommand(UINT wDevID, UINT16 wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
1909 {
1911 
1912  switch (wMsg) {
1913  case MCI_OPEN:
1914  dwRet = MCI_Open(dwParam1, (LPMCI_OPEN_PARMSW)dwParam2);
1915  break;
1916  case MCI_CLOSE:
1917  dwRet = MCI_Close(wDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1918  break;
1919  case MCI_SYSINFO:
1920  dwRet = MCI_SysInfo(wDevID, dwParam1, (LPMCI_SYSINFO_PARMSW)dwParam2);
1921  break;
1922  case MCI_BREAK:
1923  dwRet = MCI_Break(wDevID, dwParam1, (LPMCI_BREAK_PARMS)dwParam2);
1924  break;
1925  case MCI_SOUND:
1926  dwRet = MCI_Sound(wDevID, dwParam1, (LPMCI_SOUND_PARMSW)dwParam2);
1927  break;
1928  default:
1929  if ((UINT16)wDevID == (UINT16)MCI_ALL_DEVICE_ID) {
1930  FIXME("unhandled MCI_ALL_DEVICE_ID\n");
1931  dwRet = MCIERR_CANNOT_USE_ALL;
1932  } else {
1933  dwRet = MCI_SendCommandFrom32(wDevID, wMsg, dwParam1, dwParam2);
1934  }
1935  break;
1936  }
1937  return dwRet;
1938 }
1939 
1940 /**************************************************************************
1941  * MCI_CleanUp [internal]
1942  *
1943  * Some MCI commands need to be cleaned-up (when not called from
1944  * mciSendString), because MCI drivers return extra information for string
1945  * transformation. This function gets rid of them.
1946  */
1947 static LRESULT MCI_CleanUp(LRESULT dwRet, UINT wMsg, DWORD_PTR dwParam2)
1948 {
1949  if (LOWORD(dwRet))
1950  return LOWORD(dwRet);
1951 
1952  switch (wMsg) {
1953  case MCI_GETDEVCAPS:
1954  switch (dwRet & 0xFFFF0000ul) {
1955  case 0:
1956  case MCI_COLONIZED3_RETURN:
1957  case MCI_COLONIZED4_RETURN:
1958  case MCI_INTEGER_RETURNED:
1959  /* nothing to do */
1960  break;
1961  case MCI_RESOURCE_RETURNED:
1963  {
1965 
1966  lmgp = (LPMCI_GETDEVCAPS_PARMS)dwParam2;
1967  TRACE("Changing %08x to %08x\n", lmgp->dwReturn, LOWORD(lmgp->dwReturn));
1968  lmgp->dwReturn = LOWORD(lmgp->dwReturn);
1969  }
1970  break;
1971  default:
1972  FIXME("Unsupported value for hiword (%04x) returned by DriverProc(%s)\n",
1973  HIWORD(dwRet), MCI_MessageToString(wMsg));
1974  }
1975  break;
1976  case MCI_STATUS:
1977  switch (dwRet & 0xFFFF0000ul) {
1978  case 0:
1979  case MCI_COLONIZED3_RETURN:
1980  case MCI_COLONIZED4_RETURN:
1981  case MCI_INTEGER_RETURNED:
1982  /* nothing to do */
1983  break;
1984  case MCI_RESOURCE_RETURNED:
1986  {
1987  LPMCI_STATUS_PARMS lsp;
1988 
1989  lsp = (LPMCI_STATUS_PARMS)dwParam2;
1990  TRACE("Changing %08lx to %08x\n", lsp->dwReturn, LOWORD(lsp->dwReturn));
1991  lsp->dwReturn = LOWORD(lsp->dwReturn);
1992  }
1993  break;
1994  default:
1995  FIXME("Unsupported value for hiword (%04x) returned by DriverProc(%s)\n",
1996  HIWORD(dwRet), MCI_MessageToString(wMsg));
1997  }
1998  break;
1999  case MCI_SYSINFO:
2000  switch (dwRet & 0xFFFF0000ul) {
2001  case 0:
2002  case MCI_INTEGER_RETURNED:
2003  /* nothing to do */
2004  break;
2005  default:
2006  FIXME("Unsupported value for hiword (%04x)\n", HIWORD(dwRet));
2007  }
2008  break;
2009  default:
2010  if (HIWORD(dwRet)) {
2011  FIXME("Got non null hiword for dwRet=0x%08lx for command %s\n",
2012  dwRet, MCI_MessageToString(wMsg));
2013  }
2014  break;
2015  }
2016  return LOWORD(dwRet);
2017 }
2018 
2019 /**************************************************************************
2020  * mciGetErrorStringW [WINMM.@]
2021  */
2022 BOOL WINAPI mciGetErrorStringW(MCIERROR wError, LPWSTR lpstrBuffer, UINT uLength)
2023 {
2024  BOOL ret = FALSE;
2025 
2026  if (lpstrBuffer != NULL && uLength > 0 &&
2027  wError >= MCIERR_BASE && wError <= MCIERR_CUSTOM_DRIVER_BASE) {
2028 
2029  if (LoadStringW(hWinMM32Instance, wError, lpstrBuffer, uLength) > 0) {
2030  ret = TRUE;
2031  }
2032  }
2033  return ret;
2034 }
2035 
2036 /**************************************************************************
2037  * mciGetErrorStringA [WINMM.@]
2038  */
2039 BOOL WINAPI mciGetErrorStringA(MCIERROR dwError, LPSTR lpstrBuffer, UINT uLength)
2040 {
2041  BOOL ret = FALSE;
2042 
2043  if (lpstrBuffer != NULL && uLength > 0 &&
2044  dwError >= MCIERR_BASE && dwError <= MCIERR_CUSTOM_DRIVER_BASE) {
2045 
2046  if (LoadStringA(hWinMM32Instance, dwError, lpstrBuffer, uLength) > 0) {
2047  ret = TRUE;
2048  }
2049  }
2050  return ret;
2051 }
2052 
2053 /**************************************************************************
2054  * mciDriverNotify [WINMM.@]
2055  */
2056 BOOL WINAPI mciDriverNotify(HWND hWndCallBack, MCIDEVICEID wDevID, UINT wStatus)
2057 {
2058  TRACE("(%p, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
2059 
2060  return PostMessageW(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
2061 }
2062 
2063 /**************************************************************************
2064  * mciGetDriverData [WINMM.@]
2065  */
2067 {
2068  LPWINE_MCIDRIVER wmd;
2069 
2070  TRACE("(%04x)\n", uDeviceID);
2071 
2072  wmd = MCI_GetDriver(uDeviceID);
2073 
2074  if (!wmd) {
2075  WARN("Bad uDeviceID\n");
2076  return 0L;
2077  }
2078 
2079  return wmd->dwPrivate;
2080 }
2081 
2082 /**************************************************************************
2083  * mciSetDriverData [WINMM.@]
2084  */
2086 {
2087  LPWINE_MCIDRIVER wmd;
2088 
2089  TRACE("(%04x, %08lx)\n", uDeviceID, data);
2090 
2091  wmd = MCI_GetDriver(uDeviceID);
2092 
2093  if (!wmd) {
2094  WARN("Bad uDeviceID\n");
2095  return FALSE;
2096  }
2097 
2098  wmd->dwPrivate = data;
2099  return TRUE;
2100 }
2101 
2102 /**************************************************************************
2103  * mciSendCommandW [WINMM.@]
2104  *
2105  */
2107 {
2108  DWORD dwRet;
2109 
2110  TRACE("(%08x, %s, %08lx, %08lx)\n",
2111  wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
2112 
2113  dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2);
2114  dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2);
2115  TRACE("=> %08x\n", dwRet);
2116  return dwRet;
2117 }
2118 
2119 /**************************************************************************
2120  * mciSendCommandA [WINMM.@]
2121  */
2123 {
2124  DWORD ret;
2125  int mapped;
2126 
2127  TRACE("(%08x, %s, %08lx, %08lx)\n",
2128  wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2);
2129 
2130  mapped = MCI_MapMsgAtoW(wMsg, dwParam1, &dwParam2);
2131  if (mapped == -1)
2132  {
2133  FIXME("message %04x mapping failed\n", wMsg);
2134  return MMSYSERR_NOMEM;
2135  }
2136  ret = mciSendCommandW(wDevID, wMsg, dwParam1, dwParam2);
2137  if (mapped)
2138  MCI_UnmapMsgAtoW(wMsg, dwParam1, dwParam2, ret);
2139  return ret;
2140 }
2141 
2142 /**************************************************************************
2143  * mciGetDeviceIDA [WINMM.@]
2144  */
2146 {
2147  LPWSTR w = MCI_strdupAtoW(lpstrName);
2149 
2150  if (w)
2151  {
2152  ret = mciGetDeviceIDW(w);
2153  HeapFree(GetProcessHeap(), 0, w);
2154  }
2155  return ret;
2156 }
2157 
2158 /**************************************************************************
2159  * mciGetDeviceIDW [WINMM.@]
2160  */
2162 {
2163  return MCI_GetDriverFromString(lpwstrName);
2164 }
2165 
2166 /******************************************************************
2167  * MyUserYield
2168  *
2169  * Internal wrapper to call USER.UserYield16 (in fact through a Wine only export from USER32).
2170  */
2171 static void MyUserYield(void)
2172 {
2173  HMODULE mod = GetModuleHandleA( "user32.dll" );
2174  if (mod)
2175  {
2176  FARPROC proc = GetProcAddress( mod, "UserYield16" );
2177  if (proc) proc();
2178  }
2179 }
2180 
2181 /**************************************************************************
2182  * MCI_DefYieldProc [internal]
2183  */
2185 {
2186  INT16 ret;
2187 
2188  TRACE("(0x%04x, 0x%08x)\n", wDevID, data);
2189 
2190  if ((HIWORD(data) != 0 && HWND_16(GetActiveWindow()) != HIWORD(data)) ||
2191  (GetAsyncKeyState(LOWORD(data)) & 1) == 0) {
2192  MyUserYield();
2193  ret = 0;
2194  } else {
2195  MSG msg;
2196 
2197  msg.hwnd = HWND_32(HIWORD(data));
2198  while (!PeekMessageW(&msg, msg.hwnd, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
2199  ret = -1;
2200  }
2201  return ret;
2202 }
2203 
2204 /**************************************************************************
2205  * mciSetYieldProc [WINMM.@]
2206  */
2207 BOOL WINAPI mciSetYieldProc(MCIDEVICEID uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData)
2208 {
2209  LPWINE_MCIDRIVER wmd;
2210 
2211  TRACE("(%u, %p, %08x)\n", uDeviceID, fpYieldProc, dwYieldData);
2212 
2213  if (!(wmd = MCI_GetDriver(uDeviceID))) {
2214  WARN("Bad uDeviceID\n");
2215  return FALSE;
2216  }
2217 
2218  wmd->lpfnYieldProc = fpYieldProc;
2219  wmd->dwYieldData = dwYieldData;
2220 
2221  return TRUE;
2222 }
2223 
2224 /**************************************************************************
2225  * mciGetDeviceIDFromElementIDA [WINMM.@]
2226  */
2228 {
2229  LPWSTR w = MCI_strdupAtoW(lpstrType);
2230  UINT ret = 0;
2231 
2232  if (w)
2233  {
2234  ret = mciGetDeviceIDFromElementIDW(dwElementID, w);
2235  HeapFree(GetProcessHeap(), 0, w);
2236  }
2237  return ret;
2238 }
2239 
2240 /**************************************************************************
2241  * mciGetDeviceIDFromElementIDW [WINMM.@]
2242  */
2244 {
2245  /* FIXME: that's rather strange, there is no
2246  * mciGetDeviceIDFromElementID32A in winmm.spec
2247  */
2248  FIXME("(%u, %s) stub\n", dwElementID, debugstr_w(lpstrType));
2249  return 0;
2250 }
2251 
2252 /**************************************************************************
2253  * mciGetYieldProc [WINMM.@]
2254  */
2256 {
2257  LPWINE_MCIDRIVER wmd;
2258 
2259  TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
2260 
2261  if (!(wmd = MCI_GetDriver(uDeviceID))) {
2262  WARN("Bad uDeviceID\n");
2263  return NULL;
2264  }
2265  if (!wmd->lpfnYieldProc) {
2266  WARN("No proc set\n");
2267  return NULL;
2268  }
2269  if (lpdwYieldData) *lpdwYieldData = wmd->dwYieldData;
2270  return wmd->lpfnYieldProc;
2271 }
2272 
2273 /**************************************************************************
2274  * mciGetCreatorTask [WINMM.@]
2275  */
2277 {
2278  LPWINE_MCIDRIVER wmd;
2279  HTASK ret = 0;
2280 
2281  if ((wmd = MCI_GetDriver(uDeviceID))) ret = (HTASK)wmd->CreatorThread;
2282 
2283  TRACE("(%u) => %p\n", uDeviceID, ret);
2284  return ret;
2285 }
2286 
2287 /**************************************************************************
2288  * mciDriverYield [WINMM.@]
2289  */
2291 {
2292  LPWINE_MCIDRIVER wmd;
2293  UINT ret = 0;
2294 
2295  TRACE("(%04x)\n", uDeviceID);
2296 
2297  if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc) {
2298  MyUserYield();
2299  } else {
2300  ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData);
2301  }
2302 
2303  return ret;
2304 }
#define DRV_DISABLE
Definition: mmsystem.h:123
#define MCI_UNFREEZE
Definition: mmsystem.h:669
#define MCI_SETAUDIO
Definition: digitalv.h:39
#define MCI_NO_COMMAND_TABLE
Definition: mmddk.h:375
LRESULT WINAPI SendDriverMessage(HDRVR hDriver, UINT msg, LPARAM lParam1, LPARAM lParam2)
Definition: driver.c:131
BOOL WINAPI mciSetYieldProc(MCIDEVICEID uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData)
Definition: mci.c:2207
#define MCI_ESCAPE
Definition: mmsystem.h:648
static BOOL MCI_UnLoadMciDriver(LPWINE_MCIDRIVER wmd)
Definition: mci.c:754
#define SND_SYNC
Definition: mmsystem.h:153
INT WINAPI GetPrivateProfileStringW(LPCWSTR section, LPCWSTR entry, LPCWSTR def_val, LPWSTR buffer, UINT len, LPCWSTR filename)
Definition: profile.c:1142
#define TRUE
Definition: types.h:120
static DWORD MCI_FinishOpen(LPWINE_MCIDRIVER wmd, LPMCI_OPEN_PARMSW lpParms, DWORD dwParam)
Definition: mci.c:892
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:6102
#define snprintfW
Definition: unicode.h:60
#define MCI_COPY
Definition: mmsystem.h:672
#define MCI_RESOURCE_DRIVER
Definition: mmddk.h:373
WINE_UNICODE_INLINE unsigned int strlenW(const WCHAR *str)
Definition: unicode.h:212
DWORD_PTR dwCallback
Definition: mmsystem.h:1599
BOOL WINAPI mciExecute(LPCSTR lpstrCommand)
Definition: mci.c:1437
#define MCI_RESTORE
Definition: digitalv.h:46
#define ERROR_SUCCESS
Definition: deptool.c:10
DWORD_PTR dwCallback
Definition: mmsystem.h:1619
#define DWORD_PTR
Definition: treelist.c:76
#define WideCharToMultiByte
Definition: compat.h:101
static DWORD MCI_UnmapMsgAtoW(UINT msg, DWORD_PTR dwParam1, DWORD_PTR dwParam2, DWORD result)
Definition: mci.c:420
#define MCI_WAIT
Definition: mmsystem.h:730
char * strcat(char *DstString, const char *SrcString)
Definition: utclib.c:568
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
DWORD_PTR WINAPI mciGetDriverData(MCIDEVICEID uDeviceID)
Definition: mci.c:2066
#define LOBYTE(W)
Definition: jmemdos.c:487
DWORD_PTR dwCallback
Definition: mmsystem.h:1624
LPWSTR lpstrAlias
Definition: winemm.h:122
UINT WINAPI mciDriverYield(MCIDEVICEID uDeviceID)
Definition: mci.c:2290
#define MCI_COLONIZED3_RETURN
Definition: mmddk.h:370
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
static DWORD MCI_GetString(LPWSTR *str, LPWSTR *args)
Definition: mci.c:977
#define MCI_STRING
Definition: mmddk.h:378
WINE_UNICODE_INLINE WCHAR * strchrW(const WCHAR *str, WCHAR ch)
Definition: unicode.h:248
#define MCI_ANIM_WINDOW_STATE
Definition: mmsystem.h:891
LPCWSTR lpfilename
Definition: mmsystem.h:1625
#define CP_ACP
Definition: compat.h:99
#define MCI_CAPTURE
Definition: digitalv.h:36
GLuint GLuint GLsizei count
Definition: gl.h:1545
TW_UINT32 TW_UINT16 TW_UINT16 MSG
Definition: twain.h:1827
static const WCHAR wszHklmMci[]
Definition: mci.c:52
int WINAPI LoadStringA(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_writes_to_(cchBufferMax, return+1) LPSTR lpBuffer, _In_ int cchBufferMax)
#define WARN(fmt,...)
Definition: debug.h:111
LPWSTR WINAPI CharLowerW(_Inout_ LPWSTR)
#define MCI_COMMAND_HEAD
Definition: mmddk.h:377
static const WCHAR wszAll[]
Definition: mci.c:54
GLintptr offset
Definition: glext.h:5920
LRESULT WINAPI CloseDriver(HDRVR hDrvr, LPARAM lParam1, LPARAM lParam2)
Definition: driver.c:462
#define MCI_STEP
Definition: mmsystem.h:657
#define HIBYTE(W)
Definition: jmemdos.c:486
BOOL WINAPI sndPlaySoundW(LPCWSTR pszSound, UINT uFlags)
Definition: playsound.c:548
#define MCI_PASTE
Definition: mmsystem.h:673
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
#define MCI_RESERVE
Definition: digitalv.h:38
LPVOID WINAPI LockResource(HGLOBAL handle)
Definition: res.c:550
#define MCI_PLAY
Definition: mmsystem.h:649
GLuint buffer
Definition: glext.h:5915
#define DRV_CLOSE
Definition: mmsystem.h:122
#define MCI_RESUME
Definition: mmsystem.h:675
#define MCI_BREAK
Definition: mmsystem.h:660
static const WCHAR wszNull[]
Definition: mci.c:53
#define DRV_EXITSESSION
Definition: mmsystem.h:129
static WORD MCI_GetMessage(LPCWSTR lpCmd)
Definition: mci.c:948
static HANDLE proc()
Definition: pdb.c:32
#define MCI_RESOURCE_RETURNED
Definition: mmddk.h:369
#define strncmpiW(s1, s2, n)
Definition: unicode.h:40
#define MCI_FREEZE
Definition: mmsystem.h:668
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
char * LPSTR
Definition: xmlstorage.h:182
#define MCIERR_CUSTOM_DRIVER_BASE
Definition: mmsystem.h:644
HINSTANCE hWinMM32Instance
Definition: winmm.c:50
Definition: match.c:390
static const WCHAR wszSystemIni[]
Definition: mci.c:57
#define DRV_RESERVED
Definition: mmsystem.h:131
int WINAPI LoadStringW(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_writes_to_(cchBufferMax, return+1) LPWSTR lpBuffer, _In_ int cchBufferMax)
#define DWORD
Definition: nt_native.h:44
int32_t INT
Definition: typedefs.h:56
#define MCI_CUE
Definition: mmsystem.h:663
static DWORD MCI_Open(DWORD dwParam, LPMCI_OPEN_PARMSW lpParms)
Definition: mci.c:1519
#define MCI_SAVE
Definition: mmsystem.h:661
HRSRC WINAPI FindResourceW(HINSTANCE hModule, LPCWSTR name, LPCWSTR type)
Definition: res.c:176
#define MCI_QUALITY
Definition: digitalv.h:42
static int dev
Definition: mkdosfs.c:536
static DWORD MCI_Break(UINT wDevID, DWORD dwFlags, LPMCI_BREAK_PARMS lpParms)
Definition: mci.c:1872
LPWSTR WINAPI CharUpperW(_Inout_ LPWSTR)
#define lstrcpynW
Definition: compat.h:397
struct tagWINE_MCICMDTABLE WINE_MCICMDTABLE
static LRESULT MCI_CleanUp(LRESULT dwRet, UINT wMsg, DWORD_PTR dwParam2)
Definition: mci.c:1947
#define MCI_FLAG
Definition: mmddk.h:382
#define DRV_QUERYCONFIGURE
Definition: mmsystem.h:126
#define DRV_POWER
Definition: mmsystem.h:130
#define DRV_OPEN
Definition: mmsystem.h:121
YIELDPROC lpfnYieldProc
Definition: winemm.h:125
#define MCI_STOP
Definition: mmsystem.h:651
#define MCI_WINDOW
Definition: mmsystem.h:665
int WINAPI MessageBoxA(_In_opt_ HWND, _In_opt_ LPCSTR, _In_opt_ LPCSTR, _In_ UINT)
#define sprintf(buf, format,...)
Definition: sprintf.c:55
DWORD_PTR dwReturn
Definition: mmsystem.h:1567
static LPWINE_MCIDRIVER MCI_GetDriver(UINT wDevID)
Definition: mci.c:80
#define MCI_SET
Definition: mmsystem.h:656
#define HWND_16(h32)
Definition: wownt32.h:25
#define MMSYSERR_NOMEM
Definition: mmsystem.h:103
UINT WINAPI mciGetDeviceIDFromElementIDA(DWORD dwElementID, LPCSTR lpstrType)
Definition: mci.c:2227
LPCWSTR lpstrElementName
Definition: mmsystem.h:1532
struct tagMCI_GETDEVCAPS_PARMS * LPMCI_GETDEVCAPS_PARMS
#define WM_KEYFIRST
Definition: winuser.h:1690
LONG WINAPI RegCloseKey(HKEY hKey)
Definition: reg.c:423
#define HFILE_ERROR
Definition: winbase.h:111
static LPCWSTR MCI_FindCommand(UINT uTbl, LPCWSTR verb)
Definition: mci.c:914
static BOOL MCI_GetDWord(DWORD_PTR *data, LPWSTR *ptr)
Definition: mci.c:956
#define MCI_SYSINFO_QUANTITY
Definition: mmsystem.h:768
#define MCI_OPEN_ELEMENT_ID
Definition: mmsystem.h:737
static UINT MCI_GetDriverFromString(LPCWSTR lpstrName)
Definition: mci.c:96
static DWORD MCI_Close(UINT wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
Definition: mci.c:1650
unsigned int BOOL
Definition: ntddk_ex.h:94
long LONG
Definition: pedump.c:60
BOOL WINAPI mciSetDriverData(MCIDEVICEID uDeviceID, DWORD_PTR data)
Definition: mci.c:2085
#define MCI_RECORD
Definition: mmsystem.h:658
#define MCI_END_COMMAND
Definition: mmddk.h:380
static BOOL MCI_IsCommandTableValid(UINT uTbl)
Definition: mci.c:571
#define MCI_SIGNAL
Definition: digitalv.h:40
#define debugstr_w
Definition: kernel32.h:32
#define FIXME(fmt,...)
Definition: debug.h:110
BOOL WINAPI FreeResource(HGLOBAL handle)
Definition: res.c:559
#define MCI_OPEN_TYPE_ID
Definition: mmsystem.h:738
#define MCI_WHERE
Definition: mmsystem.h:667
static PVOID ptr
Definition: dispmode.c:27
#define MCI_RECT
Definition: mmddk.h:384
#define MCI_CONSTANT
Definition: mmddk.h:385
unsigned int idx
Definition: utils.c:41
DWORD WINAPI mciSendStringW(LPCWSTR lpstrCommand, LPWSTR lpstrRet, UINT uRetLen, HWND hwndCallback)
Definition: mci.c:1203
UINT WINAPI mciGetDeviceIDFromElementIDW(DWORD dwElementID, LPCWSTR lpstrType)
Definition: mci.c:2243
static DWORD MCI_WriteString(LPWSTR lpDstStr, DWORD dstSize, LPCWSTR lpSrcStr)
Definition: mci.c:1700
static UINT WINAPI MCI_DefYieldProc(MCIDEVICEID wDevID, DWORD data)
Definition: mci.c:2184
HGLOBAL WINAPI LoadResource(HINSTANCE hModule, HRSRC hRsrc)
Definition: res.c:532
const WCHAR * str
#define MCIERR_MISSING_DEVICE_NAME
Definition: mmsystem.h:600
#define strstrW(d, s)
Definition: unicode.h:32
smooth NULL
Definition: ftsmooth.c:416
DWORD_PTR dwCallback
Definition: mmsystem.h:1591
static DWORD MCI_ParseOptArgs(DWORD_PTR *data, int _offset, LPCWSTR lpCmd, LPWSTR args, LPDWORD dwFlags)
Definition: mci.c:1009
#define MCI_ALL_DEVICE_ID
Definition: mmsystem.h:679
#define DRV_LOAD(x)
DWORD_PTR dwCallback
Definition: mmsystem.h:1579
#define MCI_OPEN
Definition: mmsystem.h:646
const char * MCI_MessageToString(UINT wMsg)
Definition: mci.c:130
const char * LPCSTR
Definition: xmlstorage.h:183
DWORD WINAPI mciSendStringA(LPCSTR lpstrCommand, LPSTR lpstrRet, UINT uRetLen, HWND hwndCallback)
Definition: mci.c:1405
#define DRV_REMOVE
Definition: mmsystem.h:128
#define MCI_INFO
Definition: mmsystem.h:653
#define MCI_NOTIFY_FAILURE
Definition: mmsystem.h:728
#define MCI_ANIM_WINDOW_TEXT
Definition: mmsystem.h:892
DWORD WINAPI GetCurrentThreadId(VOID)
Definition: thread.c:420
#define MCI_DEVTYPE_LAST
Definition: mmsystem.h:692
#define MCI_COMMAND_TABLE_NOT_LOADED
Definition: mci.c:556
#define MCI_CONFIGURE
Definition: digitalv.h:45
GLuint GLfloat * val
Definition: glext.h:7180
#define MCI_OPEN_DRIVER
Definition: mmddk.h:334
static UINT MCI_SetCommandTable(HGLOBAL hMem, UINT uDevType)
Definition: mci.c:687
#define MCIERR_PARAM_OVERFLOW
Definition: mmsystem.h:578
static DWORD MCI_SysInfo(UINT uDevID, DWORD dwFlags, LPMCI_SYSINFO_PARMSW lpParms)
Definition: mci.c:1721
#define MCI_STATUS
Definition: mmsystem.h:662
static LPWSTR str_dup_upper(LPCWSTR str)
Definition: mci.c:65
HFILE WINAPI OpenFile(LPCSTR lpFileName, LPOFSTRUCT lpReOpenBuff, UINT uStyle)
Definition: create.c:368
#define MCIERR_OUT_OF_MEMORY
Definition: mmsystem.h:574
#define MCIERR_DEVICE_NOT_INSTALLED
Definition: mmsystem.h:614
#define TRACE(s)
Definition: solgame.cpp:4
#define MCI_INTEGER
Definition: mmddk.h:379
static BOOL MCI_DumpCommandTable(UINT uTbl)
Definition: mci.c:615
#define MMSYSERR_NOERROR
Definition: mmsystem.h:96
#define GetProcessHeap()
Definition: compat.h:395
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
#define MMSYSERR_ERROR
Definition: mmsystem.h:97
struct tagWINE_MCICMDTABLE * LPWINE_MCICMDTABLE
LONG WINAPI RegQueryValueExW(_In_ HKEY hkeyorg, _In_ LPCWSTR name, _In_ LPDWORD reserved, _In_ LPDWORD type, _In_ LPBYTE data, _In_ LPDWORD count)
Definition: reg.c:4116
#define DRV_CONFIGURE
Definition: mmsystem.h:125
#define MCIERR_BAD_INTEGER
Definition: mmsystem.h:580
static WINE_MCIDRIVER * MciDrivers
Definition: mci.c:59
#define MCI_OPEN_TYPE
Definition: mmsystem.h:739
CRITICAL_SECTION WINMM_cs
Definition: winmm.c:54
LPWINE_DRIVER DRIVER_TryOpenDriver32(LPCWSTR fn, LPARAM lParam2)
Definition: driver.c:273
__wchar_t WCHAR
Definition: xmlstorage.h:180
WINE_DEFAULT_DEBUG_CHANNEL(mci)
static const WCHAR keyW[]
Definition: tokenize.c:60
BOOL WINAPI mciFreeCommandResource(UINT uTable)
Definition: mci.c:1500
DWORD WINAPI mciSendCommandW(MCIDEVICEID wDevID, UINT wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
Definition: mci.c:2106
static void MyUserYield(void)
Definition: mci.c:2171
#define MCIERR_INVALID_DEVICE_NAME
Definition: mmsystem.h:573
#define WINE_MCIDRIVER_SUPP
UINT WINAPI mciLoadCommandResource(HINSTANCE hInst, LPCWSTR resNameW, UINT type)
Definition: mci.c:1460
LPCWSTR lpstrDeviceType
Definition: mmsystem.h:1531
#define WINAPI
Definition: msvc.h:8
#define MCI_REALIZE
Definition: mmsystem.h:664
UINT uSpecificCmdTable
Definition: winemm.h:129
unsigned short WORD
Definition: ntddk_ex.h:93
static int MCI_MapMsgAtoW(UINT msg, DWORD_PTR dwParam1, DWORD_PTR *dwParam2)
Definition: mci.c:226
unsigned long DWORD
Definition: ntddk_ex.h:95
#define WM_KEYLAST
Definition: winuser.h:1704
static DWORD MCI_SendCommandFrom32(MCIDEVICEID wDevID, UINT16 wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
Definition: mci.c:878
DWORD_PTR dwCallback
Definition: mmsystem.h:1529
#define DRV_FREE
Definition: mmsystem.h:124
const BYTE * lpTable
Definition: mci.c:561
MCIDEVICEID wDeviceID
Definition: mmsystem.h:1522
#define MCI_ANIM_WINDOW_HWND
Definition: mmsystem.h:890
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
LONG WINAPI RegQueryInfoKeyW(HKEY hKey, LPWSTR lpClass, LPDWORD lpcClass, LPDWORD lpReserved, LPDWORD lpcSubKeys, LPDWORD lpcMaxSubKeyLen, LPDWORD lpcMaxClassLen, LPDWORD lpcValues, LPDWORD lpcMaxValueNameLen, LPDWORD lpcMaxValueLen, LPDWORD lpcbSecurityDescriptor, PFILETIME lpftLastWriteTime)
Definition: reg.c:3686
#define MCI_SETVIDEO
Definition: digitalv.h:41
#define RT_RCDATA
Definition: pedump.c:372
#define VK_CANCEL
Definition: winuser.h:2146
UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName)
Definition: mci.c:2145
#define MCI_NOTIFY_SUCCESSFUL
Definition: mmsystem.h:725
DWORD MCIERROR
Definition: mmsystem.h:958
static const WCHAR wszOpen[]
Definition: mci.c:56
struct tagWINE_MCIDRIVER * lpNext
Definition: winemm.h:130
int ret
#define MCIERR_CANNOT_USE_ALL
Definition: mmsystem.h:589
#define MCIERR_PARSER_INTERNAL
Definition: mmsystem.h:581
#define LPDWORD
Definition: nt_native.h:46
UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName)
Definition: mci.c:2161
static const WCHAR L[]
Definition: oid.c:1250
#define MCI_LOAD
Definition: mmsystem.h:670
_In_ PCCERT_CONTEXT _In_ DWORD dwFlags
Definition: wincrypt.h:1175
static DWORD MCI_GetDevTypeFromFileName(LPCWSTR fileName, LPWSTR buf, UINT len)
Definition: mci.c:535
SHORT WINAPI GetAsyncKeyState(_In_ int)
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLenum GLsizei len
Definition: glext.h:6722
BOOL WINAPI mciGetErrorStringW(MCIERROR wError, LPWSTR lpstrBuffer, UINT uLength)
Definition: mci.c:2022
static DWORD MCI_LoadMciDriver(LPCWSTR _strDevTyp, LPWINE_MCIDRIVER *lpwmd)
Definition: mci.c:801
HMODULE WINAPI DECLSPEC_HOTPATCH GetModuleHandleA(LPCSTR lpModuleName)
Definition: loader.c:819
unsigned char BYTE
Definition: mem.h:68
#define MCI_CUT
Definition: mmsystem.h:671
#define MCI_DEVTYPE_CD_AUDIO
Definition: mmsystem.h:683
GLdouble s
Definition: gl.h:2039
#define MCIERR_OUTOFRANGE
Definition: mmsystem.h:592
#define MCI_END_COMMAND_LIST
Definition: mmddk.h:383
#define MCI_DEVTYPE_FIRST
Definition: mmsystem.h:691
#define CASE(s)
UINT WINAPI GetDriveTypeW(IN LPCWSTR lpRootPathName)
Definition: disk.c:497
#define MCI_OPEN_ALIAS
Definition: mmsystem.h:736
uint32_t DWORD_PTR
Definition: typedefs.h:63
#define MCI_CLOSE_DRIVER
Definition: mmddk.h:335
DWORD_PTR dwCallback
Definition: mmsystem.h:1629
#define DRV_ENABLE
Definition: mmsystem.h:120
struct tagMCI_STATUS_PARMS * LPMCI_STATUS_PARMS
#define strcmpiW(s1, s2)
Definition: unicode.h:39
WINE_UNICODE_INLINE WCHAR * strrchrW(const WCHAR *str, WCHAR ch)
Definition: unicode.h:254
#define ERR(fmt,...)
Definition: debug.h:109
#define OF_EXIST
Definition: winbase.h:127
#define HWND_32(h16)
Definition: wownt32.h:29
LPCWSTR * aVerbs
Definition: mci.c:563
#define MCI_SYSINFO_INSTALLNAME
Definition: mmsystem.h:771
BOOL WINAPI mciDriverNotify(HWND hWndCallBack, MCIDEVICEID wDevID, UINT wStatus)
Definition: mci.c:2056
static DWORD MCI_GetReturnType(LPCWSTR lpCmd)
Definition: mci.c:936
WINE_UNICODE_INLINE WCHAR * strcpyW(WCHAR *dst, const WCHAR *src)
Definition: unicode.h:219
HINSTANCE hInst
Definition: dxdiag.c:13
#define MCI_MAGIC
Definition: mci.c:49
DWORD_PTR dwCallback
Definition: mmsystem.h:1521
#define MCI_PUT
Definition: mmsystem.h:666
LPCWSTR lpfilename
Definition: mmsystem.h:1635
#define MM_MCINOTIFY
Definition: mmsystem.h:55
BOOL DRIVER_GetLibName(LPCWSTR keyName, LPCWSTR sectName, LPWSTR buf, int sz)
Definition: driver.c:233
#define KEY_QUERY_VALUE
Definition: nt_native.h:1016
LPWSTR MCI_strdupAtoW(LPCSTR str)
Definition: mci.c:202
HTASK WINAPI mciGetCreatorTask(MCIDEVICEID uDeviceID)
Definition: mci.c:2276
LPCSTR lpstrDeviceType
Definition: mmsystem.h:1523
#define MCI_OPEN_ELEMENT
Definition: mmsystem.h:735
#define sprintfW
Definition: unicode.h:58
#define DRIVE_CDROM
Definition: winbase.h:251
LPWSTR lpstrDeviceType
Definition: winemm.h:121
static const WCHAR wszMci[]
Definition: mci.c:55
unsigned short UINT16
unsigned int UINT
Definition: ndis.h:50
#define MAX_MCICMDTABLE
Definition: mci.c:555
#define MB_OK
Definition: winuser.h:784
#define MCIERR_NO_CLOSING_QUOTE
Definition: mmsystem.h:602
#define HEAP_ZERO_MEMORY
Definition: compat.h:123
#define MCI_CLOSE
Definition: mmsystem.h:647
#define MCI_INTEGER_RETURNED
Definition: mmddk.h:372
#define MCI_GETDEVCAPS
Definition: mmsystem.h:654
#define MCIERR_UNRECOGNIZED_KEYWORD
Definition: mmsystem.h:570
DWORD_PTR dwCallback
Definition: mmsystem.h:1634
#define MCIERR_NEW_REQUIRES_ALIAS
Definition: mmsystem.h:607
#define MultiByteToWideChar
Definition: compat.h:100
UINT MCIDEVICEID
Definition: mmsystem.h:959
#define MCIERR_EXTENSION_NOT_FOUND
Definition: mmsystem.h:591
#define MCI_COLONIZED4_RETURN
Definition: mmddk.h:371
#define msg(x)
Definition: auth_time.c:54
#define MCIERR_UNRECOGNIZED_COMMAND
Definition: mmsystem.h:571
#define HRESULT_CODE(hr)
Definition: winerror.h:76
BOOL WINAPI PostMessageW(_In_opt_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
WINE_UNICODE_INLINE int strcmpW(const WCHAR *str1, const WCHAR *str2)
Definition: unicode.h:229
LPWSTR lpstrElementName
Definition: winemm.h:120
DWORD CreatorThread
Definition: winemm.h:127
uint32_t * LPDWORD
Definition: typedefs.h:57
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
#define MCIERR_EXTRA_CHARACTERS
Definition: mmsystem.h:613
#define MCI_PAUSE
Definition: mmsystem.h:652
#define HIWORD(l)
Definition: typedefs.h:246
DWORD WINAPI mciSendCommandA(MCIDEVICEID wDevID, UINT wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
Definition: mci.c:2122
#define MCI_DATA_SIZE
Definition: mci.c:1004
LONG WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
Definition: reg.c:3366
#define MCI_DEVTYPE_SEQUENCER
Definition: mmsystem.h:690
#define DRV_INSTALL
Definition: mmsystem.h:127
static WINE_MCICMDTABLE S_MciCmdTable[MAX_MCICMDTABLE]
Definition: mci.c:566
#define MCI_DEVTYPE_WAVEFORM_AUDIO
Definition: mmsystem.h:689
#define GetProcAddress(x, y)
Definition: compat.h:410
#define MCI_SYSINFO_OPEN
Definition: mmsystem.h:769
CHAR szPathName[OFS_MAXPATHNAME]
Definition: winbase.h:1247
LPSTR MCI_strdupWtoA(LPCWSTR str)
Definition: mci.c:214
HGLOBAL hMem
Definition: mci.c:560
#define strtoulW(s1, s2, b)
Definition: unicode.h:41
#define MCI_UNDO
Definition: digitalv.h:44
LONG WINAPI RegEnumKeyExW(_In_ HKEY hKey, _In_ DWORD dwIndex, _Out_ LPWSTR lpName, _Inout_ LPDWORD lpcbName, _Reserved_ LPDWORD lpReserved, _Out_opt_ LPWSTR lpClass, _Inout_opt_ LPDWORD lpcbClass, _Out_opt_ PFILETIME lpftLastWriteTime)
Definition: reg.c:2527
BOOL WINAPI PeekMessageW(_Out_ LPMSG, _In_opt_ HWND, _In_ UINT, _In_ UINT, _In_ UINT)
#define PM_REMOVE
Definition: winuser.h:1182
MCIDEVICEID wDeviceID
Definition: mmsystem.h:1530
#define MCI_SYSINFO_NAME
Definition: mmsystem.h:770
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
DWORD dwYieldData
Definition: winemm.h:126
static DWORD MCI_HandleReturnValues(DWORD dwRet, LPWINE_MCIDRIVER wmd, DWORD retType, DWORD_PTR *data, LPWSTR lpstrRet, UINT uRetLen)
Definition: mci.c:1131
#define MCIERR_INVALID_DEVICE_ID
Definition: mmsystem.h:569
GLfloat GLfloat p
Definition: glext.h:8902
WCHAR * LPWSTR
Definition: xmlstorage.h:184
LONG_PTR LRESULT
Definition: windef.h:209
#define MCI_NOTIFY
Definition: mmsystem.h:729
#define MCI_END_CONSTANT
Definition: mmddk.h:386
#define MCI_RETURN
Definition: mmddk.h:381
HMODULE WINAPI GetDriverModuleHandle(HDRVR hDrvr)
Definition: driver.c:536
UINT uTypeCmdTable
Definition: winemm.h:128
DWORD_PTR dwCallback
Definition: mmsystem.h:1613
GLuint64EXT * result
Definition: glext.h:11304
#define memset(x, y, z)
Definition: compat.h:39
BOOL WINAPI mciGetErrorStringA(MCIERROR dwError, LPSTR lpstrBuffer, UINT uLength)
Definition: mci.c:2039
#define MCI_MONITOR
Definition: digitalv.h:37
#define MCIERR_NULL_PARAMETER_BLOCK
Definition: mmsystem.h:605
LPCSTR lpstrElementName
Definition: mmsystem.h:1524
#define TRACE_ON(x)
Definition: compat.h:65
#define MCI_SPIN
Definition: mmsystem.h:655
#define args
Definition: format.c:66
static BOOL MCI_OpenMciDriver(LPWINE_MCIDRIVER wmd, LPCWSTR drvTyp, DWORD_PTR lp)
Definition: mci.c:786
DWORD_PTR dwPrivate
Definition: winemm.h:124
HWND WINAPI GetActiveWindow(void)
Definition: winpos.c:138
#define LOWORD(l)
Definition: pedump.c:82
UINT(CALLBACK * YIELDPROC)(MCIDEVICEID, DWORD)
Definition: mmsystem.h:960
#define HeapFree(x, y, z)
Definition: compat.h:394
#define MCI_UPDATE
Definition: mmsystem.h:674
#define MCIERR_BASE
Definition: mmsystem.h:89
#define MCI_SEEK
Definition: mmsystem.h:650
int(* FARPROC)()
Definition: compat.h:28
#define MCI_DELETE
Definition: mmsystem.h:676
LPCWSTR lpstrAlias
Definition: mmsystem.h:1533
static UINT MCI_GetCommandTable(UINT uDevType)
Definition: mci.c:646
static DWORD MCI_Sound(UINT wDevID, DWORD dwFlags, LPMCI_SOUND_PARMSW lpParms)
Definition: mci.c:1888
#define MCI_LIST
Definition: digitalv.h:43
DWORD MCI_SendCommand(UINT wDevID, UINT16 wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
Definition: mci.c:1908
DWORD_PTR dwCallback
Definition: mmsystem.h:1573
static int mod
Definition: i386-dis.c:1273
#define MCI_SYSINFO
Definition: mmsystem.h:659
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
YIELDPROC WINAPI mciGetYieldProc(MCIDEVICEID uDeviceID, DWORD *lpdwYieldData)
Definition: mci.c:2255
signed short INT16