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 46 WINE_DEFAULT_DEBUG_CHANNEL(mci); 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 59 static WINE_MCIDRIVER *MciDrivers; 60 61 static UINT WINAPI MCI_DefYieldProc(MCIDEVICEID wDevID, DWORD data); 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 */ 80 static LPWINE_MCIDRIVER MCI_GetDriver(UINT wDevID) 81 { 82 LPWINE_MCIDRIVER wmd = 0; 83 84 EnterCriticalSection(&WINMM_cs); 85 for (wmd = MciDrivers; wmd; wmd = wmd->lpNext) { 86 if (wmd->wDeviceID == wDevID) 87 break; 88 } 89 LeaveCriticalSection(&WINMM_cs); 90 return wmd; 91 } 92 93 /************************************************************************** 94 * MCI_GetDriverFromString [internal] 95 */ 96 static UINT MCI_GetDriverFromString(LPCWSTR lpstrName) 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 107 EnterCriticalSection(&WINMM_cs); 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 } 122 LeaveCriticalSection(&WINMM_cs); 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); 143 CASE(DRV_CONFIGURE); 144 CASE(DRV_QUERYCONFIGURE); 145 CASE(DRV_INSTALL); 146 CASE(DRV_REMOVE); 147 CASE(DRV_EXITSESSION); 148 CASE(DRV_EXITAPPLICATION); 149 CASE(DRV_POWER); 150 CASE(MCI_BREAK); 151 CASE(MCI_CLOSE); 152 CASE(MCI_CLOSE_DRIVER); 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); 161 CASE(MCI_GETDEVCAPS); 162 CASE(MCI_INFO); 163 CASE(MCI_LOAD); 164 CASE(MCI_OPEN); 165 CASE(MCI_OPEN_DRIVER); 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); 179 CASE(MCI_UNFREEZE); 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); 187 CASE(MCI_SETAUDIO); 188 CASE(MCI_SIGNAL); 189 CASE(MCI_SETVIDEO); 190 CASE(MCI_QUALITY); 191 CASE(MCI_LIST); 192 CASE(MCI_UNDO); 193 CASE(MCI_CONFIGURE); 194 CASE(MCI_RESTORE); 195 #undef CASE 196 default: 197 sprintf(buffer, "MCI_<<%04X>>", wMsg); 198 return buffer; 199 } 200 } 201 202 LPWSTR MCI_strdupAtoW( LPCSTR str ) 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 214 LPSTR MCI_strdupWtoA( LPCWSTR str ) 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 471 WideCharToMultiByte(CP_ACP, 0, 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 { 489 WideCharToMultiByte(CP_ACP, 0, 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 */ 535 static DWORD MCI_GetDevTypeFromFileName(LPCWSTR fileName, LPWSTR buf, UINT len) 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, '.'))) { 543 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, keyW, 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 } 552 return MCIERR_EXTENSION_NOT_FOUND; 553 } 554 555 #define MAX_MCICMDTABLE 20 556 #define MCI_COMMAND_TABLE_NOT_LOADED 0xFFFE 557 558 typedef struct tagWINE_MCICMDTABLE { 559 UINT uDevType; 560 HGLOBAL hMem; 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 */ 564 } WINE_MCICMDTABLE, *LPWINE_MCICMDTABLE; 565 566 static WINE_MCICMDTABLE S_MciCmdTable[MAX_MCICMDTABLE]; 567 568 /************************************************************************** 569 * MCI_IsCommandTableValid [internal] 570 */ 571 static BOOL MCI_IsCommandTableValid(UINT uTbl) 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 */ 615 static BOOL MCI_DumpCommandTable(UINT uTbl) 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) { 669 HRSRC hRsrc = FindResourceW(hWinMM32Instance, str, (LPCWSTR)RT_RCDATA); 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", 677 hWinMM32Instance, debugstr_w(str)); 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; 699 MCI_GetCommandTable(0); 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 */ 754 static BOOL MCI_UnLoadMciDriver(LPWINE_MCIDRIVER wmd) 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 766 EnterCriticalSection(&WINMM_cs); 767 for (tmp = &MciDrivers; *tmp; tmp = &(*tmp)->lpNext) { 768 if (*tmp == wmd) { 769 *tmp = wmd->lpNext; 770 break; 771 } 772 } 773 LeaveCriticalSection(&WINMM_cs); 774 775 HeapFree(GetProcessHeap(), 0, wmd->lpstrDeviceType); 776 HeapFree(GetProcessHeap(), 0, wmd->lpstrAlias); 777 HeapFree(GetProcessHeap(), 0, wmd->lpstrElementName); 778 779 HeapFree(GetProcessHeap(), 0, wmd); 780 return TRUE; 781 } 782 783 /************************************************************************** 784 * MCI_OpenMciDriver [internal] 785 */ 786 static BOOL MCI_OpenMciDriver(LPWINE_MCIDRIVER wmd, LPCWSTR drvTyp, DWORD_PTR lp) 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 */ 801 static DWORD MCI_LoadMciDriver(LPCWSTR _strDevTyp, LPWINE_MCIDRIVER* lpwmd) 802 { 803 LPWSTR strDevTyp = str_dup_upper(_strDevTyp); 804 LPWINE_MCIDRIVER wmd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wmd)); 805 MCI_OPEN_DRIVER_PARMSW modp; 806 DWORD dwRet = 0; 807 808 if (!wmd || !strDevTyp) { 809 dwRet = MCIERR_OUT_OF_MEMORY; 810 goto errCleanUp; 811 } 812 813 wmd->lpfnYieldProc = MCI_DefYieldProc; 814 wmd->dwYieldData = VK_CANCEL; 815 wmd->CreatorThread = GetCurrentThreadId(); 816 817 EnterCriticalSection(&WINMM_cs); 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 830 LeaveCriticalSection(&WINMM_cs); 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)); 845 dwRet = MCIERR_DEVICE_NOT_INSTALLED; 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); 856 wmd->uTypeCmdTable = MCI_COMMAND_TABLE_NOT_LOADED; 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 { 880 DWORD dwRet = MCIERR_INVALID_DEVICE_ID; 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 */ 892 static DWORD MCI_FinishOpen(LPWINE_MCIDRIVER wmd, LPMCI_OPEN_PARMSW lpParms, 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 */ 914 static LPCWSTR MCI_FindCommand(UINT uTbl, LPCWSTR verb) 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 */ 936 static DWORD MCI_GetReturnType(LPCWSTR lpCmd) 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 */ 948 static WORD MCI_GetMessage(LPCWSTR lpCmd) 949 { 950 return (WORD)*(const DWORD*)(lpCmd + strlenW(lpCmd) + 1); 951 } 952 953 /************************************************************************** 954 * MCI_GetDWord [internal] 955 */ 956 static BOOL MCI_GetDWord(DWORD_PTR *data, LPWSTR* ptr) 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 */ 977 static DWORD MCI_GetString(LPWSTR* str, LPWSTR* args) 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, 1010 LPWSTR args, LPDWORD dwFlags) 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)); 1118 return MCIERR_UNRECOGNIZED_COMMAND; 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 */ 1131 static DWORD MCI_HandleReturnValues(DWORD dwRet, LPWINE_MCIDRIVER wmd, DWORD retType, 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; 1154 case MCI_RESOURCE_RETURNED|MCI_RESOURCE_DRIVER: 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 */ 1158 LoadStringW(GetDriverModuleHandle(wmd->hDriver), 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; 1210 DWORD_PTR data[MCI_DATA_SIZE]; 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, ' '))) { 1230 dwRet = MCIERR_MISSING_DEVICE_NAME; 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"); 1255 dwRet = MCIERR_MISSING_DEVICE_NAME; 1256 goto errCleanUp; 1257 } 1258 } else if ((devType = strchrW(dev, '!')) != NULL) { 1259 *devType++ = '\0'; 1260 tmp = devType; devType = dev; dev = tmp; 1261 1262 dwFlags |= MCI_OPEN_TYPE; 1263 data[2] = (DWORD_PTR)devType; 1264 devType = str_dup_upper(devType); 1265 dwFlags |= MCI_OPEN_ELEMENT; 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 = ' '; 1274 dwFlags |= MCI_OPEN_TYPE; 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 } 1289 dwFlags |= MCI_OPEN_ELEMENT; 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) 1311 dwRet = MCIERR_INVALID_DEVICE_NAME; 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 1326 wmd = MCI_GetDriver(mciGetDeviceIDW(dev)); 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 */ 1340 if (wmd->uTypeCmdTable == MCI_COMMAND_TABLE_NOT_LOADED) 1341 wmd->uTypeCmdTable = MCI_GetCommandTable(wmd->wType); 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)); 1351 dwRet = MCIERR_UNRECOGNIZED_COMMAND; 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", 1381 wmd->wDeviceID, MCI_MessageToString(MCI_GetMessage(lpCmd)), dwFlags, 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 */ 1437 BOOL WINAPI mciExecute(LPCSTR lpstrCommand) 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 */ 1460 UINT WINAPI mciLoadCommandResource(HINSTANCE hInst, LPCWSTR resNameW, UINT type) 1461 { 1462 UINT ret = MCI_NO_COMMAND_TABLE; 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 */ 1500 BOOL WINAPI mciFreeCommandResource(UINT uTable) 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) { 1553 dwRet = MCIERR_NULL_PARAMETER_BLOCK; 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)); 1567 dwRet = MCIERR_UNRECOGNIZED_KEYWORD; 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"); 1585 dwRet = MCIERR_UNRECOGNIZED_KEYWORD; 1586 goto errCleanUp; 1587 } 1588 1589 if (!lpParms->lpstrElementName) { 1590 dwRet = MCIERR_NULL_PARAMETER_BLOCK; 1591 goto errCleanUp; 1592 } 1593 1594 /* type, if given as a parameter, supersedes file extension */ 1595 if (!strDevTyp[0] && 1596 MCI_GetDevTypeFromFileName(lpParms->lpstrElementName, 1597 strDevTyp, sizeof(strDevTyp))) { 1598 static const WCHAR wszCdAudio[] = {'C','D','A','U','D','I','O',0}; 1599 if (GetDriveTypeW(lpParms->lpstrElementName) != DRIVE_CDROM) { 1600 dwRet = MCIERR_EXTENSION_NOT_FOUND; 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"); 1610 dwRet = MCIERR_INVALID_DEVICE_NAME; 1611 goto errCleanUp; 1612 } 1613 1614 if (dwParam & MCI_OPEN_ALIAS) { 1615 TRACE("Alias=%s !\n", debugstr_w(lpParms->lpstrAlias)); 1616 if (!lpParms->lpstrAlias) { 1617 dwRet = MCIERR_NULL_PARAMETER_BLOCK; 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) 1636 mciDriverNotify((HWND)lpParms->dwCallback, wmd->wDeviceID, MCI_NOTIFY_SUCCESSFUL); 1637 1638 return 0; 1639 errCleanUp: 1640 if (wmd) MCI_UnLoadMciDriver(wmd); 1641 1642 if (dwParam & MCI_NOTIFY) 1643 mciDriverNotify((HWND)lpParms->dwCallback, 0, MCI_NOTIFY_FAILURE); 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 */ 1668 EnterCriticalSection(&WINMM_cs); 1669 if (!MciDrivers) 1670 { 1671 LeaveCriticalSection(&WINMM_cs); 1672 break; 1673 } 1674 wDevID = MciDrivers->wDeviceID; 1675 LeaveCriticalSection(&WINMM_cs); 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, 1692 dwRet ? MCI_NOTIFY_FAILURE : MCI_NOTIFY_SUCCESSFUL); 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); 1708 ret = MCIERR_PARAM_OVERFLOW; 1709 } else { 1710 strcpyW(lpDstStr, lpSrcStr); 1711 } 1712 } else { 1713 *lpDstStr = 0; 1714 } 1715 return ret; 1716 } 1717 1718 /************************************************************************** 1719 * MCI_Sysinfo [internal] 1720 */ 1721 static DWORD MCI_SysInfo(UINT uDevID, DWORD dwFlags, LPMCI_SYSINFO_PARMSW lpParms) 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 1736 switch (dwFlags & ~(MCI_SYSINFO_OPEN|MCI_NOTIFY|MCI_WAIT)) { 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"); 1745 EnterCriticalSection(&WINMM_cs); 1746 for (wmd = MciDrivers; wmd; wmd = wmd->lpNext) { 1747 cnt++; 1748 } 1749 LeaveCriticalSection(&WINMM_cs); 1750 } else { 1751 TRACE("MCI_SYSINFO_QUANTITY: # of installed MCI drivers\n"); 1752 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, wszHklmMci, 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); 1763 EnterCriticalSection(&WINMM_cs); 1764 for (wmd = MciDrivers; wmd; wmd = wmd->lpNext) { 1765 if (wmd->wType == lpParms->wDeviceType) cnt++; 1766 } 1767 LeaveCriticalSection(&WINMM_cs); 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: 1775 case MCI_DEVTYPE_WAVEFORM_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); 1786 ret = MCI_INTEGER_RETURNED; 1787 /* return ret; Only Win9x sends a notification in this case. */ 1788 break; 1789 case MCI_SYSINFO_INSTALLNAME: 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) 1796 ? MCIERR_CANNOT_USE_ALL : MCIERR_INVALID_DEVICE_NAME; 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); 1806 EnterCriticalSection(&WINMM_cs); 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 } 1818 LeaveCriticalSection(&WINMM_cs); 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); 1822 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, wszHklmMci, 0, 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) 1851 ret = MCIERR_OUTOFRANGE; 1852 else { 1853 LoadStringW(hWinMM32Instance, LOWORD(lpParms->wDeviceType), 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); 1862 ret = MCIERR_UNRECOGNIZED_KEYWORD; 1863 } 1864 if ((dwFlags & MCI_NOTIFY) && HRESULT_CODE(ret)==0) 1865 mciDriverNotify((HWND)lpParms->dwCallback, uDevID, MCI_NOTIFY_SUCCESSFUL); 1866 return ret; 1867 } 1868 1869 /************************************************************************** 1870 * MCI_Break [internal] 1871 */ 1872 static DWORD MCI_Break(UINT wDevID, DWORD dwFlags, LPMCI_BREAK_PARMS lpParms) 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 { 1910 DWORD dwRet = MCIERR_UNRECOGNIZED_COMMAND; 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: 1962 case MCI_RESOURCE_RETURNED|MCI_RESOURCE_DRIVER: 1963 { 1964 LPMCI_GETDEVCAPS_PARMS lmgp; 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: 1985 case MCI_RESOURCE_RETURNED|MCI_RESOURCE_DRIVER: 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 */ 2066 DWORD_PTR WINAPI mciGetDriverData(MCIDEVICEID uDeviceID) 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 */ 2085 BOOL WINAPI mciSetDriverData(MCIDEVICEID uDeviceID, DWORD_PTR data) 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 */ 2106 DWORD WINAPI mciSendCommandW(MCIDEVICEID wDevID, UINT wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2) 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 */ 2122 DWORD WINAPI mciSendCommandA(MCIDEVICEID wDevID, UINT wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2) 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 */ 2145 UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName) 2146 { 2147 LPWSTR w = MCI_strdupAtoW(lpstrName); 2148 UINT ret = MCIERR_OUT_OF_MEMORY; 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 */ 2161 UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName) 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 */ 2184 static UINT WINAPI MCI_DefYieldProc(MCIDEVICEID wDevID, DWORD data) 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 */ 2227 UINT WINAPI mciGetDeviceIDFromElementIDA(DWORD dwElementID, LPCSTR lpstrType) 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 */ 2243 UINT WINAPI mciGetDeviceIDFromElementIDW(DWORD dwElementID, LPCWSTR lpstrType) 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 */ 2255 YIELDPROC WINAPI mciGetYieldProc(MCIDEVICEID uDeviceID, DWORD* lpdwYieldData) 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 */ 2276 HTASK WINAPI mciGetCreatorTask(MCIDEVICEID uDeviceID) 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 */ 2290 UINT WINAPI mciDriverYield(MCIDEVICEID uDeviceID) 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 } 2305