mshtml: Use create_nselem in exec_hyperlink.
[wine] / dlls / winmm / mci16.c
1 /*
2  * MMSYSTEM functions
3  *
4  * Copyright 1993      Martin Ayotte
5  *           1998-2003,2009 Eric Pouech
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #include <stdarg.h>
23 #include <string.h>
24
25 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
27 #include "windef.h"
28 #include "winbase.h"
29 #include "mmsystem.h"
30 #include "winternl.h"
31 #include "wownt32.h"
32 #include "winnls.h"
33
34 #include "wine/winuser16.h"
35 #include "winemm16.h"
36
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(mmsys);
40
41 /* ###################################################
42  * #                     MCI                         #
43  * ###################################################
44  */
45
46 #include <pshpack1.h>
47 #define MCI_MAX_THUNKS      32
48
49 static struct mci_thunk
50 {
51     BYTE        popl_eax;       /* popl  %eax (return address) */
52     BYTE        pushl_func;     /* pushl $pfn16 (16bit callback function) */
53     YIELDPROC16 yield16;
54     BYTE        pushl_eax;      /* pushl %eax */
55     BYTE        jmp;            /* ljmp MCI_Yield1632 */
56     DWORD       callback;
57     MCIDEVICEID id;
58 } *MCI_Thunks;
59
60 #include <poppack.h>
61
62 static CRITICAL_SECTION mci_cs;
63 static CRITICAL_SECTION_DEBUG mci_critsect_debug =
64 {
65     0, 0, &mci_cs,
66     { &mci_critsect_debug.ProcessLocksList, &mci_critsect_debug.ProcessLocksList },
67       0, 0, { (DWORD_PTR)(__FILE__ ": mmsystem_mci_cs") }
68 };
69 static CRITICAL_SECTION mci_cs = { &mci_critsect_debug, -1, 0, 0, 0, 0 };
70
71 static UINT MCI_Yield1632(DWORD pfn16, MCIDEVICEID id, DWORD yield_data)
72 {
73     WORD args[8];
74
75     if (!pfn16)
76     {
77         UserYield16();
78         return 0;
79     }
80
81     /* 16 bit func, call it */
82     TRACE("Function (16 bit) !\n");
83
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);
88 }
89
90 /******************************************************************
91  *              MCI_AddThunk
92  *
93  */
94 static struct mci_thunk*       MCI_AddThunk(MCIDEVICEID id, YIELDPROC16 pfn16)
95 {
96      struct mci_thunk* thunk;
97
98      if (!MCI_Thunks)
99      {
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++)
104          {
105              thunk->popl_eax     = 0x58;   /* popl  %eax */
106              thunk->pushl_func   = 0x68;   /* pushl $pfn16 */
107              thunk->yield16      = 0;
108              thunk->pushl_eax    = 0x50;   /* pushl %eax */
109              thunk->jmp          = 0xe9;   /* jmp MCI_Yield1632 */
110              thunk->callback     = (char *)MCI_Yield1632 - (char *)(&thunk->callback + 1);
111              thunk->id           = 0;
112          }
113      }
114      for (thunk = MCI_Thunks; thunk < &MCI_Thunks[MCI_MAX_THUNKS]; thunk++)
115      {
116          if (thunk->yield16 == 0)
117          {
118              thunk->yield16 = pfn16;
119              thunk->id      = id;
120              return thunk;
121          }
122      }
123      FIXME("Out of mci-thunks. Bump MCI_MAX_THUNKS\n");
124      return NULL;
125 }
126
127 /******************************************************************
128  *              MCI_HasThunk
129  *
130  */
131 static struct mci_thunk*    MCI_HasThunk(YIELDPROC pfn)
132 {
133     struct mci_thunk* thunk;
134
135     if (!MCI_Thunks) return NULL;
136     for (thunk = MCI_Thunks; thunk < &MCI_Thunks[MCI_MAX_THUNKS]; thunk++)
137     {
138         if ((YIELDPROC)thunk == pfn) return thunk;
139     }
140     return NULL;
141 }
142
143 /**************************************************************************
144  *                              mciSetYieldProc                 [MMSYSTEM.714]
145  */
146 BOOL16 WINAPI mciSetYieldProc16(UINT16 uDeviceID, YIELDPROC16 fpYieldProc, DWORD dwYieldData)
147 {
148     struct mci_thunk*   thunk;
149     BOOL                ret;
150
151     TRACE("(%u, %p, %08x)\n", uDeviceID, fpYieldProc, dwYieldData);
152
153     if (!(thunk = MCI_AddThunk(uDeviceID, fpYieldProc)))
154         return FALSE;
155     ret = mciSetYieldProc(uDeviceID, (YIELDPROC)thunk, dwYieldData);
156     if (!ret) thunk->yield16 = NULL;
157     return ret;
158 }
159
160 /**************************************************************************
161  *                              mciGetYieldProc                 [MMSYSTEM.716]
162  */
163 YIELDPROC16 WINAPI mciGetYieldProc16(UINT16 uDeviceID, DWORD* lpdwYieldData)
164 {
165     YIELDPROC           yield;
166     DWORD               data;
167     struct mci_thunk*   thunk;
168
169     TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData);
170
171     yield = mciGetYieldProc(uDeviceID, &data);
172     if (!yield || !(thunk = MCI_HasThunk(yield))) return NULL;
173
174     if (lpdwYieldData) *lpdwYieldData = data;
175     return thunk->yield16;
176 }
177
178 /**************************************************************************
179  *                              mciGetErrorString               [MMSYSTEM.706]
180  */
181 BOOL16 WINAPI mciGetErrorString16(DWORD wError, LPSTR lpstrBuffer, UINT16 uLength)
182 {
183     return mciGetErrorStringA(wError, lpstrBuffer, uLength);
184 }
185
186 /**************************************************************************
187  *                              mciDriverNotify                 [MMSYSTEM.711]
188  */
189 BOOL16 WINAPI mciDriverNotify16(HWND16 hWndCallBack, UINT16 wDevID, UINT16 wStatus)
190 {
191     TRACE("(%04X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
192
193     return PostMessageA(HWND_32(hWndCallBack), MM_MCINOTIFY, wStatus, wDevID);
194 }
195
196 /**************************************************************************
197  *                      mciGetDriverData                        [MMSYSTEM.708]
198  */
199 DWORD WINAPI mciGetDriverData16(UINT16 uDeviceID)
200 {
201     return mciGetDriverData(uDeviceID);
202 }
203
204 /**************************************************************************
205  *                      mciSetDriverData                        [MMSYSTEM.707]
206  */
207 BOOL16 WINAPI mciSetDriverData16(UINT16 uDeviceID, DWORD data)
208 {
209     return mciSetDriverData(uDeviceID, data);
210 }
211
212 /**************************************************************************
213  *                              mciSendCommand                  [MMSYSTEM.701]
214  */
215 DWORD WINAPI mciSendCommand16(UINT16 wDevID, UINT16 wMsg, DWORD dwParam1, DWORD p2)
216 {
217     DWORD               dwRet;
218     BOOL                to32;
219     DWORD_PTR           dwParam2 = p2;
220
221     TRACE("(%04X, %u, %08X, %08lX)\n", wDevID, wMsg, dwParam1, dwParam2);
222
223     switch (wMsg) {
224     case MCI_CLOSE:
225     case MCI_OPEN:
226     case MCI_SYSINFO:
227     case MCI_BREAK:
228     case MCI_SOUND:
229         to32 = TRUE;
230         break;
231     default:
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.
235          */
236         to32 = TRUE;
237     }
238     if (to32) {
239         MMSYSTEM_MapType res;
240
241         dwRet = MCIERR_INVALID_DEVICE_ID;
242
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;
247             break;
248         case MMSYSTEM_MAP_NOMEM:
249             TRACE("Problem mapping msg=%u from 16 to 32a\n", wMsg);
250             dwRet = MCIERR_OUT_OF_MEMORY;
251             break;
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);
257             break;
258         }
259     }
260     else
261     {
262 #if 0
263         if (wDevID == MCI_ALL_DEVICE_ID) {
264             FIXME("unhandled MCI_ALL_DEVICE_ID\n");
265             dwRet = MCIERR_CANNOT_USE_ALL;
266         } else {
267             dwRet = SendDriverMessage(hdrv, wMsg, dwParam1, dwParam2);
268         }
269 #endif
270     }
271     if (wMsg == MCI_CLOSE && dwRet == 0 && MCI_Thunks)
272     {
273         /* free yield thunks, if any */
274         unsigned    i;
275         for (i = 0; i < MCI_MAX_THUNKS; i++)
276         {
277             if (MCI_Thunks[i].id == wDevID)
278                 MCI_Thunks[i].yield16 = NULL;
279         }
280     }
281     return dwRet;
282 }
283
284 /**************************************************************************
285  *                              mciGetDeviceID                  [MMSYSTEM.703]
286  */
287 UINT16 WINAPI mciGetDeviceID16(LPCSTR lpstrName)
288 {
289     TRACE("(\"%s\")\n", lpstrName);
290
291     return mciGetDeviceIDA(lpstrName);
292 }
293
294 /**************************************************************************
295  *                              mciGetDeviceIDFromElementID     [MMSYSTEM.715]
296  */
297 UINT16 WINAPI mciGetDeviceIDFromElementID16(DWORD dwElementID, LPCSTR lpstrType)
298 {
299     return mciGetDeviceIDFromElementIDA(dwElementID, lpstrType);
300 }
301
302 /**************************************************************************
303  *                              mciGetCreatorTask               [MMSYSTEM.717]
304  */
305 HTASK16 WINAPI mciGetCreatorTask16(UINT16 uDeviceID)
306 {
307     return HTASK_16(mciGetCreatorTask(uDeviceID));
308 }
309
310 /**************************************************************************
311  *                              mciDriverYield                  [MMSYSTEM.710]
312  */
313 UINT16 WINAPI mciDriverYield16(UINT16 uDeviceID)
314 {
315     return mciDriverYield(uDeviceID);
316 }
317
318 /**************************************************************************
319  *                              mciSendString                   [MMSYSTEM.702]
320  */
321 DWORD WINAPI mciSendString16(LPCSTR lpstrCommand, LPSTR lpstrRet,
322                              UINT16 uRetLen, HWND16 hwndCallback)
323 {
324     return mciSendStringA(lpstrCommand, lpstrRet, uRetLen, HWND_32(hwndCallback));
325 }