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