Fixed Win16 documentation not fixed because of a bug in winapi_check.
[wine] / loader / resource.c
1 /*
2  * Resources
3  *
4  * Copyright 1993 Robert J. Amstadt
5  * Copyright 1995 Alexandre Julliard
6  */
7
8 #include <assert.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <unistd.h>
15 #include "windef.h"
16 #include "winbase.h"
17 #include "wine/winbase16.h"
18 #include "wine/exception.h"
19 #include "ldt.h"
20 #include "global.h"
21 #include "heap.h"
22 #include "callback.h"
23 #include "cursoricon.h"
24 #include "task.h"
25 #include "process.h"
26 #include "module.h"
27 #include "file.h"
28 #include "debugtools.h"
29 #include "winerror.h"
30 #include "winnls.h"
31
32 DEFAULT_DEBUG_CHANNEL(resource);
33
34 #define HRSRC_MAP_BLOCKSIZE 16
35
36 typedef struct _HRSRC_ELEM
37 {
38     HANDLE hRsrc;
39     WORD     type;
40 } HRSRC_ELEM;
41
42 typedef struct _HRSRC_MAP
43 {
44     int nAlloc;
45     int nUsed;
46     HRSRC_ELEM *elem;
47 } HRSRC_MAP;
48
49 /**********************************************************************
50  *          MapHRsrc32To16
51  */
52 static HRSRC16 MapHRsrc32To16( NE_MODULE *pModule, HANDLE hRsrc32, WORD type )
53 {
54     HRSRC_MAP *map = (HRSRC_MAP *)pModule->hRsrcMap;
55     HRSRC_ELEM *newElem;
56     int i;
57
58     /* On first call, initialize HRSRC map */
59     if ( !map )
60     {
61         if ( !(map = (HRSRC_MAP *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 
62                                              sizeof(HRSRC_MAP) ) ) )
63         {
64             ERR("Cannot allocate HRSRC map\n" );
65             return 0;
66         }
67         pModule->hRsrcMap = (LPVOID)map;
68     }
69
70     /* Check whether HRSRC32 already in map */
71     for ( i = 0; i < map->nUsed; i++ )
72         if ( map->elem[i].hRsrc == hRsrc32 )
73             return (HRSRC16)(i + 1);
74
75     /* If no space left, grow table */
76     if ( map->nUsed == map->nAlloc )
77     {
78         if ( !(newElem = (HRSRC_ELEM *)HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 
79                                                     map->elem, 
80                                                     (map->nAlloc + HRSRC_MAP_BLOCKSIZE) 
81                                                     * sizeof(HRSRC_ELEM) ) ))
82         {
83             ERR("Cannot grow HRSRC map\n" );
84             return 0;
85         }
86         map->elem = newElem;
87         map->nAlloc += HRSRC_MAP_BLOCKSIZE;
88     }
89
90     /* Add HRSRC32 to table */
91     map->elem[map->nUsed].hRsrc = hRsrc32;
92     map->elem[map->nUsed].type  = type;
93     map->nUsed++;
94
95     return (HRSRC16)map->nUsed;
96 }
97
98 /**********************************************************************
99  *          MapHRsrc16To32
100  */
101 static HANDLE MapHRsrc16To32( NE_MODULE *pModule, HRSRC16 hRsrc16 )
102 {
103     HRSRC_MAP *map = (HRSRC_MAP *)pModule->hRsrcMap;
104     if ( !map || !hRsrc16 || (int)hRsrc16 > map->nUsed ) return 0;
105
106     return map->elem[(int)hRsrc16-1].hRsrc;
107 }
108
109 /**********************************************************************
110  *          MapHRsrc16ToType
111  */
112 static WORD MapHRsrc16ToType( NE_MODULE *pModule, HRSRC16 hRsrc16 )
113 {
114     HRSRC_MAP *map = (HRSRC_MAP *)pModule->hRsrcMap;
115     if ( !map || !hRsrc16 || (int)hRsrc16 > map->nUsed ) return 0;
116
117     return map->elem[(int)hRsrc16-1].type;
118 }
119
120
121 /* filter for page-fault exceptions */
122 static WINE_EXCEPTION_FILTER(page_fault)
123 {
124     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
125         return EXCEPTION_EXECUTE_HANDLER;
126     return EXCEPTION_CONTINUE_SEARCH;
127 }
128
129 static HRSRC RES_FindResource2( HMODULE hModule, LPCSTR type,
130                                 LPCSTR name, WORD lang, 
131                                 BOOL bUnicode, BOOL bRet16 )
132 {
133     HRSRC hRsrc = 0;
134     
135     TRACE("(%08x, %08x%s, %08x%s, %04x, %s, %s)\n",
136           hModule,
137           (UINT)type, HIWORD(type)? (bUnicode? debugstr_w((LPWSTR)type) : debugstr_a(type)) : "",
138           (UINT)name, HIWORD(name)? (bUnicode? debugstr_w((LPWSTR)name) : debugstr_a(name)) : "",
139           lang,
140           bUnicode? "W"  : "A",
141           bRet16?   "NE" : "PE" );
142
143     if (!HIWORD(hModule))
144     {
145         HMODULE16 hMod16   = MapHModuleLS( hModule );
146         NE_MODULE *pModule = NE_GetPtr( hMod16 );
147         if (!pModule) return 0;
148         if (!pModule->module32)
149         {
150             /* 16-bit NE module */
151             LPSTR typeStr, nameStr;
152             
153             if ( HIWORD( type ) && bUnicode )
154                 typeStr = HEAP_strdupWtoA( GetProcessHeap(), 0, (LPCWSTR)type );
155             else
156                 typeStr = (LPSTR)type;
157             if ( HIWORD( name ) && bUnicode )
158                 nameStr = HEAP_strdupWtoA( GetProcessHeap(), 0, (LPCWSTR)name );
159             else
160                 nameStr = (LPSTR)name;
161             
162             hRsrc = NE_FindResource( pModule, nameStr, typeStr );
163             
164             if ( HIWORD( type ) && bUnicode ) 
165                 HeapFree( GetProcessHeap(), 0, typeStr );
166             if ( HIWORD( name ) && bUnicode ) 
167                 HeapFree( GetProcessHeap(), 0, nameStr );
168             
169             /* If we need to return 32-bit HRSRC, no conversion is necessary,
170                we simply use the 16-bit HRSRC as 32-bit HRSRC */
171         }
172         else
173         {
174             /* 32-bit PE module */
175             hRsrc = RES_FindResource2( pModule->module32, type, name, lang, bUnicode, FALSE );
176             /* If we need to return 16-bit HRSRC, perform conversion */
177             if ( bRet16 )
178                 hRsrc = MapHRsrc32To16( pModule, hRsrc, 
179                                         HIWORD( type )? 0 : LOWORD( type ) );
180         }
181     }
182     else
183     {
184         /* 32-bit PE module */
185         LPWSTR typeStr, nameStr;
186             
187         if ( HIWORD( type ) && !bUnicode )
188             typeStr = HEAP_strdupAtoW( GetProcessHeap(), 0, type );
189         else
190             typeStr = (LPWSTR)type;
191         if ( HIWORD( name ) && !bUnicode )
192             nameStr = HEAP_strdupAtoW( GetProcessHeap(), 0, name );
193         else
194             nameStr = (LPWSTR)name;
195
196         /* Here is the real difference between FindResouce and FindResourceEx */
197         if(lang == MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) ||
198                 lang == MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) ||
199                 lang == MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT) ||
200                 lang == MAKELANGID(LANG_NEUTRAL, 3)) /* FIXME: real name? */
201             hRsrc = PE_FindResourceW( hModule, nameStr, typeStr );
202         else
203             hRsrc = PE_FindResourceExW( hModule, nameStr, typeStr, lang );
204             
205         if ( HIWORD( type ) && !bUnicode ) 
206             HeapFree( GetProcessHeap(), 0, typeStr );
207         if ( HIWORD( name ) && !bUnicode ) 
208             HeapFree( GetProcessHeap(), 0, nameStr );
209     }
210     return hRsrc;
211 }
212
213 /**********************************************************************
214  *          RES_FindResource
215  */
216
217 static HRSRC RES_FindResource( HMODULE hModule, LPCSTR type,
218                                LPCSTR name, WORD lang, 
219                                BOOL bUnicode, BOOL bRet16 )
220 {
221     HRSRC hRsrc;
222     __TRY
223     {
224         hRsrc = RES_FindResource2(hModule, type, name, lang, bUnicode, bRet16);
225     }
226     __EXCEPT(page_fault)
227     {
228         WARN("page fault\n");
229         SetLastError(ERROR_INVALID_PARAMETER);
230         return 0;
231     }
232     __ENDTRY
233     return hRsrc;
234 }
235
236 /**********************************************************************
237  *          RES_SizeofResource
238  */
239 static DWORD RES_SizeofResource( HMODULE hModule, HRSRC hRsrc, BOOL bRet16 )
240 {
241     if (!hRsrc) return 0;
242
243     TRACE("(%08x, %08x, %s)\n", hModule, hRsrc, bRet16? "NE" : "PE" );
244
245     if (!HIWORD(hModule))
246     {
247         HMODULE16 hMod16   = MapHModuleLS( hModule );
248         NE_MODULE *pModule = NE_GetPtr( hMod16 );
249         if (!pModule) return 0;
250
251         if (!pModule->module32)  /* 16-bit NE module */
252         {
253             /* If we got a 32-bit hRsrc, we don't need to convert it */
254             return NE_SizeofResource( pModule, hRsrc );
255         }
256
257         /* If we got a 16-bit hRsrc, convert it */
258         if (!HIWORD(hRsrc)) hRsrc = MapHRsrc16To32( pModule, hRsrc );
259     }
260
261     /* 32-bit PE module */
262     return PE_SizeofResource( hRsrc );
263 }
264
265 /**********************************************************************
266  *          RES_LoadResource
267  */
268 static HGLOBAL RES_LoadResource( HMODULE hModule, HRSRC hRsrc, BOOL bRet16 )
269 {
270     HGLOBAL hMem = 0;
271
272     TRACE("(%08x, %08x, %s)\n", hModule, hRsrc, bRet16? "NE" : "PE" );
273
274     if (!hRsrc) return 0;
275
276     if (!HIWORD(hModule))
277     {
278         HMODULE16 hMod16   = MapHModuleLS( hModule );
279         NE_MODULE *pModule = NE_GetPtr( hMod16 );
280         if (!pModule) return 0;
281         if (!pModule->module32)
282         {
283             /* 16-bit NE module */
284
285             /* If we got a 32-bit hRsrc, we don't need to convert it */
286             hMem = NE_LoadResource( pModule, hRsrc );
287
288             /* If we are to return a 32-bit resource, we should probably
289                convert it but we don't for now.  FIXME !!! */
290             return hMem;
291         }
292         else
293         {
294             /* If we got a 16-bit hRsrc, convert it */
295             HRSRC hRsrc32 = HIWORD(hRsrc)? hRsrc : MapHRsrc16To32( pModule, hRsrc );
296
297             hMem = PE_LoadResource( pModule->module32, hRsrc32 );
298
299             /* If we need to return a 16-bit resource, convert it */
300             if ( bRet16 )
301             {
302                 WORD type   = MapHRsrc16ToType( pModule, hRsrc );
303                 DWORD size  = SizeofResource( hModule, hRsrc );
304                 LPVOID bits = LockResource( hMem );
305
306                 hMem = NE_LoadPEResource( pModule, type, bits, size );
307             }
308         }
309     }
310     else
311     {
312         /* 32-bit PE module */
313         hMem = PE_LoadResource( hModule, hRsrc );
314     }
315
316     return hMem;
317 }
318
319 /**********************************************************************
320  *          FindResource16   (KERNEL.60)
321  */
322 HRSRC16 WINAPI FindResource16( HMODULE16 hModule, LPCSTR name, LPCSTR type )
323 {
324     return RES_FindResource( hModule, type, name,
325                     MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), FALSE, TRUE );
326 }
327
328 /**********************************************************************
329  *          FindResourceA    (KERNEL32.128)
330  */
331 HANDLE WINAPI FindResourceA( HMODULE hModule, LPCSTR name, LPCSTR type )
332 {
333     return RES_FindResource( hModule, type, name, 
334                     MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), FALSE, FALSE );
335 }
336
337 /**********************************************************************
338  *          FindResourceExA  (KERNEL32.129)
339  */
340 HANDLE WINAPI FindResourceExA( HMODULE hModule, 
341                                LPCSTR type, LPCSTR name, WORD lang )
342 {
343     return RES_FindResource( hModule, type, name, 
344                              lang, FALSE, FALSE );
345 }
346
347 /**********************************************************************
348  *          FindResourceExW  (KERNEL32.130)
349  */
350 HRSRC WINAPI FindResourceExW( HMODULE hModule, 
351                               LPCWSTR type, LPCWSTR name, WORD lang )
352 {
353     return RES_FindResource( hModule, (LPCSTR)type, (LPCSTR)name, 
354                              lang, TRUE, FALSE );
355 }
356
357 /**********************************************************************
358  *          FindResourceW    (KERNEL32.131)
359  */
360 HRSRC WINAPI FindResourceW(HINSTANCE hModule, LPCWSTR name, LPCWSTR type)
361 {
362     return RES_FindResource( hModule, (LPCSTR)type, (LPCSTR)name, 
363                     MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), TRUE, FALSE );
364 }
365
366 /**********************************************************************
367  *          LoadResource16   (KERNEL.61)
368  */
369 HGLOBAL16 WINAPI LoadResource16( HMODULE16 hModule, HRSRC16 hRsrc )
370 {
371     return RES_LoadResource( hModule, hRsrc, TRUE );
372 }
373
374 /**********************************************************************
375  *          LoadResource     (KERNEL32.370)
376  */
377 HGLOBAL WINAPI LoadResource( HINSTANCE hModule, HRSRC hRsrc )
378 {
379     return RES_LoadResource( hModule, hRsrc, FALSE );
380 }
381
382 /**********************************************************************
383  *          LockResource16   (KERNEL.62)
384  */
385 SEGPTR WINAPI WIN16_LockResource16( HGLOBAL16 handle )
386 {
387     TRACE("(%04x)\n", handle );
388     /* May need to reload the resource if discarded */
389     return WIN16_GlobalLock16( handle );
390 }
391 LPVOID WINAPI LockResource16( HGLOBAL16 handle )
392 {
393     return PTR_SEG_TO_LIN( WIN16_LockResource16(handle) );
394 }
395
396 /**********************************************************************
397  *          LockResource     (KERNEL32.384)
398  */
399 LPVOID WINAPI LockResource( HGLOBAL handle )
400 {
401     TRACE("(%08x)\n", handle );
402
403     if (HIWORD( handle ))  /* 32-bit memory handle */
404         return (LPVOID)handle;
405
406     /* 16-bit memory handle */
407     return LockResource16( handle );
408 }
409
410 /**********************************************************************
411  *          FreeResource16   (KERNEL.63)
412  */
413 BOOL16 WINAPI FreeResource16( HGLOBAL16 handle )
414 {
415     HGLOBAL retv = handle;
416     NE_MODULE *pModule = NE_GetPtr( FarGetOwner16( handle ) );
417
418     TRACE("(%04x)\n", handle );
419
420     /* Try NE resource first */
421     retv = NE_FreeResource( pModule, handle );
422
423     /* If this failed, call USER.DestroyIcon32; this will check
424        whether it is a shared cursor/icon; if not it will call
425        GlobalFree16() */
426     if ( retv )
427     {
428         if ( Callout.DestroyIcon32 )
429             retv = Callout.DestroyIcon32( handle, CID_RESOURCE );
430         else
431             retv = GlobalFree16( handle );
432     }
433     return (BOOL)retv;
434 }
435
436 /**********************************************************************
437  *          FreeResource     (KERNEL32.145)
438  */
439 BOOL WINAPI FreeResource( HGLOBAL handle )
440 {
441     if (HIWORD(handle)) return 0; /* 32-bit memory handle: nothing to do */
442
443     return FreeResource16( handle );
444 }
445
446 /**********************************************************************
447  *          SizeofResource16 (KERNEL.65)
448  */
449 DWORD WINAPI SizeofResource16( HMODULE16 hModule, HRSRC16 hRsrc )
450 {
451     return RES_SizeofResource( hModule, hRsrc, TRUE );
452 }
453
454 /**********************************************************************
455  *          SizeofResource   (KERNEL32.522)
456  */
457 DWORD WINAPI SizeofResource( HINSTANCE hModule, HRSRC hRsrc )
458 {
459     return RES_SizeofResource( hModule, hRsrc, FALSE );
460 }