2
* Copyright (c) 1990, 2002 Michael J. Roberts. All Rights Reserved.
4
* Please see the accompanying license file, LICENSE.TXT, for information
5
* on using and copying this software.
9
dosmktrx - DOS TRX builder
11
Combines the generic runtime module (TRX) with a game data file (.GAM) to
12
produce a single file that contains the entire game (code + data).
14
Define MKTRX_SETICON to include icon-setting code. The icon-setting
15
code is applicable only to 32-bit Windows executables (PE format files).
17
11/16/92 MJRoberts - add end signature
18
11/11/91 MJRoberts - creation
34
/* ------------------------------------------------------------------------ */
36
* Icon-setting code for PE (win32 exe) files
43
* Icon resource file format structures
49
/* icon directory entry in ICO file */
52
BYTE bWidth; // Width, in pixels, of the image
53
BYTE bHeight; // Height, in pixels, of the image
54
BYTE bColorCount; // Number of colors in image (0 if >=8bpp)
55
BYTE bReserved; // Reserved ( must be 0)
56
WORD wPlanes; // Color Planes
57
WORD wBitCount; // Bits per pixel
58
DWORD dwBytesInRes; // How many bytes in this resource?
59
DWORD dwImageOffset; // Where in the file is this image?
60
} ICONDIRENTRY, *LPICONDIRENTRY;
62
/* icon directory in ICO file */
65
WORD idReserved; // Reserved (must be 0)
66
WORD idType; // Resource Type (1 for icons)
67
WORD idCount; // How many images?
68
ICONDIRENTRY idEntries[1]; // An entry for each image (idCount of 'em)
69
} ICONDIR, *LPICONDIR;
71
/* group icon directory entry in EXE file */
73
BYTE bWidth; // Width, in pixels, of the image
74
BYTE bHeight; // Height, in pixels, of the image
75
BYTE bColorCount; // Number of colors in image (0 if >=8bpp)
76
BYTE bReserved; // Reserved
77
WORD wPlanes; // Color Planes
78
WORD wBitCount; // Bits per pixel
79
DWORD dwBytesInRes; // how many bytes in this resource?
81
} GRPICONDIRENTRY, *LPGRPICONDIRENTRY;
83
/* group icon directory header in EXE file */
85
WORD idReserved; // Reserved (must be 0)
86
WORD idType; // Resource type (1 for icons)
87
WORD idCount; // How many images?
88
GRPICONDIRENTRY idEntries[1]; // The entries for each image
89
} GRPICONDIR, *LPGRPICONDIR;
94
/* ------------------------------------------------------------------------ */
98
static void errexit(const char *msg)
105
* Resource directory information structure
107
typedef struct res_info_t res_info_t;
110
/* seek address of the resource directory */
113
/* virtual address base of resource data */
118
* Look up the resource directory information. Fills in the res_info
119
* structure with the resource data. Returns zero on success, or a
120
* non-zero error code on failure.
122
static int find_resource_dir(FILE *fp, res_info_t *res_info)
124
IMAGE_DOS_HEADER doshdr;
125
IMAGE_NT_HEADERS nthdr;
130
/* read the old-style DOS header */
131
if (fread(&doshdr, sizeof(doshdr), 1, fp) != 1)
133
if (doshdr.e_magic != IMAGE_DOS_SIGNATURE)
136
/* seek to the PE header and read that */
137
fseek(fp, doshdr.e_lfanew, SEEK_SET);
138
if (fread(&nthdr, sizeof(nthdr), 1, fp) != 1)
140
if (nthdr.Signature != IMAGE_NT_SIGNATURE)
143
/* find the first image section */
144
start = doshdr.e_lfanew
145
+ FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader)
146
+ nthdr.FileHeader.SizeOfOptionalHeader;
147
fseek(fp, start, SEEK_SET);
149
/* read image sections */
150
for (lastsect = 0, cnt = 0 ; cnt < nthdr.FileHeader.NumberOfSections ;
153
IMAGE_SECTION_HEADER imghdr;
155
/* read this section header */
156
if (fread(&imghdr, sizeof(imghdr), 1, fp) != 1)
159
/* if this is the resource section, return it */
160
if (memcmp(imghdr.Name, ".rsrc", IMAGE_SIZEOF_SHORT_NAME) == 0)
162
/* fill in the information */
163
res_info->dir_pos = imghdr.PointerToRawData;
164
res_info->base_addr = imghdr.VirtualAddress;
172
* we went through all the sections and failed to find a resource
173
* section - return an error
179
* Get a file offset and size for a resource, given the resource type
180
* and either the identifier or the index. If 'id_is_index' is true,
181
* the id is the 0-based index; otherwise, it's the ID. Returns zero if
182
* the resource is not found, otherwise returns the seek offset in the
183
* file of the resource's data, and fills in *data_size with the size of
186
static long find_resource(FILE *fp, long *data_size,
187
const res_info_t *res_info,
188
LPSTR res_type, int res_id, int id_is_index)
190
IMAGE_RESOURCE_DIRECTORY dirhdr;
193
IMAGE_RESOURCE_DIRECTORY_ENTRY direntry;
194
IMAGE_RESOURCE_DATA_ENTRY dataentry;
196
/* read the root directory, which contains the type index */
197
fseek(fp, res_info->dir_pos, SEEK_SET);
198
if (fread(&dirhdr, sizeof(dirhdr), 1, fp) != 1)
201
/* find the desired type */
202
for (i = 0, found = FALSE ;
203
i < dirhdr.NumberOfNamedEntries + dirhdr.NumberOfIdEntries ; ++i)
205
/* read the next entry */
206
if (fread(&direntry, sizeof(direntry), 1, fp) != 1)
209
/* check to see if it's the type we want */
210
if (direntry.Id == (WORD)res_type)
217
/* if we didn't find the type we want, give up */
221
/* we found the type index - read its directory header */
222
fseek(fp, res_info->dir_pos + direntry.OffsetToDirectory, SEEK_SET);
223
if (fread(&dirhdr, sizeof(dirhdr), 1, fp) != 1)
226
/* now search the directory for our index or ID */
227
for (i = 0, found = FALSE ;
228
i < dirhdr.NumberOfNamedEntries + dirhdr.NumberOfIdEntries ; ++i)
230
/* read the next entry */
231
if (fread(&direntry, sizeof(direntry), 1, fp) != 1)
234
/* if this is the one we want, return it */
235
if ((id_is_index && res_id == i)
236
|| (!id_is_index && !direntry.NameIsString
237
&& direntry.Id == res_id))
244
/* if we didn't find it, give up */
249
* got it - this entry will point to yet another directory, which
250
* will contain the actual data; seek to the directory and read its
253
fseek(fp, res_info->dir_pos + direntry.OffsetToDirectory, SEEK_SET);
254
if (fread(&dirhdr, sizeof(dirhdr), 1, fp) != 1
255
|| fread(&direntry, sizeof(direntry), 1, fp) != 1)
258
/* seek to and read the first directory entry's data header */
259
fseek(fp, res_info->dir_pos + direntry.OffsetToData, SEEK_SET);
260
if (fread(&dataentry, sizeof(dataentry), 1, fp) != 1)
263
/* set the size from the directory entry */
264
*data_size = dataentry.Size;
267
* compute and return the data address - note that the address is
268
* relative to the resource section's virtual address setting, so we
269
* must adjust the virtual address to determine the seek address in
272
return dataentry.OffsetToData - res_info->base_addr + res_info->dir_pos;
276
* Replace the icon at icon_idx in the EXE file with the icon in the ICO
277
* file. Returns zero on success, non-zero on error.
279
static int replace_icon(FILE *fpexe, int icon_idx, FILE *fpico)
286
GRPICONDIR group_dir;
287
GRPICONDIRENTRY *group_dir_entry = 0;
289
ICONDIRENTRY *icon_dir_entry = 0;
290
ICONDIRENTRY *cur_ico;
292
/* seek to the start of the executable */
293
fseek(fpexe, 0, SEEK_SET);
295
/* read the ICO directory header */
297
sizeof(icon_dir) - sizeof(ICONDIRENTRY), 1, fpico) != 1)
303
/* read the ICO directory entries */
304
icon_dir_entry = (ICONDIRENTRY *)malloc(icon_dir.idCount
305
* sizeof(ICONDIRENTRY));
306
if (icon_dir_entry == 0)
311
if (fread(icon_dir_entry, icon_dir.idCount * sizeof(ICONDIRENTRY),
318
/* find the resource directory in the EXE file */
319
err = find_resource_dir(fpexe, &res_info);
323
/* look up the icon group resource by index */
324
group_pos = find_resource(fpexe, &group_size, &res_info,
325
RT_GROUP_ICON, icon_idx, TRUE);
327
/* seek to and read the group icon directory */
328
fseek(fpexe, group_pos, SEEK_SET);
329
if (fread(&group_dir, sizeof(group_dir) - sizeof(GRPICONDIRENTRY),
336
/* read the group directory entries */
337
group_dir_entry = (GRPICONDIRENTRY *)malloc(group_dir.idCount
338
* sizeof(GRPICONDIRENTRY));
339
if (group_dir_entry == 0)
344
if (fread(group_dir_entry, group_dir.idCount * sizeof(GRPICONDIRENTRY),
352
* go through the image types in the replacement icon file; for each
353
* one, try to find the corresponding entry in the EXE file, and
356
for (i = 0, cur_ico = icon_dir_entry ; i < icon_dir.idCount ;
360
GRPICONDIRENTRY *cur_grp;
363
/* try to find this icon type in the EXE group icon directory */
364
for (found = FALSE, j = 0, cur_grp = group_dir_entry ;
365
j < group_dir.idCount ; ++j, ++cur_grp)
367
/* see if it matches */
368
if (cur_grp->bWidth == cur_ico->bWidth
369
&& cur_grp->bHeight == cur_ico->bHeight
370
&& cur_grp->bColorCount == cur_ico->bColorCount
371
&& cur_grp->dwBytesInRes == cur_ico->dwBytesInRes)
377
/* note that we found it */
380
/* look up this icon entry */
381
icon_pos = find_resource(fpexe, &icon_size, &res_info,
382
RT_ICON, cur_grp->nID, FALSE);
389
/* seek to the icon resource in the EXE file */
390
fseek(fpexe, icon_pos, SEEK_SET);
392
/* seek to the icon image in the ICO file */
393
fseek(fpico, cur_ico->dwImageOffset, SEEK_SET);
395
/* copy data from the ICO file to the EXE file */
396
for (rem = cur_ico->dwBytesInRes ; rem != 0 ; )
402
* read up to the buffer size or the amount
403
* remaining, whichever is less
405
cur = sizeof(copybuf);
408
if (fread(copybuf, cur, 1, fpico) != 1)
414
/* write it out to the EXE file */
415
if (fwrite(copybuf, cur, 1, fpexe) != 1)
421
/* deduct the amount read from the total */
425
/* no need to look any further */
430
/* if we didn't find it, report an error */
434
* note the error, but keep looking anyway, because there
435
* may still be other resources that we can successfully
436
* use; this error is essentially just a warning that there
437
* were some icon types in the ICO file that we couldn't
438
* store into the EXE file
445
/* free any memory we allocated */
446
if (group_dir_entry != 0)
447
free(group_dir_entry);
448
if (icon_dir_entry != 0)
449
free(icon_dir_entry);
451
/* return the result */
456
#endif /* MKTRX_SETICON
458
/* ------------------------------------------------------------------------ */
460
* A couple of OS routines we lifted from osgen.c
463
static void os_defext(char *fn, char *ext)
465
char *p = fn + strlen(fn);
469
if (*p == '.') return; /* already has an extension */
470
if (*p == '/' || *p == '\\' || * p== ':') break; /* found a path */
472
strcat(fn, "."); /* add a dot */
473
strcat(fn, ext); /* add the extension */
476
static void os_remext(char *fn)
478
char *p = fn + strlen(fn);
487
if (*p == '/' || *p == '\\' || *p == ':') return;
491
static char *os_get_root_name(char *buf)
495
/* scan the name for path separators */
496
for (rootname = buf ; *buf != '\0' ; ++buf)
498
/* if this is a path separator, remember it */
499
if (*buf == '/' || *buf == '\\' || *buf == ':')
502
* It's a path separators - for now, assume the root will
503
* start at the next character after this separator. If we
504
* find another separator later, we'll forget about this one
505
* and use the later one instead.
511
/* return the last root name candidate */
516
* Write a section header. The section header consists of a check value
517
* that indicates that the seek position is correct, and a section type
520
* The typecode must always be four bytes long.
522
static void write_header(FILE *fpout, const char *typecode)
526
/* compute the check code */
527
comp = ~ftell(fpout);
529
/* write the check and the type code */
530
if (fwrite(&comp, sizeof(comp), 1, fpout) != 1
531
|| fwrite(typecode, 4, 1, fpout) != 1)
533
fprintf(stderr, "error writing section header (%s)\n", typecode);
539
* Write the end-of-section trailing header. The trailing header
540
* consists of a check indicating its own seek location, so we can tell
541
* that the trailing header is indeed a trailing header; a type code;
542
* and the seek position of the leading data block header.
544
* The typecode must always be four bytes long.
546
static void write_trailing_header(FILE *fpout, long startofs,
547
const char *typecode)
551
/* compute the check */
552
comp = ~ftell(fpout);
554
/* write the trailing header */
555
if (fwrite(&comp, sizeof(comp), 1, fpout) != 1
556
|| fwrite(typecode, 4, 1, fpout) != 1
557
|| fwrite(&startofs, sizeof(startofs), 1, fpout) != 1)
559
fprintf(stderr, "error writing trailing header (%s)\n", typecode);
565
* A great big buffer for copying the files around.
567
static char buf[30*1024];
569
static void append_file(FILE *fpout, FILE *fpin, char *typ, int put_size)
573
/* remember where this starts */
574
startofs = ftell(fpout);
576
/* write the section header */
577
write_header(fpout, typ);
579
/* write the size prefix if desired */
584
/* seek to the end to get the size, then back to the start */
585
fseek(fpin, 0L, SEEK_END);
587
fseek(fpin, 0L, SEEK_SET);
589
/* write the size prefix */
590
if (fwrite(&siz, sizeof(siz), 1, fpout) != 1)
592
fprintf(stderr, "error writing output file\n");
597
/* copy the data from the input file to the output file */
602
if (!(siz = fread(buf, 1, sizeof(buf), fpin))) break;
603
if (fwrite(buf, 1, siz, fpout) != siz)
605
fprintf(stderr, "error writing output file\n");
610
/* write the trailing descriptor block */
611
write_trailing_header(fpout, startofs, typ);
615
int main(int argc, char **argv)
617
FILE *fptrx, *fpgam, *fpout;
618
char trxnam[_MAX_PATH];
619
char gamnam[_MAX_PATH];
620
char outnam[_MAX_PATH];
622
char *argv0 = argv[0];
627
int use_html_exe = FALSE;
628
int use_t3_exe = FALSE;
629
int use_prot_exe = FALSE;
630
int use_win32_exe = FALSE;
631
int show_logo = TRUE;
633
char charlibname[_MAX_PATH];
634
char *res_type = "TGAM";
636
char iconname[_MAX_PATH];
637
int set_icon = FALSE;
640
/* presume we won't find a saved game extension option */
643
/* presume we won't find a character map library */
649
for (curarg = 1 ; curarg < argc ; ++curarg)
651
/* if it's not an option, we're done */
652
if (argv[curarg][0] != '-')
655
/* check the option */
656
if (stricmp(argv[curarg], "-savext") == 0)
658
/* the next argument is the saved game extension */
661
savext = argv[curarg];
663
else if (stricmp(argv[curarg], "-html") == 0)
665
/* note that we want to use the HTML TADS executable */
668
else if (stricmp(argv[curarg], "-prot") == 0)
670
/* note that we want to use the protected-mode run-time */
673
else if (stricmp(argv[curarg], "-win32") == 0)
675
/* note that we want to use the 32-bit Windows run-time */
676
use_win32_exe = TRUE;
678
else if (stricmp(argv[curarg], "-nologo") == 0)
683
else if (stricmp(argv[curarg], "-t3") == 0)
685
/* use a T3 executable */
688
else if (stricmp(argv[curarg], "-clib") == 0)
692
charlib = argv[curarg];
695
else if (stricmp(argv[curarg], "-icon") == 0)
697
/* the next argument is the icon file */
702
* copy the name of the icon file and apply the .ICO
703
* extension by default
705
strcpy(iconname, argv[curarg]);
706
os_defext(iconname, "ico");
708
/* note that we want to set the icon */
713
else if (stricmp(argv[curarg], "-type") == 0)
715
/* the next argument is the type string */
717
if (curarg < argc && strlen(argv[curarg]) == 4)
719
/* set the resource type name to this argument */
720
res_type = argv[curarg];
723
printf("usage error - "
724
"type must be exactly four characters\n");
728
/* display the usage message */
735
* If there's a config file, get it now, and remove it from the
736
* arguments so the rest of the argument parser doesn't have to be
737
* bothered with it (which is important, since the rest of the
738
* argument parser is positional)
740
if (curarg < argc && argv[curarg][0] == '@')
742
config_file = &argv[curarg][1];
748
/* show the banner, unless we've been asked not to do so */
751
printf("maketrx v3.0.0 ");
752
printf("Copyright (c) 1992, 2000 by Michael J. Roberts.\n");
756
* check to make sure we have enough arguments remaining - we need
757
* at least one argument for the game filename
762
"usage: maketrx [options] [@config] [source] game [dest]\n"
763
" config = [optional] configuration file\n"
764
" source = [optional] TADS interpreter executable\n"
765
" game = your compiled .gam or .t3 file\n"
766
" dest = [optional] output .exe executable file\n"
768
"If 'source' is not specified, the program will look for "
769
"the interpreter in\n"
770
"the same directory as MAKETRX.EXE. If 'dest' is not "
771
"specified, the program\n"
772
"will use the same filename as the 'game' with the "
773
"extension replaced\n"
777
" -html Use the HTML TADS 2 run-time (HTMLT2.EXE)\n"
779
" -icon icofile Use the icon in 'icofile' for the desktop "
781
" output file (for HTML TADS only)\n"
783
" -prot Use the 16-bit DOS protected mode run-time"
785
" -win32 Use the 32-bit Windows console-mode "
786
"run-time (T2R32.EXE)\n"
787
" -savext ext Use 'ext' as the saved game extension "
789
" -t3 Use TADS 3 executables (T3RUN/HTMLT3)\n"
790
" -clib resfile Add 'resfile' as a CLIB (T3 character map "
792
" Note: -t3 implies '-clib "
793
"charmap\\cmaplib.t3r' if charmap\\cmaplib.t3r exists\n"
799
* check for the run-time executable - if we have three more
800
* arguments, they've explicitly told us which run-time executable
801
* to use; otherwise, try to find the default executable
803
if (curarg + 2 >= argc)
808
* the run-time executable was not specified - get the implicit
809
* TR.EXE location from argv[0] if possible
811
strcpy(trxnam, argv0);
816
"error: you must specify the full path to TR.EXE as the\n"
817
"first argument (run this program again with no arguments"
818
"\nfor the usage message)\n");
822
/* use first argument as the game */
823
strcpy(gamnam, argv[curarg]);
825
/* if there's a .t3 suffix on the input file, assume -t3 mode */
826
if ((len = strlen(gamnam)) > 3
827
&& stricmp(gamnam + len - 3, ".t3") == 0)
830
/* find the end of the path prefix */
831
for (p += strlen(p) - 1 ; p > trxnam
832
&& *p != '/' && *p != '\\' && *p != ':' ; --p);
833
if (*p == '/' || *p == '\\' || *p == ':') ++p;
835
/* copy the executable name */
838
/* build using the appropriate T3 executable */
840
strcpy(p, "htmlt3.exe");
842
strcpy(p, "t3run.exe");
846
/* use the appropriate TADS 2 executable */
848
strcpy(p, "htmlt2.exe");
849
else if (use_prot_exe)
850
strcpy(p, "trx.exe");
851
else if (use_win32_exe)
852
strcpy(p, "t2r32.exe");
858
* if there's no directory path prefix at all, and the file we're
859
* looking for doesn't exist, then we must have an argv[0] that
860
* found this program on the PATH environment variable; scan the
861
* PATH for a directory containing the file we're looking for
863
if (access(trxnam, 0) && p == trxnam)
865
char fullname[_MAX_PATH];
868
/* get the PATH setting */
869
path = getenv("PATH");
871
/* if we found it, scan it */
876
/* scan for a semicolon */
877
for (p = path ; *p != ';' && *p != '\0' ; ++p) ;
880
* get the length of this element, but limit it to our
881
* buffer size, leaving space for the filename we need to
882
* append (our filenames are all 8.3, so we need at most 12
883
* characters including the dot, plus one for the null
887
if (len > _MAX_PATH - 13)
888
len = _MAX_PATH - 13;
890
/* check this path element if it's not empty */
893
/* extract the path element */
894
memcpy(fullname, path, len);
896
/* add a path separator if there isn't one already */
898
&& fullname[len-1] != '\\' && fullname[len-1] != '/')
899
fullname[len++] = '\\';
901
/* append the name of the file we're looking for */
902
strcpy(fullname + len, trxnam);
904
/* if this is the one, use this path */
905
if (!access(fullname, 0))
907
/* use this as the full interpreter path */
908
strcpy(trxnam, fullname);
910
/* no need to look any further */
916
* this isn't the one; if we found a semicolon, move to the
917
* next path element, otherwise we're done
926
/* if no destination is specified, use game (but strip extension) */
927
if (curarg + 1 >= argc)
929
strcpy(outnam, argv[curarg]);
933
strcpy(outnam, argv[curarg + 1]);
937
/* get TR.EXE path from explicit first argument */
938
strcpy(trxnam, argv[curarg]);
939
strcpy(gamnam, argv[curarg + 1]);
940
strcpy(outnam, argv[curarg + 2]);
941
os_defext(trxnam, "exe");
944
/* apply default extensions */
945
os_defext(trxnam, "exe");
946
os_defext(gamnam, use_t3_exe ? "t3" : "gam");
947
os_defext(outnam, "exe");
949
if (!(fptrx = fopen(trxnam, "rb")))
951
fprintf(stderr, "unable to open program file \"%s\"\n", trxnam);
954
if (!(fpgam = fopen(gamnam, "rb")))
956
fprintf(stderr, "unable to open .GAM file \"%s\"\n", gamnam);
959
if (!(fpout = fopen(outnam, "w+b")))
961
fprintf(stderr, "unable to open output file \"%s\"\n", outnam);
966
* if we're in t3 mode, and no CLIB file was specified, and we can
967
* find 'cmaplib.t3r' in the same directory as the original
968
* interpreter .exe file, add cmaplib.t3r to as the implicit CLIB
971
if (use_t3_exe && charlib == 0)
973
/* build the name of the implicit file */
974
strcpy(charlibname, trxnam);
975
strcpy(os_get_root_name(charlibname), "charmap\\cmaplib.t3r");
976
if (!access(charlibname, 0))
977
charlib = charlibname;
980
/* Copy the all of TR.EXE original to the output file */
983
if (!(siz = fread(buf, 1, sizeof(buf), fptrx))) break;
984
if (fwrite(buf, 1, siz, fpout) != siz)
986
fprintf(stderr, "error writing output file\n");
991
/* write the config file, if present */
996
/* open the config file */
997
fpconfig = fopen(config_file, "rb");
1000
fprintf(stderr, "unable to open configuration file \"%s\"\n",
1005
/* copy the config file to the output file */
1006
append_file(fpout, fpconfig, "RCFG", 1);
1010
/* add the game file */
1011
append_file(fpout, fpgam, res_type, 0);
1014
* If there's a save file extension, add the SAVX resource to
1015
* specify the extension
1022
/* remember the starting location */
1023
startofs = ftell(fpout);
1025
/* write the header */
1026
write_header(fpout, "SAVX");
1028
/* write the length of the extension, followed by the extension */
1029
len = strlen(savext);
1030
if (fwrite(&len, sizeof(len), 1, fpout) != 1
1031
|| fwrite(savext, len, 1, fpout) != 1)
1033
fprintf(stderr, "error writing output file\n");
1037
/* write the trailing header */
1038
write_trailing_header(fpout, startofs, "SAVX");
1041
/* if there's a character library file, add it */
1047
fpchar = fopen(charlib, "rb");
1049
/* make sure we got it */
1053
append_file(fpout, fpchar, "CLIB", 0);
1055
/* done with the file */
1060
fprintf(stderr, "unable to open character library (CLIB) file "
1061
"\"%s\"\n", charlib);
1065
#ifdef MKTRX_SETICON
1067
* If they want to set the icon, do so now
1074
/* open the icon file */
1075
fpico = fopen(iconname, "rb");
1078
/* report the error */
1079
fprintf(stderr, "error opening icon file \"%s\"\n", iconname);
1084
* replace the icon - always replace the icon at index zero,
1085
* since this is the icon used to represent the application
1088
err = replace_icon(fpout, 0, fpico);
1093
"error replacing icon: .EXE file is invalid\n");
1094
else if (err <= 106)
1096
"error replacing icon: .EXE file does not "
1097
"contain any icon resources\n");
1098
else if (err == 107)
1100
"error replacing icon: desktop icon is not "
1101
"present in .EXE file\n");
1102
else if (err == 110)
1104
"Error replacing icon: one or more icon formats "
1105
"in this .ICO file are not present\n"
1106
"in the .EXE file -- "
1107
"these formats could not be replaced.\n");
1110
"error: icon could not be replaced in "
1117
/* close all the files and terminate successfully */