Release 940706
[wine] / loader / wine.c
1 static char RCSId[] = "$Id: wine.c,v 1.2 1993/07/04 04:04:21 root Exp root $";
2 static char Copyright[] = "Copyright  Robert J. Amstadt, 1993";
3
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <fcntl.h>
9 #include <unistd.h>
10 #ifdef linux
11 #include <linux/unistd.h>
12 #include <linux/head.h>
13 #include <linux/ldt.h>
14 #include <linux/segment.h>
15 #endif
16 #include <string.h>
17 #include <errno.h>
18 #include "neexe.h"
19 #include "segmem.h"
20 #include "prototypes.h"
21 #include "dlls.h"
22 #include "wine.h"
23 #include "windows.h"
24 #include "wineopts.h"
25 #include "arch.h"
26 #include "options.h"
27
28 /* #define DEBUG_FIXUP */
29
30 extern int CallToInit16(unsigned long csip, unsigned long sssp, 
31                         unsigned short ds);
32 extern void CallTo32();
33
34 char * GetModuleName(struct w_files * wpnt, int index, char *buffer);
35 extern unsigned char ran_out;
36 extern char WindowsPath[256];
37 char *WIN_ProgramName;
38
39 unsigned short WIN_StackSize;
40 unsigned short WIN_HeapSize;
41
42 struct  w_files * wine_files = NULL;
43
44 int WineForceFail = 0;
45
46 char **Argv;
47 int Argc;
48 struct mz_header_s *CurrentMZHeader;
49 struct ne_header_s *CurrentNEHeader;
50 int CurrentNEFile;
51 HINSTANCE hSysRes;
52
53 static char *DLL_Extensions[] = { "dll", "exe", NULL };
54 static char *EXE_Extensions[] = { "exe", NULL };
55 static char *WinePath = NULL;
56
57 FILE *SpyFp = NULL;
58
59 /**********************************************************************
60  *                                      myerror
61  */
62 void
63 myerror(const char *s)
64 {
65     if (s == NULL)
66         perror("wine");
67     else
68         fprintf(stderr, "wine: %s\n", s);
69
70     exit(1);
71 }
72 \f
73 /**********************************************************************
74  *                                      GetFilenameFromInstance
75  */
76 char *
77 GetFilenameFromInstance(unsigned short instance)
78 {
79     register struct w_files *w = wine_files;
80
81     while (w && w->hinstance != instance)
82         w = w->next;
83     
84     if (w)
85         return w->filename;
86     else
87         return NULL;
88 }
89
90 struct w_files *
91 GetFileInfo(unsigned short instance)
92 {
93     register struct w_files *w = wine_files;
94
95     while (w && w->hinstance != instance)
96         w = w->next;
97     
98     return w;
99 }
100 \f
101 #ifndef WINELIB
102 /**********************************************************************
103  *
104  * Load MZ Header
105  */
106 void load_mz_header(int fd, struct mz_header_s *mz_header)
107 {
108     if (read(fd, mz_header, sizeof(struct mz_header_s)) !=
109         sizeof(struct mz_header_s))
110     {
111         myerror("Unable to read MZ header from file");
112     }
113 }
114
115 void load_ne_header (int fd, struct ne_header_s *ne_header)
116 {
117     if (read(fd, ne_header, sizeof(struct ne_header_s)) 
118         != sizeof(struct ne_header_s))
119     {
120         myerror("Unable to read NE header from file");
121     }
122 }
123 #endif
124
125 /**********************************************************************
126  *                                      LoadImage
127  * Load one NE format executable into memory
128  */
129 HINSTANCE LoadImage(char *modulename, int filetype, int change_dir)
130 {
131     unsigned int read_size;
132     int i;
133     struct w_files * wpnt, *wpnt1;
134     unsigned int status;
135     char buffer[256];
136     char *fullname;
137
138     /*
139      * search file
140      */
141     fullname = FindFile(buffer, sizeof(buffer), modulename, 
142                         (filetype == EXE ? EXE_Extensions : DLL_Extensions), 
143                         WindowsPath);
144     if (fullname == NULL)
145     {
146         fprintf(stderr, "LoadImage: I can't find %s.dll | %s.exe !\n",
147                 modulename, modulename);
148         return (HINSTANCE) NULL;
149     }
150
151     fullname = GetDosFileName(fullname);
152     WIN_ProgramName = strdup(fullname);
153     
154     fprintf(stderr,"LoadImage: loading %s (%s)\n           [%s]\n", 
155             modulename, buffer, WIN_ProgramName);
156
157     if (change_dir && fullname)
158     {
159         char dirname[256];
160         char *p;
161
162         strcpy(dirname, fullname);
163         p = strrchr(dirname, '\\');
164         *p = '\0';
165
166         DOS_SetDefaultDrive(dirname[0] - 'A');
167         DOS_ChangeDir(dirname[0] - 'A', dirname + 2);
168     }
169
170     /* First allocate a spot to store the info we collect, and add it to
171      * our linked list.
172      */
173
174     wpnt = (struct w_files *) malloc(sizeof(struct w_files));
175     if(wine_files == NULL)
176       wine_files = wpnt;
177     else {
178       wpnt1 = wine_files;
179       while(wpnt1->next) wpnt1 =  wpnt1->next;
180       wpnt1->next  = wpnt;
181     };
182     wpnt->next = NULL;
183
184     /*
185      * Open file for reading.
186      */
187     wpnt->fd = open(buffer, O_RDONLY);
188     if (wpnt->fd < 0)
189     {
190         myerror(NULL);
191     }
192     /*
193      * Establish header pointers.
194      */
195     wpnt->filename = strdup(buffer);
196     wpnt->name = NULL;
197     if(modulename)  wpnt->name = strdup(modulename);
198
199     wpnt->mz_header = (struct mz_header_s *) malloc(sizeof(struct mz_header_s));;
200     status = lseek(wpnt->fd, 0, SEEK_SET);
201     load_mz_header (wpnt->fd, wpnt->mz_header);
202     if (wpnt->mz_header->must_be_0x40 != 0x40)
203         myerror("This is not a Windows program");
204     
205     wpnt->ne_header = (struct ne_header_s *) malloc(sizeof(struct ne_header_s));
206     status = lseek(wpnt->fd, wpnt->mz_header->ne_offset, SEEK_SET);
207     load_ne_header (wpnt->fd, wpnt->ne_header);
208     if (wpnt->ne_header->header_type[0] != 'N' || 
209         wpnt->ne_header->header_type[1] != 'E')
210       myerror("This is not a Windows program");
211
212     if(wine_files ==  wpnt){
213       CurrentMZHeader = wpnt->mz_header;
214       CurrentNEHeader = wpnt->ne_header;
215       CurrentNEFile   = wpnt->fd;
216       
217       WIN_StackSize = wpnt->ne_header->stack_length;
218       WIN_HeapSize = wpnt->ne_header->local_heap_length;
219     };
220
221     /*
222      * Create segment selectors.
223      */
224 #ifndef WINELIB
225     status = lseek(wpnt->fd, wpnt->mz_header->ne_offset + 
226                    wpnt->ne_header->segment_tab_offset,
227                    SEEK_SET);
228     read_size  = wpnt->ne_header->n_segment_tab *
229                  sizeof(struct ne_segment_table_entry_s);
230     wpnt->seg_table = (struct ne_segment_table_entry_s *) malloc(read_size);
231     if (read(wpnt->fd, wpnt->seg_table, read_size) != read_size)
232         myerror("Unable to read segment table header from file");
233     wpnt->selector_table = CreateSelectors(wpnt);
234     wpnt->hinstance 
235         = wpnt->
236             selector_table[wpnt->ne_header->auto_data_seg-1].selector;
237
238     /* Get the lookup  table.  This is used for looking up the addresses
239        of functions that are exported */
240
241     read_size  = wpnt->ne_header->entry_tab_length;
242     wpnt->lookup_table = (char *) malloc(read_size);
243     lseek(wpnt->fd, wpnt->mz_header->ne_offset + 
244           wpnt->ne_header->entry_tab_offset, SEEK_SET);
245     if (read(wpnt->fd, wpnt->lookup_table, read_size) != read_size)
246         myerror("Unable to read lookup table header from file");
247
248     /* Get the iname table.  This is used for looking up the names
249        of functions that are exported */
250
251     status = lseek(wpnt->fd, wpnt->ne_header->nrname_tab_offset,  SEEK_SET);
252     read_size  = wpnt->ne_header->nrname_tab_length;
253     wpnt->nrname_table = (char *) malloc(read_size);
254     if (read(wpnt->fd, wpnt->nrname_table, read_size) != read_size)
255         myerror("Unable to read nrname table header from file");
256
257     status = lseek(wpnt->fd, wpnt->mz_header->ne_offset + 
258                    wpnt->ne_header->rname_tab_offset,  SEEK_SET);
259     read_size  = wpnt->ne_header->moduleref_tab_offset - 
260             wpnt->ne_header->rname_tab_offset;
261     wpnt->rname_table = (char *) malloc(read_size);
262     if (read(wpnt->fd, wpnt->rname_table, read_size) != read_size)
263         myerror("Unable to read rname table header from file");
264
265     /* Now get the module name */
266
267     wpnt->name  = (char*) malloc(*wpnt->rname_table + 1);
268     memcpy(wpnt->name, wpnt->rname_table+1, *wpnt->rname_table);
269     wpnt->name[*wpnt->rname_table] =  0;
270 #endif
271     /*
272      * Now load any DLLs that  this module refers to.
273      */
274     for(i=0; i<wpnt->ne_header->n_mod_ref_tab; i++){
275       char buff[14];
276       char buff2[256];
277       int  fd, j;
278       GetModuleName(wpnt, i + 1, buff);
279       
280 #ifndef WINELIB
281       if(FindDLLTable(buff)) continue;  /* This module already loaded */
282 #endif
283
284       LoadImage(buff, DLL, 0);
285 /*
286       fprintf(stderr,"Unable to load:%s\n",  buff);
287 */
288     }
289 return(wpnt->hinstance);
290 }
291 \f
292
293 /**********************************************************************
294  *                                      main
295  */
296 _WinMain(int argc, char **argv)
297 {
298         int segment;
299         char *p;
300         char *sysresname;
301         char filename[100];
302         char syspath[256];
303         char exe_path[256];
304 #ifdef WINESTAT
305         char * cp;
306 #endif
307         struct w_files * wpnt;
308         int cs_reg, ds_reg, ss_reg, ip_reg, sp_reg;
309         int i;
310         int rv;
311
312         Argc = argc - 1;
313         Argv = argv + 1;
314         
315         WinePath = malloc(1024);
316         
317         getcwd(WinePath, 512);
318         
319         if ((p = getenv("WINEPATH")) != NULL) { 
320                 strcat(WinePath, ";");
321                 strcat(WinePath, p);
322         }
323         
324         if ((hInstMain = LoadImage(Argv[0], EXE, 1)) == (HINSTANCE) NULL ) {
325                 fprintf(stderr, "wine: can't find %s!.\n", Argv[0]);
326                 exit(1);
327         }
328
329         GetPrivateProfileString("wine", "SystemResources", "sysres.dll", 
330                                 filename, sizeof(filename), WINE_INI);
331
332         hSysRes = LoadImage(filename, DLL);
333         if (hSysRes == (HINSTANCE)NULL)
334                 fprintf(stderr, "wine: can't find %s!\n", filename);
335         else
336             printf("System Resources Loaded // hSysRes='%04X'\n", hSysRes);
337         
338     /*
339      * Fixup references.
340      */
341     wpnt = wine_files;
342     for(wpnt = wine_files; wpnt; wpnt = wpnt->next)
343     {
344         for (segment = 0; segment < wpnt->ne_header->n_segment_tab; segment++)
345         {
346             if (FixupSegment(wpnt, segment) < 0)
347             {
348                 myerror("fixup failed.");
349             }
350         }
351     }
352
353 #ifdef WINESTAT
354     cp = strrchr(argv[0], '/');
355     if(!cp) cp = argv[0];
356         else cp++;
357     if(strcmp(cp,"winestat") == 0) {
358             winestat();
359             exit(0);
360     };
361 #endif
362
363     /*
364      * Initialize signal handling.
365      */
366     init_wine_signals();
367
368     /*
369      * Fixup stack and jump to start.
370      */
371     ds_reg = (wine_files->
372               selector_table[wine_files->ne_header->auto_data_seg-1].selector);
373     cs_reg = wine_files->selector_table[wine_files->ne_header->cs-1].selector;
374     ip_reg = wine_files->ne_header->ip;
375     ss_reg = wine_files->selector_table[wine_files->ne_header->ss-1].selector;
376     sp_reg = wine_files->ne_header->sp;
377
378     if (Options.debug) wine_debug(0, NULL);
379
380     rv = CallToInit16(cs_reg << 16 | ip_reg, ss_reg << 16 | sp_reg, ds_reg);
381     printf ("rv = %x\n", rv);
382 }
383
384 void InitializeLoadedDLLs()
385 {
386     struct w_files * wpnt;
387     int cs_reg, ds_reg, ip_reg;
388     int rv;
389
390     fprintf(stderr, "Initializing DLLs\n");
391
392     /*
393      * Initialize libraries
394      */
395     wpnt = wine_files;
396     for(wpnt = wine_files; wpnt; wpnt = wpnt->next)
397     {
398         /* 
399          * Is this a library? 
400          */
401         if (wpnt->ne_header->format_flags & 0x8000)
402         {
403             if (!(wpnt->ne_header->format_flags & 0x0001))
404             {
405                 /* Not SINGLEDATA */
406                 fprintf(stderr, "Library is not marked SINGLEDATA\n");
407                 exit(1);
408             }
409
410             ds_reg = wpnt->selector_table[wpnt->
411                                           ne_header->auto_data_seg-1].selector;
412             cs_reg = wpnt->selector_table[wpnt->ne_header->cs-1].selector;
413             ip_reg = wpnt->ne_header->ip;
414
415             fprintf(stderr, "Initializing %s, cs:ip %04x:%04x, ds %04x\n", 
416                     wpnt->name, cs_reg, ip_reg, ds_reg);
417
418             rv = CallTo16(cs_reg << 16 | ip_reg, ds_reg);
419             printf ("rv = %x\n", rv);
420         }
421     }
422 }
423
424 \f
425 /**********************************************************************
426  *                                      GetImportedName
427  */
428 char *
429 GetImportedName(int fd, struct mz_header_s *mz_header, 
430                 struct ne_header_s *ne_header, int name_offset, char *buffer)
431 {
432     char *p;
433     int length;
434     int status;
435     int i;
436     
437     status = lseek(fd, mz_header->ne_offset + ne_header->iname_tab_offset +
438                    name_offset, SEEK_SET);
439     length = 0;
440     read(fd, &length, 1);  /* Get the length byte */
441     length = CONV_CHAR_TO_LONG (length);
442     read(fd, buffer, length);
443     buffer[length] = 0;
444     return buffer;
445 }
446
447 /**********************************************************************
448  *                                      GetModuleName
449  */
450 char *
451 GetModuleName(struct w_files * wpnt, int index, char *buffer)
452 {
453     int fd = wpnt->fd;
454     struct mz_header_s *mz_header = wpnt->mz_header; 
455     struct ne_header_s *ne_header = wpnt->ne_header;
456     char *p;
457     int length;
458     WORD name_offset, status;
459     int i;
460     
461     status = lseek(fd, mz_header->ne_offset + ne_header->moduleref_tab_offset +
462                    2*(index - 1), SEEK_SET);
463     name_offset = 0;
464     read(fd, &name_offset, 2);
465     name_offset = CONV_SHORT (name_offset);
466     status = lseek(fd, mz_header->ne_offset + ne_header->iname_tab_offset +
467                    name_offset, SEEK_SET);
468     length = 0;
469     read(fd, &length, 1);  /* Get the length byte */
470     length = CONV_CHAR_TO_LONG (length);
471     read(fd, buffer, length);
472     buffer[length] = 0;
473
474     /* Module names  are always upper case */
475     for(i=0; i<length; i++)
476             if(buffer[i] >= 'a' && buffer[i] <= 'z')  buffer[i] &= ~0x20;
477
478     return buffer;
479 }
480
481 \f
482 #ifndef WINELIB
483 /**********************************************************************
484  *                                      FixupSegment
485  */
486 int
487 FixupSegment(struct w_files * wpnt, int segment_num)
488 {
489     int fd =  wpnt->fd;
490     struct mz_header_s * mz_header = wpnt->mz_header;
491     struct ne_header_s *ne_header =  wpnt->ne_header;
492     struct ne_segment_table_entry_s *seg_table = wpnt->seg_table;
493     struct segment_descriptor_s *selector_table = wpnt->selector_table;
494     struct relocation_entry_s *rep, *rep1;
495     struct ne_segment_table_entry_s *seg;
496     struct segment_descriptor_s *sel;
497     struct dll_table_entry_s *dll_table;
498     int status;
499     unsigned short *sp;
500     unsigned int selector, address;
501     unsigned int next_addr;
502     int ordinal;
503     char dll_name[257];
504     char func_name[257];
505     int i, n_entries;
506     int additive;
507
508     seg = &seg_table[segment_num];
509     sel = &selector_table[segment_num];
510
511 #ifdef DEBUG_FIXUP
512     printf("Segment fixups for %s, segment %d, selector %x\n", 
513            wpnt->name, segment_num, (int) sel->base_addr >> 16);
514 #endif
515
516     if ((seg->seg_data_offset == 0) ||
517         !(seg->seg_flags & NE_SEGFLAGS_RELOC_DATA))
518         return 0;
519
520     /*
521      * Go through the relocation table on entry at a time.
522      */
523     i = seg->seg_data_length;
524     if (i == 0)
525         i = 0x10000;
526
527     status = lseek(fd, seg->seg_data_offset * 
528                        (1 << ne_header->align_shift_count) + i, SEEK_SET);
529     n_entries = 0;
530     read(fd, &n_entries, sizeof(short int));
531     rep = (struct relocation_entry_s *)
532           malloc(n_entries * sizeof(struct relocation_entry_s));
533
534     if (read(fd,rep, n_entries * sizeof(struct relocation_entry_s)) !=
535         n_entries * sizeof(struct relocation_entry_s))
536     {
537         myerror("Unable to read relocation information");
538     }
539     
540     rep1 = rep;
541
542     for (i = 0; i < n_entries; i++, rep++)
543     {
544         /*
545          * Get the target address corresponding to this entry.
546          */
547         additive = 0;
548         
549         switch (rep->relocation_type)
550         {
551           case NE_RELTYPE_ORDINALADD:
552             additive = 1;
553             
554           case NE_RELTYPE_ORDINAL:
555             if (GetModuleName(wpnt, rep->target1,
556                               dll_name) == NULL)
557             {
558               fprintf(stderr, "NE_RELTYPE_ORDINAL failed");
559                 return -1;
560             }
561             
562             ordinal = rep->target2;
563
564             status = GetEntryDLLOrdinal(dll_name, ordinal, &selector,
565                                         &address);
566             if (status)
567             {
568                 char s[80];
569                 
570                 sprintf(s, "Bad DLL name '%s.%d'", dll_name, ordinal);
571                 myerror(s);
572                 return -1;
573             }
574
575 #ifdef DEBUG_FIXUP
576             printf("%d: %s.%d: %04.4x:%04.4x\n", i + 1, dll_name, ordinal,
577                    selector, address);
578 #endif
579             break;
580             
581           case NE_RELTYPE_NAMEADD:
582             additive = 1;
583             
584           case NE_RELTYPE_NAME:
585             if (GetModuleName(wpnt, rep->target1, dll_name)
586                 == NULL)
587             {
588               fprintf(stderr,"NE_RELTYPE_NAME failed");
589                 return -1;
590             }
591
592             if (GetImportedName(fd, mz_header, ne_header, 
593                                 rep->target2, func_name) == NULL)
594             {
595               fprintf(stderr,"getimportedname failed");
596                 return -1;
597             }
598
599             status = GetEntryDLLName(dll_name, func_name, &selector, 
600                                            &address);
601             if (status)
602             {
603                 char s[80];
604                 
605                 sprintf(s, "Bad DLL name '%s (%s)'", dll_name,func_name);
606                 myerror(s);
607                 return -1;
608             }
609
610 #ifdef DEBUG_FIXUP
611             printf("%d: %s %s.%d: %04.4x:%04.4x\n", i + 1, func_name,
612                    dll_name, ordinal, selector, address);
613 #endif
614             break;
615             
616           case NE_RELTYPE_INTERNAL:
617           case NE_RELTYPE_INT1:
618             if (rep->target1 == 0x00ff)
619             {
620                 address  = GetEntryPointFromOrdinal(wpnt, rep->target2);
621                 selector = (address >> 16) & 0xffff;
622                 address &= 0xffff;
623             }
624             else
625             {
626                 selector = selector_table[rep->target1-1].selector;
627                 address  = rep->target2;
628             }
629             
630 #ifdef DEBUG_FIXUP
631             printf("%d: %04.4x:%04.4x\n", i + 1, selector, address);
632 #endif
633             break;
634
635           case 7:
636             /* Relocation type 7:
637              *
638              *    These appear to be used as fixups for the Windows
639              * floating point emulator.  Let's just ignore them and
640              * try to use the hardware floating point.  Linux should
641              * successfully emulate the coprocessor if it doesn't
642              * exist.
643              */
644 #ifdef DEBUG_FIXUP
645             printf("%d: ADDR TYPE %d,  TYPE %d,  OFFSET %04.4x,  ",
646                    i + 1, rep->address_type, rep->relocation_type, 
647                    rep->offset);
648             printf("TARGET %04.4x %04.4x\n", rep->target1, rep->target2);
649 #endif
650             continue;
651             
652           default:
653             fprintf(stderr,"%d: ADDR TYPE %d,  TYPE %d,  OFFSET %04.4x,  ",
654                    i + 1, rep->address_type, rep->relocation_type, 
655                    rep->offset);
656             fprintf(stderr,"TARGET %04.4x %04.4x\n", 
657                     rep->target1, rep->target2);
658             free(rep1);
659             return -1;
660         }
661
662         /*
663          * Stuff the right size result in.
664          */
665         sp = (unsigned short *) ((char *) sel->base_addr + rep->offset);
666         if (additive)
667         {
668             if (FindDLLTable(dll_name) == NULL)
669                 additive = 2;
670
671             fprintf(stderr,"%d: ADDR TYPE %d,  TYPE %d,  OFFSET %04.4x,  ",
672                    i + 1, rep->address_type, rep->relocation_type, 
673                    rep->offset);
674             fprintf(stderr,"TARGET %04.4x %04.4x\n", 
675                     rep->target1, rep->target2);
676             fprintf(stderr, "    Additive = %d\n", additive);
677         }
678         
679         switch (rep->address_type)
680         {
681           case NE_RADDR_OFFSET16:
682             do {
683 #ifdef DEBUG_FIXUP
684                 printf("    %04.4x:%04.4x:%04.4x OFFSET16\n",
685                        (unsigned long) sp >> 16, (int) sp & 0xFFFF, *sp);
686 #endif
687                 next_addr = *sp;
688                 *sp = (unsigned short) address;
689                 if (additive == 2)
690                     *sp += next_addr;
691                 sp = (unsigned short *) ((char *) sel->base_addr + next_addr);
692             } 
693             while (next_addr != 0xffff && !additive);
694
695             break;
696             
697           case NE_RADDR_POINTER32:
698             do {
699 #ifdef DEBUG_FIXUP
700                 printf("    %04.4x:%04.4x:%04.4x POINTER32\n",
701                        (unsigned long) sp >> 16, (int) sp & 0xFFFF, *sp);
702 #endif
703                 next_addr = *sp;
704                 *sp     = (unsigned short) address;
705                 if (additive == 2)
706                     *sp += next_addr;
707                 *(sp+1) = (unsigned short) selector;
708                 sp = (unsigned short *) ((char *) sel->base_addr + next_addr);
709             } 
710             while (next_addr != 0xffff && !additive);
711
712             break;
713             
714           case NE_RADDR_SELECTOR:
715             do {
716 #ifdef DEBUG_FIXUP
717                 printf("    %04.4x:%04.4x:%04.4x SELECTOR\n",
718                        (unsigned long) sp >> 16, (int) sp & 0xFFFF, *sp);
719 #endif
720                 next_addr = *sp;
721                 *sp     = (unsigned short) selector;
722                 sp = (unsigned short *) ((char *) sel->base_addr + next_addr);
723                 if (rep->relocation_type == NE_RELTYPE_INT1) 
724                     break;
725             } 
726             while (next_addr != 0xffff && !additive);
727
728             break;
729             
730           default:
731             printf("%d: ADDR TYPE %d,  TYPE %d,  OFFSET %04.4x,  ",
732                    i + 1, rep->address_type, rep->relocation_type, 
733                    rep->offset);
734             printf("TARGET %04.4x %04.4x\n", rep->target1, rep->target2);
735             free(rep1);
736             return -1;
737         }
738     }
739
740     free(rep1);
741     return 0;
742 }
743
744 /**********************************************************************
745  *                                      GetProcAddress
746  */
747 FARPROC GetProcAddress(HINSTANCE hinstance, char *proc_name)
748 {
749     if ((int) proc_name & 0xffff0000)
750         printf("GetProcAddress: %#04x, '%s'\n", hinstance, proc_name);
751     else
752         printf("GetProcAddress: %#04x, %d\n", hinstance, (int) proc_name);
753
754     return NULL;
755 }
756 #endif