4 * Copyright 1993 Martin Ayotte
5 * 1998-2003,2009 Eric Pouech
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
34 #include "wine/winuser16.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(mmsys);
41 /* ###################################################
43 * ###################################################
47 #define MCI_MAX_THUNKS 32
49 static struct mci_thunk
51 BYTE popl_eax; /* popl %eax (return address) */
52 BYTE pushl_func; /* pushl $pfn16 (16bit callback function) */
54 BYTE pushl_eax; /* pushl %eax */
55 BYTE jmp; /* ljmp MCI_Yield1632 */
62 static CRITICAL_SECTION mci_cs;
63 static CRITICAL_SECTION_DEBUG mci_critsect_debug =
66 { &mci_critsect_debug.ProcessLocksList, &mci_critsect_debug.ProcessLocksList },
67 0, 0, { (DWORD_PTR)(__FILE__ ": mmsystem_mci_cs") }
69 static CRITICAL_SECTION mci_cs = { &mci_critsect_debug, -1, 0, 0, 0, 0 };
71 static UINT MCI_Yield1632(DWORD pfn16, MCIDEVICEID id, DWORD yield_data)
81 /* 16 bit func, call it */
82 TRACE("Function (16 bit) !\n");
84 args[2] = (MCIDEVICEID16)id;
85 args[1] = HIWORD(yield_data);
86 args[0] = LOWORD(yield_data);
87 return WOWCallback16Ex(pfn16, WCB16_PASCAL, sizeof(args), args, NULL);
90 /******************************************************************
94 static struct mci_thunk* MCI_AddThunk(MCIDEVICEID id, YIELDPROC16 pfn16)
96 struct mci_thunk* thunk;
100 MCI_Thunks = VirtualAlloc(NULL, MCI_MAX_THUNKS * sizeof(*MCI_Thunks), MEM_COMMIT,
101 PAGE_EXECUTE_READWRITE);
102 if (!MCI_Thunks) return NULL;
103 for (thunk = MCI_Thunks; thunk < &MCI_Thunks[MCI_MAX_THUNKS]; thunk++)
105 thunk->popl_eax = 0x58; /* popl %eax */
106 thunk->pushl_func = 0x68; /* pushl $pfn16 */
108 thunk->pushl_eax = 0x50; /* pushl %eax */
109 thunk->jmp = 0xe9; /* jmp MCI_Yield1632 */
110 thunk->callback = (char *)MCI_Yield1632 - (char *)(&thunk->callback + 1);
114 for (thunk = MCI_Thunks; thunk < &MCI_Thunks[MCI_MAX_THUNKS]; thunk++)
116 if (thunk->yield16 == 0)
118 thunk->yield16 = pfn16;
123 FIXME("Out of mci-thunks. Bump MCI_MAX_THUNKS\n");
127 /******************************************************************
131 static struct mci_thunk* MCI_HasThunk(YIELDPROC pfn)
133 struct mci_thunk* thunk;
135 if (!MCI_Thunks) return NULL;
136 for (thunk = MCI_Thunks; thunk < &MCI_Thunks[MCI_MAX_THUNKS]; thunk++)
138 if ((YIELDPROC)thunk == pfn) return thunk;
143 /**************************************************************************
144 * mciSetYieldProc [MMSYSTEM.714]
146 BOOL16 WINAPI mciSetYieldProc16(UINT16 uDeviceID, YIELDPROC16 fpYieldProc, DWORD dwYieldData)
148 struct mci_thunk* thunk;
151 TRACE("(%u, %p, %08x)\n", uDeviceID, fpYieldProc, dwYieldData);
153 if (!(thunk = MCI_AddThunk(uDeviceID, fpYieldProc)))
155 ret = mciSetYieldProc(uDeviceID, (YIELDPROC)thunk, dwYieldData);
156 if (!ret) thunk->yield16 = NULL;
160 /**************************************************************************
161 * mciGetYieldProc [MMSYSTEM.716]
163 YIELDPROC16 WINAPI mciGetYieldProc16(UINT16 uDeviceID, DWORD* lpdwYieldData)
167 struct mci_thunk* thunk;
169 TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
171 yield = mciGetYieldProc(uDeviceID, &data);
172 if (!yield || !(thunk = MCI_HasThunk(yield))) return NULL;
174 if (lpdwYieldData) *lpdwYieldData = data;
175 return thunk->yield16;
178 /**************************************************************************
179 * mciGetErrorString [MMSYSTEM.706]
181 BOOL16 WINAPI mciGetErrorString16(DWORD wError, LPSTR lpstrBuffer, UINT16 uLength)
183 return mciGetErrorStringA(wError, lpstrBuffer, uLength);
186 /**************************************************************************
187 * mciDriverNotify [MMSYSTEM.711]
189 BOOL16 WINAPI mciDriverNotify16(HWND16 hWndCallBack, UINT16 wDevID, UINT16 wStatus)
191 TRACE("(%04X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
193 return PostMessageA(HWND_32(hWndCallBack), MM_MCINOTIFY, wStatus, wDevID);
196 /**************************************************************************
197 * mciGetDriverData [MMSYSTEM.708]
199 DWORD WINAPI mciGetDriverData16(UINT16 uDeviceID)
201 return mciGetDriverData(uDeviceID);
204 /**************************************************************************
205 * mciSetDriverData [MMSYSTEM.707]
207 BOOL16 WINAPI mciSetDriverData16(UINT16 uDeviceID, DWORD data)
209 return mciSetDriverData(uDeviceID, data);
212 /**************************************************************************
213 * mciSendCommand [MMSYSTEM.701]
215 DWORD WINAPI mciSendCommand16(UINT16 wDevID, UINT16 wMsg, DWORD dwParam1, DWORD p2)
219 DWORD_PTR dwParam2 = p2;
221 TRACE("(%04X, %u, %08X, %08lX)\n", wDevID, wMsg, dwParam1, dwParam2);
232 /* FIXME: this is suboptimal. If MCI driver is a 16bit one, we'll be
233 * doing 16=>32W, then 32W=>16 conversions.
234 * We could directly call the 16bit driver if we had the information.
239 MMSYSTEM_MapType res;
241 dwRet = MCIERR_INVALID_DEVICE_ID;
243 switch (res = MCI_MapMsg16To32W(wMsg, dwParam1, &dwParam2)) {
244 case MMSYSTEM_MAP_MSGERROR:
245 TRACE("Not handled yet (%u)\n", wMsg);
246 dwRet = MCIERR_DRIVER_INTERNAL;
248 case MMSYSTEM_MAP_NOMEM:
249 TRACE("Problem mapping msg=%u from 16 to 32a\n", wMsg);
250 dwRet = MCIERR_OUT_OF_MEMORY;
252 case MMSYSTEM_MAP_OK:
253 case MMSYSTEM_MAP_OKMEM:
254 dwRet = mciSendCommandW(wDevID, wMsg, dwParam1, dwParam2);
255 if (res == MMSYSTEM_MAP_OKMEM)
256 MCI_UnMapMsg16To32W(wMsg, dwParam1, dwParam2);
263 if (wDevID == MCI_ALL_DEVICE_ID) {
264 FIXME("unhandled MCI_ALL_DEVICE_ID\n");
265 dwRet = MCIERR_CANNOT_USE_ALL;
267 dwRet = SendDriverMessage(hdrv, wMsg, dwParam1, dwParam2);
271 if (wMsg == MCI_CLOSE && dwRet == 0 && MCI_Thunks)
273 /* free yield thunks, if any */
275 for (i = 0; i < MCI_MAX_THUNKS; i++)
277 if (MCI_Thunks[i].id == wDevID)
278 MCI_Thunks[i].yield16 = NULL;
284 /**************************************************************************
285 * mciGetDeviceID [MMSYSTEM.703]
287 UINT16 WINAPI mciGetDeviceID16(LPCSTR lpstrName)
289 TRACE("(\"%s\")\n", lpstrName);
291 return mciGetDeviceIDA(lpstrName);
294 /**************************************************************************
295 * mciGetDeviceIDFromElementID [MMSYSTEM.715]
297 UINT16 WINAPI mciGetDeviceIDFromElementID16(DWORD dwElementID, LPCSTR lpstrType)
299 return mciGetDeviceIDFromElementIDA(dwElementID, lpstrType);
302 /**************************************************************************
303 * mciGetCreatorTask [MMSYSTEM.717]
305 HTASK16 WINAPI mciGetCreatorTask16(UINT16 uDeviceID)
307 return HTASK_16(mciGetCreatorTask(uDeviceID));
310 /**************************************************************************
311 * mciDriverYield [MMSYSTEM.710]
313 UINT16 WINAPI mciDriverYield16(UINT16 uDeviceID)
315 return mciDriverYield(uDeviceID);
318 /**************************************************************************
319 * mciSendString [MMSYSTEM.702]
321 DWORD WINAPI mciSendString16(LPCSTR lpstrCommand, LPSTR lpstrRet,
322 UINT16 uRetLen, HWND16 hwndCallback)
324 return mciSendStringA(lpstrCommand, lpstrRet, uRetLen, HWND_32(hwndCallback));