Support for nonstandard baud rate in SetCommState.
[wine] / dlls / msacm / internal.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2
3 /*
4  *      MSACM32 library
5  *
6  *      Copyright 1998  Patrik Stridvall
7  *                1999  Eric Pouech
8  */
9
10 #include <string.h>
11
12 #include "winbase.h"
13 #include "windef.h"
14 #include "wingdi.h"
15 #include "winuser.h"
16 #include "winerror.h"
17 #include "winreg.h"
18 #include "mmsystem.h"
19 #include "msacm.h"
20 #include "msacmdrv.h"
21 #include "wineacm.h"
22 #include "debugtools.h"
23
24 DEFAULT_DEBUG_CHANNEL(msacm);
25
26 /**********************************************************************/
27
28 HANDLE MSACM_hHeap = (HANDLE) NULL;
29 PWINE_ACMDRIVERID MSACM_pFirstACMDriverID = NULL;
30 PWINE_ACMDRIVERID MSACM_pLastACMDriverID = NULL;
31
32 #if 0
33 /***********************************************************************
34  *           MSACM_DumpCache
35  */
36 static  void MSACM_DumpCache(PWINE_ACMDRIVERID padid) 
37 {
38     unsigned    i;
39
40     TRACE("cFilterTags=%lu cFormatTags=%lu fdwSupport=%08lx\n",
41           padid->cFilterTags, padid->cFormatTags, padid->fdwSupport);
42     for (i = 0; i < padid->cache->cFormatTags; i++) {
43         TRACE("\tdwFormatTag=%lu cbwfx=%lu\n", 
44               padid->aFormatTag[i].dwFormatTag, padid->aFormatTag[i].cbwfx);
45     }
46 }
47 #endif
48
49 /***********************************************************************
50  *           MSACM_FindFormatTagInCache                 [internal]
51  * 
52  *      Returns TRUE is the format tag fmtTag is present in the cache.
53  *      If so, idx is set to its index.
54  */
55 BOOL MSACM_FindFormatTagInCache(WINE_ACMDRIVERID* padid, DWORD fmtTag, LPDWORD idx)
56 {
57     unsigned    i;
58
59     for (i = 0; i < padid->cFormatTags; i++) {
60         if (padid->aFormatTag[i].dwFormatTag == fmtTag) {
61             if (idx) *idx = i;
62             return TRUE;
63         }
64     }
65     return FALSE;
66 }
67
68 /***********************************************************************
69  *           MSACM_FillCache
70  */
71 static BOOL MSACM_FillCache(PWINE_ACMDRIVERID padid) 
72 {
73     HACMDRIVER                  had = 0;
74     int                         ntag;
75     ACMDRIVERDETAILSW           add;
76     ACMFORMATTAGDETAILSW        aftd;
77
78     if (acmDriverOpen(&had, (HACMDRIVERID)padid, 0) != 0)
79         return FALSE;
80
81     padid->aFormatTag = NULL;
82     add.cbStruct = sizeof(add);
83     if (MSACM_Message(had, ACMDM_DRIVER_DETAILS, (LPARAM)&add,  0))
84         goto errCleanUp;
85
86     if (add.cFormatTags > 0) {
87         padid->aFormatTag = HeapAlloc(MSACM_hHeap, HEAP_ZERO_MEMORY, 
88                                       add.cFormatTags * sizeof(padid->aFormatTag[0]));
89         if (!padid->aFormatTag) goto errCleanUp;
90     }
91
92     padid->cFormatTags = add.cFormatTags;
93     padid->cFilterTags = add.cFilterTags;
94     padid->fdwSupport  = add.fdwSupport;
95
96     aftd.cbStruct = sizeof(aftd);
97  
98     for (ntag = 0; ntag < add.cFormatTags; ntag++) {
99         aftd.dwFormatTagIndex = ntag;
100         if (MSACM_Message(had, ACMDM_FORMATTAG_DETAILS, (LPARAM)&aftd, ACM_FORMATTAGDETAILSF_INDEX)) {
101             TRACE("IIOs (%s)\n", padid->pszDriverAlias);
102             goto errCleanUp;
103         }
104         padid->aFormatTag[ntag].dwFormatTag = aftd.dwFormatTag;
105         padid->aFormatTag[ntag].cbwfx = aftd.cbFormatSize;
106     }
107
108     acmDriverClose(had, 0);
109
110     return TRUE;
111
112 errCleanUp:
113     if (had) acmDriverClose(had, 0);
114     HeapFree(MSACM_hHeap, 0, padid->aFormatTag);
115     padid->aFormatTag = NULL;
116     return FALSE;
117 }
118
119 /***********************************************************************
120  *           MSACM_GetRegistryKey
121  */
122 static  LPSTR   MSACM_GetRegistryKey(const WINE_ACMDRIVERID* padid)
123 {
124     static const char*  baseKey = "Software\\Microsoft\\AudioCompressionManager\\DriverCache\\";
125     LPSTR       ret;
126     int         len;
127
128     if (!padid->pszDriverAlias) {
129         ERR("No alias needed for registry entry\n");
130         return NULL;
131     }
132     len = strlen(baseKey);
133     ret = HeapAlloc(MSACM_hHeap, 0, len + strlen(padid->pszDriverAlias) + 1);
134     if (!ret) return NULL;
135
136     strcpy(ret, baseKey);
137     strcpy(ret + len, padid->pszDriverAlias);
138     CharLowerA(ret + len);
139     return ret;
140 }
141
142 /***********************************************************************
143  *           MSACM_ReadCache
144  */
145 static BOOL MSACM_ReadCache(PWINE_ACMDRIVERID padid)
146 {
147     LPSTR       key = MSACM_GetRegistryKey(padid);
148     HKEY        hKey;
149     DWORD       type, size;
150
151     if (!key) return FALSE;
152
153     padid->aFormatTag = NULL;
154
155     if (RegCreateKeyA(HKEY_LOCAL_MACHINE, key, &hKey))
156         goto errCleanUp;
157
158     size = sizeof(padid->cFormatTags);
159     if (RegQueryValueExA(hKey, "cFormatTags", 0, &type, (void*)&padid->cFormatTags, &size))
160         goto errCleanUp;
161     size = sizeof(padid->cFilterTags);
162     if (RegQueryValueExA(hKey, "cFilterTags", 0, &type, (void*)&padid->cFilterTags, &size))
163         goto errCleanUp;
164     size = sizeof(padid->fdwSupport);
165     if (RegQueryValueExA(hKey, "fdwSupport", 0, &type, (void*)&padid->fdwSupport, &size))
166         goto errCleanUp;
167
168     if (padid->cFormatTags > 0) {
169         size = padid->cFormatTags * sizeof(padid->aFormatTag[0]);
170         padid->aFormatTag = HeapAlloc(MSACM_hHeap, HEAP_ZERO_MEMORY, size);
171         if (!padid->aFormatTag) goto errCleanUp;
172         if (RegQueryValueExA(hKey, "aFormatTagCache", 0, &type, (void*)padid->aFormatTag, &size))
173             goto errCleanUp;
174     }
175     HeapFree(MSACM_hHeap, 0, key);
176     return TRUE;
177
178  errCleanUp:
179     HeapFree(MSACM_hHeap, 0, key);
180     HeapFree(MSACM_hHeap, 0, padid->aFormatTag);
181     padid->aFormatTag = NULL;
182     RegCloseKey(hKey);
183     return FALSE;
184 }
185
186 /***********************************************************************
187  *           MSACM_WriteCache
188  */
189 static  BOOL MSACM_WriteCache(PWINE_ACMDRIVERID padid)
190 {
191     LPSTR       key = MSACM_GetRegistryKey(padid);
192     HKEY        hKey;
193
194     if (!key) return FALSE;
195
196     if (RegCreateKeyA(HKEY_LOCAL_MACHINE, key, &hKey))
197         goto errCleanUp;
198
199     if (RegSetValueExA(hKey, "cFormatTags", 0, REG_DWORD, (void*)&padid->cFormatTags, sizeof(DWORD)))
200         goto errCleanUp;
201     if (RegSetValueExA(hKey, "cFilterTags", 0, REG_DWORD, (void*)&padid->cFilterTags, sizeof(DWORD)))
202         goto errCleanUp;
203     if (RegSetValueExA(hKey, "fdwSupport", 0, REG_DWORD, (void*)&padid->fdwSupport, sizeof(DWORD)))
204         goto errCleanUp;
205     if (RegSetValueExA(hKey, "aFormatTagCache", 0, REG_BINARY, 
206                        (void*)padid->aFormatTag, 
207                        padid->cFormatTags * sizeof(padid->aFormatTag[0])))
208         goto errCleanUp;
209     HeapFree(MSACM_hHeap, 0, key);
210     return TRUE;
211
212  errCleanUp:
213     HeapFree(MSACM_hHeap, 0, key);
214     return FALSE;
215 }
216
217 /***********************************************************************
218  *           MSACM_RegisterDriver() 
219  */
220 PWINE_ACMDRIVERID MSACM_RegisterDriver(LPSTR pszDriverAlias, LPSTR pszFileName,
221                                        HINSTANCE hinstModule)
222
223     PWINE_ACMDRIVERID   padid;
224
225     TRACE("('%s', '%s', 0x%08x)\n", pszDriverAlias, pszFileName, hinstModule);
226
227     padid = (PWINE_ACMDRIVERID) HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVERID));
228     padid->obj.dwType = WINE_ACMOBJ_DRIVERID;
229     padid->obj.pACMDriverID = padid;
230     padid->pszDriverAlias = NULL;
231     if (pszDriverAlias)
232     {
233         padid->pszDriverAlias = HeapAlloc( MSACM_hHeap, 0, strlen(pszDriverAlias)+1 );
234         strcpy( padid->pszDriverAlias, pszDriverAlias );
235     }
236     padid->pszFileName = NULL;
237     if (pszFileName)
238     {
239         padid->pszFileName = HeapAlloc( MSACM_hHeap, 0, strlen(pszFileName)+1 );
240         strcpy( padid->pszFileName, pszFileName );
241     }
242     padid->hInstModule = hinstModule;
243         
244     padid->pACMDriverList = NULL;
245     padid->pNextACMDriverID = NULL;
246     padid->pPrevACMDriverID = MSACM_pLastACMDriverID;
247     if (MSACM_pLastACMDriverID)
248         MSACM_pLastACMDriverID->pNextACMDriverID = padid;
249     MSACM_pLastACMDriverID = padid;
250     if (!MSACM_pFirstACMDriverID)
251         MSACM_pFirstACMDriverID = padid;
252     /* disable the driver if we cannot load the cache */
253     if (!MSACM_ReadCache(padid) && !MSACM_FillCache(padid)) {
254         WARN("Couldn't load cache for ACM driver (%s)\n", pszFileName);
255         MSACM_UnregisterDriver(padid);
256         return NULL;
257     }
258     return padid;
259 }
260
261 /***********************************************************************
262  *           MSACM_RegisterAllDrivers() 
263  */
264 void MSACM_RegisterAllDrivers(void)
265 {
266     LPSTR pszBuffer;
267     DWORD dwBufferLength;
268
269     /* FIXME 
270      *  What if the user edits system.ini while the program is running?
271      *  Does Windows handle that?
272      */
273     if (MSACM_pFirstACMDriverID)
274         return;
275     
276     /* FIXME: Does not work! How do I determine the section length? */
277     dwBufferLength = 1024;
278 /* EPP  GetPrivateProfileSectionA("drivers32", NULL, 0, "system.ini"); */
279     
280     pszBuffer = (LPSTR) HeapAlloc(MSACM_hHeap, 0, dwBufferLength);
281     if (GetPrivateProfileSectionA("drivers32", pszBuffer, dwBufferLength, "system.ini")) {
282         char* s = pszBuffer;
283         while (*s) {
284             if (!strncasecmp("MSACM.", s, 6)) {
285                 char *s2 = s;
286                 while (*s2 != '\0' && *s2 != '=') s2++;
287                 if (*s2) {
288                     *s2 = '\0';
289                     MSACM_RegisterDriver(s, s2 + 1, 0);
290                     *s2 = '=';
291                 }
292             }  
293             s += strlen(s) + 1; /* Either next char or \0 */
294         }
295     }
296     
297     HeapFree(MSACM_hHeap, 0, pszBuffer);
298
299     MSACM_RegisterDriver("msacm32.dll", "msacm32.dll", 0);
300 }
301
302 /***********************************************************************
303  *           MSACM_UnregisterDriver()
304  */
305 PWINE_ACMDRIVERID MSACM_UnregisterDriver(PWINE_ACMDRIVERID p)
306 {
307     PWINE_ACMDRIVERID pNextACMDriverID;
308     
309     while (p->pACMDriverList)
310         acmDriverClose((HACMDRIVER) p->pACMDriverList, 0);
311     
312     if (p->pszDriverAlias)
313         HeapFree(MSACM_hHeap, 0, p->pszDriverAlias);
314     if (p->pszFileName)
315         HeapFree(MSACM_hHeap, 0, p->pszFileName);
316     HeapFree(MSACM_hHeap, 0, p->aFormatTag);
317
318     if (p == MSACM_pFirstACMDriverID)
319         MSACM_pFirstACMDriverID = p->pNextACMDriverID;
320     if (p == MSACM_pLastACMDriverID)
321         MSACM_pLastACMDriverID = p->pPrevACMDriverID;
322
323     if (p->pPrevACMDriverID)
324         p->pPrevACMDriverID->pNextACMDriverID = p->pNextACMDriverID;
325     if (p->pNextACMDriverID)
326         p->pNextACMDriverID->pPrevACMDriverID = p->pPrevACMDriverID;
327     
328     pNextACMDriverID = p->pNextACMDriverID;
329     
330     HeapFree(MSACM_hHeap, 0, p);
331     
332     return pNextACMDriverID;
333 }
334
335 /***********************************************************************
336  *           MSACM_UnregisterAllDrivers()
337  */
338 void MSACM_UnregisterAllDrivers(void)
339 {
340     PWINE_ACMDRIVERID p = MSACM_pFirstACMDriverID; 
341
342     while (p) {
343         MSACM_WriteCache(p);
344         p = MSACM_UnregisterDriver(p);
345     }
346 }
347
348 /***********************************************************************
349  *           MSACM_GetObj()
350  */
351 PWINE_ACMOBJ MSACM_GetObj(HACMOBJ hObj, DWORD type)
352 {
353     PWINE_ACMOBJ        pao = (PWINE_ACMOBJ)hObj;
354
355     if (pao == NULL || IsBadReadPtr(pao, sizeof(WINE_ACMOBJ)) ||
356         ((type != WINE_ACMOBJ_DONTCARE) && (type != pao->dwType)))
357         return NULL;
358     return pao;
359 }
360
361 /***********************************************************************
362  *           MSACM_GetDriverID() 
363  */
364 PWINE_ACMDRIVERID MSACM_GetDriverID(HACMDRIVERID hDriverID)
365 {
366     return (PWINE_ACMDRIVERID)MSACM_GetObj((HACMOBJ)hDriverID, WINE_ACMOBJ_DRIVERID);
367 }
368
369 /***********************************************************************
370  *           MSACM_GetDriver()
371  */
372 PWINE_ACMDRIVER MSACM_GetDriver(HACMDRIVER hDriver)
373 {
374     return (PWINE_ACMDRIVER)MSACM_GetObj((HACMOBJ)hDriver, WINE_ACMOBJ_DRIVER);
375 }
376
377 /***********************************************************************
378  *           MSACM_Message()
379  */
380 MMRESULT MSACM_Message(HACMDRIVER had, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
381 {
382     PWINE_ACMDRIVER     pad = MSACM_GetDriver(had);
383
384     return pad ? SendDriverMessage(pad->hDrvr, uMsg, lParam1, lParam2) : MMSYSERR_INVALHANDLE;
385 }