Added CMEM_SETITEM32A and message forwarding to combobox.
[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 "windows.h"
16 #include "gdi.h"
17 #include "global.h"
18 #include "heap.h"
19 #include "neexe.h"
20 #include "task.h"
21 #include "process.h"
22 #include "module.h"
23 #include "resource.h"
24 #include "debug.h"
25 #include "libres.h"
26 #include "winerror.h"
27 #include "debugstr.h"
28
29 extern WORD WINE_LanguageId;
30
31
32 /**********************************************************************
33  *          FindResource32A    (KERNEL32.128)
34  */
35 HANDLE32 WINAPI FindResource32A( HMODULE32 hModule, LPCSTR name, LPCSTR type)
36 {
37     return FindResourceEx32A(hModule,type,name,WINE_LanguageId);
38 }
39
40 /**********************************************************************
41  *          FindResourceEx32A    (KERNEL32.129)
42  */
43 HANDLE32 WINAPI FindResourceEx32A( HMODULE32 hModule, LPCSTR type, LPCSTR name,
44                                    WORD lang
45 ) {
46     LPWSTR xname,xtype;
47     HANDLE32 ret;
48
49     if (HIWORD((DWORD)name))
50         xname = HEAP_strdupAtoW( GetProcessHeap(), 0, name );
51     else
52         xname = (LPWSTR)name;
53     if (HIWORD((DWORD)type))
54         xtype = HEAP_strdupAtoW( GetProcessHeap(), 0, type);
55     else
56         xtype = (LPWSTR)type;
57     ret = FindResourceEx32W( hModule, xtype, xname, lang );
58     if (HIWORD((DWORD)name)) HeapFree( GetProcessHeap(), 0, xname );
59     if (HIWORD((DWORD)type)) HeapFree( GetProcessHeap(), 0, xtype );
60     return ret;
61 }
62
63
64 /**********************************************************************
65  *          FindResourceEx32W    (KERNEL32.130)
66  */
67 HRSRC32 WINAPI FindResourceEx32W( HMODULE32 hModule, LPCWSTR type,
68                                   LPCWSTR name, WORD lang )
69 {
70     WINE_MODREF *wm = MODULE32_LookupHMODULE(PROCESS_Current(),hModule);
71     HRSRC32     hrsrc;
72
73     TRACE(resource, "module=%08x(%s) type=%s name=%s\n",
74           hModule, wm->modname,
75           debugres_w (type),
76           debugres_w (name));
77
78     if (!wm) return (HRSRC32)0;
79
80     switch (wm->type) 
81     {
82     case MODULE32_PE:
83         hrsrc = PE_FindResourceEx32W(wm,name,type,lang);
84         break;
85
86     case MODULE32_ELF:
87         hrsrc = LIBRES_FindResource( hModule, name, type );
88         break;
89         
90     default:
91         ERR(module,"unknown module type %d\n",wm->type);
92         return (HRSRC32)0;
93     }
94
95     if ( !hrsrc )
96         ERR(resource,"0x%08x(%s) %s(%s) not found!\n", hModule,wm->modname, debugres_w (name), debugres_w (type));
97
98     return hrsrc;
99 }
100
101
102 /**********************************************************************
103  *          FindResource32W    (KERNEL32.131)
104  */
105 HRSRC32 WINAPI FindResource32W(HINSTANCE32 hModule, LPCWSTR name, LPCWSTR type)
106 {
107     return FindResourceEx32W(hModule,type,name,WINE_LanguageId);
108 }
109
110
111 /**********************************************************************
112  *          LoadResource32    (KERNEL32.370)
113  * 'loads' a resource. The current implementation just returns a pointer
114  * into the already mapped image.
115  * RETURNS
116  *      pointer into the mapped resource of the passed module
117  */
118 HGLOBAL32 WINAPI LoadResource32( 
119         HINSTANCE32 hModule,    /* [in] module handle */
120         HRSRC32 hRsrc )         /* [in] resource handle */
121 {
122     WINE_MODREF *wm = MODULE32_LookupHMODULE(PROCESS_Current(),hModule);
123
124     TRACE(resource, "module=%04x res=%04x\n",
125                      hModule, hRsrc );
126     if (!hRsrc) {
127         ERR(resource,"hRsrc is 0, return 0.\n");
128         return 0;
129     }
130     if (!wm) return 0;
131
132     switch (wm->type) 
133     {
134     case MODULE32_PE:
135         return PE_LoadResource32(wm,hRsrc);
136
137     case MODULE32_ELF:
138         return LIBRES_LoadResource( hModule, hRsrc );
139
140     default:
141         ERR(resource,"unknown module type %d\n",wm->type);
142         break;
143     }
144     return 0;
145 }
146
147
148 /**********************************************************************
149  *          LockResource32    (KERNEL32.384)
150  */
151 LPVOID WINAPI LockResource32( HGLOBAL32 handle )
152 {
153     return (LPVOID)handle;
154 }
155
156
157 /**********************************************************************
158  *          FreeResource32    (KERNEL32.145)
159  */
160 BOOL32 WINAPI FreeResource32( HGLOBAL32 handle )
161 {
162     /* no longer used in Win32 */
163     return TRUE;
164 }
165
166
167 /**********************************************************************
168  *          AccessResource32    (KERNEL32.64)
169  */
170 INT32 WINAPI AccessResource32( HMODULE32 hModule, HRSRC32 hRsrc )
171 {
172     FIXME(resource,"(module=%08x res=%08x),not implemented\n", hModule, hRsrc);
173     return 0;
174 }
175
176
177 /**********************************************************************
178  *          SizeofResource32    (KERNEL32.522)
179  */
180 DWORD WINAPI SizeofResource32( HINSTANCE32 hModule, HRSRC32 hRsrc )
181 {
182     WINE_MODREF *wm = MODULE32_LookupHMODULE(PROCESS_Current(),hModule);
183
184     TRACE(resource, "module=%08x res=%08x\n", hModule, hRsrc );
185     if (!wm) return 0;
186
187     switch (wm->type)
188     {
189     case MODULE32_PE:
190         return PE_SizeofResource32(hModule,hRsrc);
191
192     case MODULE32_ELF:
193         FIXME(module,"Not implemented for ELF modules\n");
194         break;
195
196     default:
197         ERR(module,"unknown module type %d\n",wm->type);
198         break;
199     }
200     return 0;
201 }
202
203
204 /**********************************************************************
205  *                      LoadAccelerators16      [USER.177]
206  */
207 HACCEL16 WINAPI LoadAccelerators16(HINSTANCE16 instance, SEGPTR lpTableName)
208 {
209     HRSRC16     hRsrc;
210
211     if (HIWORD(lpTableName))
212         TRACE(accel, "%04x '%s'\n",
213                       instance, (char *)PTR_SEG_TO_LIN( lpTableName ) );
214     else
215         TRACE(accel, "%04x %04x\n",
216                        instance, LOWORD(lpTableName) );
217
218     if (!(hRsrc = FindResource16( instance, lpTableName, RT_ACCELERATOR16 ))) {
219       WARN(accel, "couldn't find accelerator table resource\n");
220       return 0;
221     }
222
223     TRACE(accel, "returning HACCEL 0x%x\n", hRsrc);
224     return LoadResource16(instance,hRsrc);
225 }
226
227 /**********************************************************************
228  *                      LoadAccelerators32W     [USER.177]
229  * The image layout seems to look like this (not 100% sure):
230  * 00:  BYTE    type            type of accelerator
231  * 01:  BYTE    pad             (to WORD boundary)
232  * 02:  WORD    event
233  * 04:  WORD    IDval           
234  * 06:  WORD    pad             (to DWORD boundary)
235  */
236 HACCEL32 WINAPI LoadAccelerators32W(HINSTANCE32 instance,LPCWSTR lpTableName)
237 {
238     HRSRC32 hRsrc;
239     HACCEL32 hRetval;
240     DWORD size;
241
242     if (HIWORD(lpTableName))
243         TRACE(accel, "%p '%s'\n",
244                       (LPVOID)instance, (char *)( lpTableName ) );
245     else
246         TRACE(accel, "%p 0x%04x\n",
247                        (LPVOID)instance, LOWORD(lpTableName) );
248
249     if (!(hRsrc = FindResource32W( instance, lpTableName, RT_ACCELERATOR32W )))
250     {
251       WARN(accel, "couldn't find accelerator table resource\n");
252       hRetval = 0;
253     }
254     else {
255       hRetval = LoadResource32( instance, hRsrc );
256       size = SizeofResource32( instance, hRsrc );
257       if(size>=sizeof(ACCEL32))
258       {
259         LPACCEL32 accel_table = (LPACCEL32) hRetval;
260         /* mark last element as such - sometimes it is not marked in image */
261         accel_table[size/sizeof(ACCEL32)-1].fVirt |= 0x80;
262       }
263     }
264
265     TRACE(accel, "returning HACCEL 0x%x\n", hRsrc);
266     return hRetval;
267 }
268
269 HACCEL32 WINAPI LoadAccelerators32A(HINSTANCE32 instance,LPCSTR lpTableName)
270 {
271         LPWSTR   uni;
272         HACCEL32 result;
273         if (HIWORD(lpTableName))
274                 uni = HEAP_strdupAtoW( GetProcessHeap(), 0, lpTableName );
275         else
276                 uni = (LPWSTR)lpTableName;
277         result = LoadAccelerators32W(instance,uni);
278         if (HIWORD(uni)) HeapFree( GetProcessHeap(), 0, uni);
279         return result;
280 }
281
282 /**********************************************************************
283  *             CopyAcceleratorTable32A   (USER32.58)
284  */
285 INT32 WINAPI CopyAcceleratorTable32A(HACCEL32 src, LPACCEL32 dst, INT32 entries)
286 {
287   return CopyAcceleratorTable32W(src, dst, entries);
288 }
289
290 /**********************************************************************
291  *             CopyAcceleratorTable32W   (USER32.59)
292  *
293  * By mortene@pvv.org 980321
294  */
295 INT32 WINAPI CopyAcceleratorTable32W(HACCEL32 src, LPACCEL32 dst,
296                                      INT32 entries)
297 {
298   int i;
299   LPACCEL32 accel = (LPACCEL32)src;
300   BOOL32 done = FALSE;
301
302   /* Do parameter checking to avoid the explosions and the screaming
303      as far as possible. */
304   if((dst && (entries < 1)) || (src == (HACCEL32)NULL)) {
305     WARN(accel, "Application sent invalid parameters (%p %p %d).\n",
306          (LPVOID)src, (LPVOID)dst, entries);
307     return 0;
308   }
309
310
311   i=0;
312   while(!done) {
313     /* Spit out some debugging information. */
314     TRACE(accel, "accel %d: type 0x%02x, event '%c', IDval 0x%04x.\n",
315           i, accel[i].fVirt, accel[i].key, accel[i].cmd);
316
317     /* Copy data to the destination structure array (if dst == NULL,
318        we're just supposed to count the number of entries). */
319     if(dst) {
320       memcpy(&dst[i], &accel[i], sizeof(ACCEL32));
321
322       /* Check if we've reached the end of the application supplied
323          accelerator table. */
324       if(i+1 == entries) {
325         /* Turn off the high order bit, just in case. */
326         dst[i].fVirt &= 0x7f;
327         done = TRUE;
328       }
329     }
330
331     /* The highest order bit seems to mark the end of the accelerator
332        resource table. (?) */
333     if((accel[i].fVirt & 0x80) != 0) done = TRUE;
334
335     i++;
336   }
337
338   return i;
339 }
340
341 /*********************************************************************
342  *                    CreateAcceleratorTable   (USER32.64)
343  *
344  * By mortene@pvv.org 980321
345  */
346 HACCEL32 WINAPI CreateAcceleratorTable32A(LPACCEL32 lpaccel, INT32 cEntries)
347 {
348   HACCEL32 hAccel;
349
350   /* Do parameter checking just in case someone's trying to be
351      funny. */
352   if(cEntries < 1) {
353     WARN(accel, "Application sent invalid parameters (%p %d).\n",
354          lpaccel, cEntries);
355     SetLastError(ERROR_INVALID_PARAMETER);
356     return (HACCEL32)NULL;
357   }
358   FIXME(accel, "should check that the accelerator descriptions are valid,"
359         " return NULL and SetLastError() if not.\n");
360
361
362   /* Allocate memory and copy the table. */
363   hAccel = (HACCEL32)HeapAlloc(GetProcessHeap(), 0,
364                                cEntries * sizeof(ACCEL32));
365   TRACE(accel, "handle %p\n", (LPVOID)hAccel);
366   if(!hAccel) {
367     ERR(accel, "Out of memory.\n");
368     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
369     return (HACCEL32)NULL;
370   }
371   memcpy((LPACCEL32)hAccel, lpaccel, cEntries * sizeof(ACCEL32));
372
373   /* Set the end-of-table terminator. */
374   ((LPACCEL32)hAccel)[cEntries-1].fVirt |= 0x80;
375
376   TRACE(accel, "Allocated accelerator handle %x\n", hAccel);
377   return hAccel;
378 }
379
380
381 /******************************************************************************
382  * DestroyAcceleratorTable [USER32.130]
383  * Destroys an accelerator table
384  *
385  * NOTES
386  *    By mortene@pvv.org 980321
387  *
388  * PARAMS
389  *    handle [I] Handle to accelerator table
390  *
391  * RETURNS STD
392  */
393 BOOL32 WINAPI DestroyAcceleratorTable( HACCEL32 handle )
394 {
395     FIXME(accel, "(0x%x): stub\n", handle);
396
397
398   /* Weird.. I thought this should work. According to the API
399      specification, DestroyAcceleratorTable() should only be called on
400      HACCEL32's made by CreateAcceleratorTable(), but Microsoft Visual
401      Studio 97 calls this function with a series of different handle
402      values without ever calling CreateAcceleratorTable(). Something
403      is very fishy in Denmark... */
404   /* Update: looks like the calls to this function matches the calls
405      to LoadAccelerators() in M$ Visual Studio, except that the handle
406      values are off by some variable size from the HACCEL's returned
407      from LoadAccelerators(). WTH? */
408   
409   /* Parameter checking to avoid any embarassing situations. */
410 #if 0
411      if(!handle) {
412        WARN(accel, "Application sent NULL ptr.\n");
413        SetLastError(ERROR_INVALID_PARAMETER);
414        return FALSE;
415      }
416   
417      HeapFree(GetProcessHeap(), 0, (LPACCEL32)handle);
418 #endif
419
420   return TRUE;
421 }
422   
423 /**********************************************************************
424  *                                      LoadString16
425  */
426 INT16 WINAPI LoadString16( HINSTANCE16 instance, UINT16 resource_id,
427                            LPSTR buffer, INT16 buflen )
428 {
429     HGLOBAL16 hmem;
430     HRSRC16 hrsrc;
431     unsigned char *p;
432     int string_num;
433     int i;
434
435     TRACE(resource,"inst=%04x id=%04x buff=%08x len=%d\n",
436                      instance, resource_id, (int) buffer, buflen);
437
438     hrsrc = FindResource16( instance, (SEGPTR)((resource_id>>4)+1), RT_STRING16 );
439     if (!hrsrc) return 0;
440     hmem = LoadResource16( instance, hrsrc );
441     if (!hmem) return 0;
442     
443     p = LockResource16(hmem);
444     string_num = resource_id & 0x000f;
445     for (i = 0; i < string_num; i++)
446         p += *p + 1;
447     
448     TRACE(resource, "strlen = %d\n", (int)*p );
449     
450     i = MIN(buflen - 1, *p);
451     if (buffer == NULL)
452         return i;
453     if (i > 0) {
454         memcpy(buffer, p + 1, i);
455         buffer[i] = '\0';
456     } else {
457         if (buflen > 1) {
458             buffer[0] = '\0';
459             return 0;
460         }
461         WARN(resource,"Dont know why caller give buflen=%d *p=%d trying to obtain string '%s'\n", buflen, *p, p + 1);
462     }
463     FreeResource16( hmem );
464
465     TRACE(resource,"'%s' loaded !\n", buffer);
466     return i;
467 }
468
469 /**********************************************************************
470  *      LoadString32W           (USER32.376)
471  */
472 INT32 WINAPI LoadString32W( HINSTANCE32 instance, UINT32 resource_id,
473                             LPWSTR buffer, INT32 buflen )
474 {
475     HGLOBAL32 hmem;
476     HRSRC32 hrsrc;
477     WCHAR *p;
478     int string_num;
479     int i;
480
481     if (HIWORD(resource_id)==0xFFFF) /* netscape 3 passes this */
482         resource_id = (UINT32)(-((INT32)resource_id));
483     TRACE(resource, "instance = %04x, id = %04x, buffer = %08x, "
484            "length = %d\n", instance, (int)resource_id, (int) buffer, buflen);
485
486     hrsrc = FindResource32W( instance, (LPCWSTR)((resource_id>>4)+1),
487                              RT_STRING32W );
488     if (!hrsrc) return 0;
489     hmem = LoadResource32( instance, hrsrc );
490     if (!hmem) return 0;
491     
492     p = LockResource32(hmem);
493     string_num = resource_id & 0x000f;
494     for (i = 0; i < string_num; i++)
495         p += *p + 1;
496     
497     TRACE(resource, "strlen = %d\n", (int)*p );
498     
499     i = MIN(buflen - 1, *p);
500     if (buffer == NULL)
501         return i;
502     if (i > 0) {
503         memcpy(buffer, p + 1, i * sizeof (WCHAR));
504         buffer[i] = (WCHAR) 0;
505     } else {
506         if (buflen > 1) {
507             buffer[0] = (WCHAR) 0;
508             return 0;
509         }
510 #if 0
511         WARN(resource,"Dont know why caller give buflen=%d *p=%d trying to obtain string '%s'\n", buflen, *p, p + 1);
512 #endif
513     }
514
515     TRACE(resource,"%s loaded !\n", debugstr_w(buffer));
516     return i;
517 }
518
519 /**********************************************************************
520  *      LoadString32A   (USER32.375)
521  */
522 INT32 WINAPI LoadString32A( HINSTANCE32 instance, UINT32 resource_id,
523                             LPSTR buffer, INT32 buflen )
524 {
525     INT32 retval;
526     LPWSTR buffer2 = NULL;
527     if (buffer && buflen)
528         buffer2 = HeapAlloc( GetProcessHeap(), 0, buflen * 2 );
529     retval = LoadString32W(instance,resource_id,buffer2,buflen);
530
531     if (buffer2)
532     {
533         if (retval) {
534             lstrcpynWtoA( buffer, buffer2, buflen );
535             retval = lstrlen32A( buffer );
536         }
537         else
538             *buffer = 0;
539         HeapFree( GetProcessHeap(), 0, buffer2 );
540     }
541     return retval;
542 }
543
544 /* Messages...used by FormatMessage32* (KERNEL32.something)
545  * 
546  * They can be specified either directly or using a message ID and
547  * loading them from the resource.
548  * 
549  * The resourcedata has following format:
550  * start:
551  * 0: DWORD nrofentries
552  * nrofentries * subentry:
553  *      0: DWORD firstentry
554  *      4: DWORD lastentry
555  *      8: DWORD offset from start to the stringentries
556  *
557  * (lastentry-firstentry) * stringentry:
558  * 0: WORD len (0 marks end)
559  * 2: WORD unknown (flags?)
560  * 4: CHAR[len-4]
561  *      (stringentry i of a subentry refers to the ID 'firstentry+i')
562  *
563  * Yes, ANSI strings in win32 resources. Go figure.
564  */
565
566 /**********************************************************************
567  *      LoadMessage32A          (internal)
568  */
569 INT32 WINAPI LoadMessage32A( HMODULE32 instance, UINT32 id, WORD lang,
570                       LPSTR buffer, INT32 buflen )
571 {
572     HGLOBAL32   hmem;
573     HRSRC32     hrsrc;
574     BYTE        *p;
575     int         nrofentries,i,slen;
576     struct      _subentry {
577         DWORD   firstentry;
578         DWORD   lastentry;
579         DWORD   offset;
580     } *se;
581     struct      _stringentry {
582         WORD    len;
583         WORD    unknown;
584         CHAR    str[1];
585     } *stre;
586
587     TRACE(resource, "instance = %08lx, id = %08lx, buffer = %p, length = %ld\n", (DWORD)instance, (DWORD)id, buffer, (DWORD)buflen);
588
589     /*FIXME: I am not sure about the '1' ... But I've only seen those entries*/
590     hrsrc = FindResourceEx32W(instance,RT_MESSAGELIST32W,(LPWSTR)1,lang);
591     if (!hrsrc) return 0;
592     hmem = LoadResource32( instance, hrsrc );
593     if (!hmem) return 0;
594     
595     p = LockResource32(hmem);
596     nrofentries = *(DWORD*)p;
597     stre = NULL;
598     se = (struct _subentry*)(p+4);
599     for (i=nrofentries;i--;) {
600         if ((id>=se->firstentry) && (id<=se->lastentry)) {
601             stre = (struct _stringentry*)(p+se->offset);
602             id  -= se->firstentry;
603             break;
604         }
605         se++;
606     }
607     if (!stre)
608         return 0;
609     for (i=id;i--;) {
610         if (!(slen=stre->len))
611                 return 0;
612         stre = (struct _stringentry*)(((char*)stre)+slen);
613     }
614     slen=stre->len;
615     TRACE(resource,"    - strlen=%d\n",slen);
616     i = MIN(buflen - 1, slen);
617     if (buffer == NULL)
618         return slen; /* different to LoadString */
619     if (i>0) {
620         lstrcpyn32A(buffer,stre->str,i);
621         buffer[i]=0;
622     } else {
623         if (buflen>1) {
624             buffer[0]=0;
625             return 0;
626         }
627     }
628     if (buffer)
629             TRACE(resource,"'%s' copied !\n", buffer);
630     return i;
631 }
632
633 /**********************************************************************
634  *      LoadMessage32W  (internal)
635  */
636 INT32 WINAPI LoadMessage32W( HMODULE32 instance, UINT32 id, WORD lang,
637                       LPWSTR buffer, INT32 buflen )
638 {
639     INT32 retval;
640     LPSTR buffer2 = NULL;
641     if (buffer && buflen)
642         buffer2 = HeapAlloc( GetProcessHeap(), 0, buflen );
643     retval = LoadMessage32A(instance,id,lang,buffer2,buflen);
644     if (buffer)
645     {
646         if (retval) {
647             lstrcpynAtoW( buffer, buffer2, buflen );
648             retval = lstrlen32W( buffer );
649         }
650         HeapFree( GetProcessHeap(), 0, buffer2 );
651     }
652     return retval;
653 }
654
655
656 /**********************************************************************
657  *      EnumResourceTypesA      (KERNEL32.90)
658  */
659 BOOL32 WINAPI EnumResourceTypes32A( HMODULE32 hmodule,ENUMRESTYPEPROC32A lpfun,
660                                     LONG lParam)
661 {
662         /* FIXME: move WINE_MODREF stuff here */
663     return PE_EnumResourceTypes32A(hmodule,lpfun,lParam);
664 }
665
666 /**********************************************************************
667  *      EnumResourceTypesW      (KERNEL32.91)
668  */
669 BOOL32 WINAPI EnumResourceTypes32W( HMODULE32 hmodule,ENUMRESTYPEPROC32W lpfun,
670                                     LONG lParam)
671 {
672         /* FIXME: move WINE_MODREF stuff here */
673     return PE_EnumResourceTypes32W(hmodule,lpfun,lParam);
674 }
675
676 /**********************************************************************
677  *      EnumResourceNamesA      (KERNEL32.88)
678  */
679 BOOL32 WINAPI EnumResourceNames32A( HMODULE32 hmodule, LPCSTR type,
680                                     ENUMRESNAMEPROC32A lpfun, LONG lParam )
681 {
682         /* FIXME: move WINE_MODREF stuff here */
683     return PE_EnumResourceNames32A(hmodule,type,lpfun,lParam);
684 }
685 /**********************************************************************
686  *      EnumResourceNamesW      (KERNEL32.89)
687  */
688 BOOL32 WINAPI EnumResourceNames32W( HMODULE32 hmodule, LPCWSTR type,
689                                     ENUMRESNAMEPROC32W lpfun, LONG lParam )
690 {
691         /* FIXME: move WINE_MODREF stuff here */
692     return PE_EnumResourceNames32W(hmodule,type,lpfun,lParam);
693 }
694
695 /**********************************************************************
696  *      EnumResourceLanguagesA  (KERNEL32.86)
697  */
698 BOOL32 WINAPI EnumResourceLanguages32A( HMODULE32 hmodule, LPCSTR type,
699                                         LPCSTR name, ENUMRESLANGPROC32A lpfun,
700                                         LONG lParam)
701 {
702         /* FIXME: move WINE_MODREF stuff here */
703     return PE_EnumResourceLanguages32A(hmodule,type,name,lpfun,lParam);
704 }
705 /**********************************************************************
706  *      EnumResourceLanguagesW  (KERNEL32.87)
707  */
708 BOOL32 WINAPI EnumResourceLanguages32W( HMODULE32 hmodule, LPCWSTR type,
709                                         LPCWSTR name, ENUMRESLANGPROC32W lpfun,
710                                         LONG lParam)
711 {
712         /* FIXME: move WINE_MODREF stuff here */
713     return PE_EnumResourceLanguages32W(hmodule,type,name,lpfun,lParam);
714 }