Subversion Repositories filter_foundry

Rev

Rev 279 | Rev 281 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
258 daniel-mar 1
/*
2
    This file is part of "Filter Foundry", a filter plugin for Adobe Photoshop
3
    Copyright (C) 2003-2009 Toby Thain, toby@telegraphics.com.au
4
    Copyright (C) 2018-2021 Daniel Marschall, ViaThinkSoft
5
 
6
    This program is free software; you can redistribute it and/or modify
7
    it under the terms of the GNU General Public License as published by
8
    the Free Software Foundation; either version 2 of the License, or
9
    (at your option) any later version.
10
 
11
    This program is distributed in the hope that it will be useful,
12
    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
    GNU General Public License for more details.
15
 
16
    You should have received a copy of the GNU General Public License
17
    along with this program; if not, write to the Free Software
18
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
*/
20
 
21
#include "ff.h"
22
 
278 daniel-mar 23
#include <time.h>
24
 
258 daniel-mar 25
#include "file_compat.h"
26
#include "compat_string.h"
27
#include "versioninfo_modify_win.h"
28
#include "version.h"
29
 
30
extern HINSTANCE hDllInstance;
31
 
274 daniel-mar 32
Boolean doresources(HMODULE srcmod,char *dstname, int bits);
258 daniel-mar 33
 
34
void dbglasterror(char *func){
35
        char s[0x100];
36
 
37
        strcpy(s,func);
38
        strcat(s," failed: ");
39
        FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM,NULL,GetLastError(),0,s+strlen(s),0x100,NULL );
40
        dbg(s);
41
}
42
 
43
/*
44
BOOL CALLBACK enumfunc(HMODULE hModule,LPCTSTR lpszType,LPCTSTR lpszName,WORD wIDLanguage,LONG lParam){
45
        char s[0x100];
46
        sprintf(s,"EnumResourceLanguages callback: module=%#x type=%s name=%s lang=%d",
47
                hModule,lpszType,lpszName,wIDLanguage);
48
        dbg(s);
49
        return TRUE;
50
}
51
*/
52
 
274 daniel-mar 53
int domanifest(char *newmanifest, const char *manifestp, PARM_T* pparm, int bits) {
258 daniel-mar 54
        char name[1024];
55
        char description[1024];
56
        size_t i;
276 daniel-mar 57
        size_t iname = 0;
258 daniel-mar 58
        int idescription = 0;
59
 
60
        // Description
61
        for (i = 0; i < strlen((char*)pparm->category); i++) {
62
                char c = pparm->category[i];
63
                if ((c != '<') && (c != '>')) {
64
                        description[idescription++] = c;
65
                }
66
        }
67
        description[idescription++] = ' ';
68
        description[idescription++] = '-';
69
        description[idescription++] = ' ';
70
        for (i = 0; i < strlen((char*)pparm->title); i++) {
71
                char c = pparm->title[i];
72
                if ((c != '<') && (c != '>')) {
73
                        description[idescription++] = c;
74
                }
75
        }
76
        description[idescription++] = '\0';
77
 
78
        // Name
79
        strcpy(name, "Telegraphics.FilterFoundry.");
80
        iname = strlen("Telegraphics.FilterFoundry.");
81
        for (i = 0; i < strlen((char*)pparm->category); i++) {
82
                char c = pparm->category[i];
83
                if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'))) {
84
                        name[iname++] = c;
85
                }
86
        }
87
        name[iname++] = '.';
88
        for (i = 0; i < strlen((char*)pparm->title); i++) {
89
                char c = pparm->title[i];
90
                if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'))) {
91
                        name[iname++] = c;
92
                }
93
        }
94
        name[iname++] = '\0';
95
 
274 daniel-mar 96
        if (bits == 64) {
97
                return sprintf(newmanifest, manifestp, (char*)name, "amd64", VERSION_STR, (char*)description);
98
        }
99
        else {
100
                return sprintf(newmanifest, manifestp, (char*)name, "x86", VERSION_STR, (char*)description);
101
        }
258 daniel-mar 102
}
103
 
104
void changeVersionInfo(char* dstname, PARM_T* pparm, HGLOBAL hupdate) {
105
        char* soleFilename;
106
        LPWSTR changeRequestStr, tmp;
107
 
108
        if (soleFilename = strrchr(dstname, '\\')) {
109
                ++soleFilename;
110
        }
111
        else {
112
                soleFilename = dstname;
113
        }
114
 
115
        // Format of argument "PCWSTR changes" is "<name>\0<value>\0<name>\0<value>\0....."
116
        // You can CHANGE values for any given name
117
        // You can DELETE entries by setting the value to "\b" (0x08 backspace character)
118
        // You cannot (yet) ADD entries.
119
        changeRequestStr = (LPWSTR)malloc(6 * 2 * 100 + 1);
120
 
121
        tmp = changeRequestStr;
122
 
123
        tmp += mbstowcs(tmp, "Comments", 100);
124
        tmp++;
125
        tmp += mbstowcs(tmp, "Built using Filter Foundry " VERSION_STR, 100);
126
        tmp++;
127
 
128
        tmp += mbstowcs(tmp, "CompanyName", 100);
129
        tmp++;
130
        if (strlen((char*)pparm->author) > 0) {
131
                tmp += mbstowcs(tmp, (char*)pparm->author, 100);
132
        }
133
        else {
134
                tmp += mbstowcs(tmp, "\b", 100); // \b = remove
135
        }
136
        tmp++;
137
 
138
        tmp += mbstowcs(tmp, "LegalCopyright", 100);
139
        tmp++;
140
        if (strlen((char*)pparm->copyright) > 0) {
141
                tmp += mbstowcs(tmp, (char*)pparm->copyright, 100);
142
        }
143
        else {
144
                tmp += mbstowcs(tmp, "\b", 100); // \b = remove
145
        }
146
        tmp++;
147
 
148
        tmp += mbstowcs(tmp, "FileDescription", 100);
149
        tmp++;
150
        if (strlen((char*)pparm->title) > 0) {
151
                tmp += mbstowcs(tmp, (char*)pparm->title, 100);
152
        }
153
        else {
154
                tmp += mbstowcs(tmp, "Untitled filter", 100);
155
        }
156
        tmp++;
157
 
158
        tmp += mbstowcs(tmp, "OriginalFilename", 100);
159
        tmp++;
160
        tmp += mbstowcs(tmp, soleFilename, 100);
161
        tmp++;
162
 
163
        tmp += mbstowcs(tmp, "License", 100);
164
        tmp++;
165
        tmp += mbstowcs(tmp, "\b", 100); // \b = remove, since filter is standalone and might have its own license
166
        tmp++;
167
 
168
        tmp += mbstowcs(tmp, "", 1);
169
 
170
        if (UpdateVersionInfoWithHandle(dstname, hupdate, changeRequestStr) != NOERROR) {
171
                alertuser(_strdup("UpdateVersionInfoWithHandle failed"), _strdup(""));
172
        }
173
 
174
        free(changeRequestStr);
175
}
176
 
278 daniel-mar 177
Boolean update_pe_timestamp(const char* filename, time_t timestamp) {
280 daniel-mar 178
        size_t peoffset;
179
        FILE* fptr;
180
 
181
        fptr = fopen(filename, "rb+");
278 daniel-mar 182
        if (fptr == NULL) return false;
183
 
184
        fseek(fptr, 0x3C, SEEK_SET);
185
        fread(&peoffset, sizeof(peoffset), 1, fptr);
186
 
280 daniel-mar 187
        fseek(fptr, (long)peoffset + 8, SEEK_SET);
278 daniel-mar 188
        fwrite(&timestamp, sizeof(time_t), 1, fptr);
189
 
190
        fclose(fptr);
191
 
192
        return true;
193
}
194
 
276 daniel-mar 195
int binary_replace_file(const char* filename, unsigned int search, unsigned int replace) {
196
        unsigned int srecord = 0;
197
        int found = 0;
198
 
199
        FILE* fptr = fopen(filename, "rb+");
200
        if (fptr == NULL) return -1;
201
 
202
        while ((fread(&srecord, sizeof(srecord), 1, fptr) == 1))
203
        {
204
                if (srecord == search) {
205
                        srecord = replace;
206
                        fseek(fptr, -1*(long)sizeof(srecord), SEEK_CUR);
207
                        fwrite(&srecord, (int)sizeof(srecord), 1, fptr);
208
                        fseek(fptr, 0, SEEK_CUR); // important!
209
                        found++;
210
                }
211
                else {
212
                        fseek(fptr, -1*(long)(sizeof(srecord) - 1), SEEK_CUR);
213
                }
214
        }
215
        fclose(fptr);
216
 
217
        return found;
218
}
219
 
274 daniel-mar 220
Boolean doresources(HMODULE srcmod,char *dstname, int bits){
258 daniel-mar 221
        HRSRC datarsrc,aetersrc,manifestsrc;
222
        HGLOBAL datah,aeteh,hupdate,manifesth;
223
        Ptr newpipl = NULL, newaete = NULL;
224
        LPVOID datap, aetep, manifestp;
225
        PARM_T *pparm = NULL;
226
        size_t piplsize,aetesize,origsize,manifestsize;
227
        Str255 title;
228
        LPCTSTR parm_type;
229
        int i,parm_id;
230
        Boolean discard = true;
276 daniel-mar 231
        unsigned int obfuscseed = 0;
258 daniel-mar 232
        long event_id;
233
 
234
        if( (hupdate = _BeginUpdateResource(dstname,false)) ){
235
                DBG("BeginUpdateResource OK");
236
                if( (datarsrc = FindResource(srcmod,MAKEINTRESOURCE(16000),"TPLT"))
237
                        && (datah = LoadResource(srcmod,datarsrc))
238
                        && (datap = (Ptr)LockResource(datah))
239
                        && (aetersrc = FindResource(srcmod, MAKEINTRESOURCE(16000), "AETE"))
240
                        && (aeteh = LoadResource(srcmod, aetersrc))
241
                        && (aetep = (Ptr)LockResource(aeteh))
242
                        && (manifestsrc = FindResource(srcmod, MAKEINTRESOURCE(50), "TPLT"))
243
                        && (manifesth = LoadResource(srcmod, manifestsrc))
244
                        && (manifestp = (Ptr)LockResource(manifesth)) )
245
                {
246
                        char newmanifest[5000];
247
 
248
                        DBG("loaded DATA, PiPL");
249
 
250
                        PLstrcpy(title,gdata->parm.title);
251
                        if(gdata->parm.popDialog)
252
                                PLstrcat(title,(StringPtr)"\003...");
253
 
254
                        origsize = SizeofResource(srcmod,datarsrc);
255
 
256
                        if( (newpipl = (Ptr)malloc(origsize+0x300))
257
                         && (newaete = (Ptr)malloc(4096))
258
                         && (pparm = (PARM_T*)malloc(sizeof(PARM_T))) )
259
                        {
260
                                // ====== Generate AETE and PIPL
261
 
262
                                /* add user-specified title and category to new PiPL */
263
                                memcpy(newpipl,datap,origsize);
264
                                /* note that Windows PiPLs have 2 byte version datum in front
265
                                   that isn't reflected in struct definition or Mac resource template: */
266
                                piplsize = fixpipl((PIPropertyList*)(newpipl+2),origsize-2,title, &event_id) + 2;
267
 
268
                                /* set up the PARM resource with saved parameters */
269
                                memcpy(pparm,&gdata->parm,sizeof(PARM_T));
270
 
271
                                /* Generate 'aete' resource (contains names of the parameters for the "Actions" tab in Photoshop) */
272
                                aetesize = aete_generate(newaete, pparm, event_id);
273
 
276 daniel-mar 274
                                if (gdata->obfusc) {
275
                                        // Avoid that the same filter can generate with two seeds,
276
                                        // otherwise the comparison would be much easier
277
                                        obfuscseed = (unsigned int)get_parm_hash(pparm);
278
                                }
279
 
258 daniel-mar 280
                                // ====== Change Pascal strings to C-Strings
281
 
282
                                /* convert to C strings for Windows PARM resource */
283
                                // Don't do it before aete_generate, because they need Pascal strings
284
                                myp2cstr(pparm->category);
285
                                myp2cstr(pparm->title);
286
                                myp2cstr(pparm->copyright);
287
                                myp2cstr(pparm->author);
288
                                for (i = 0; i < 4; ++i)
289
                                        myp2cstr(pparm->map[i]);
290
                                for (i = 0; i < 8; ++i)
291
                                        myp2cstr(pparm->ctl[i]);
292
 
274 daniel-mar 293
                                manifestsize = domanifest(newmanifest, (const char*)manifestp, pparm, bits);
258 daniel-mar 294
 
295
                                // ====== Change version attributes
296
 
297
                                changeVersionInfo(dstname, pparm, hupdate);
298
 
299
                                // ====== Obfuscate pparm!
300
 
301
                                if(gdata->obfusc){
302
                                        parm_type = RT_RCDATA;
303
                                        parm_id = OBFUSCDATA_ID;
276 daniel-mar 304
 
305
                                        // Note: After we have finished updating the resources, we will write <obfuscseed> into the binary code of the 8BF file
306
                                        obfusc(pparm, obfuscseed);
258 daniel-mar 307
                                }else{
308
                                        parm_type = "PARM";
309
                                        parm_id = PARM_ID;
310
                                }
311
 
312
                                // ====== Save AETE, PIPL, Manifest and PARM/RCDATA
313
 
314
                                /* Attention: The resource we have found using FindResource() might have a different
315
                                   language than the resource we are saving (Neutral), so we might end up having
316
                                   multiple languages for the same resource. Therefore, the language "Neutral" was
317
                                   set in the Scripting.rc file for the resource AETE and PIPL.rc for the resources PIPL. */
274 daniel-mar 318
 
319
                                if(_UpdateResource(hupdate, "TPLT" /* note: caps!! */, MAKEINTRESOURCE(50), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0)
320
                                        && _UpdateResource(hupdate, "TPLT" /* note: caps!! */, MAKEINTRESOURCE(16000), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0)
321
                                        && _UpdateResource(hupdate, RT_DIALOG, MAKEINTRESOURCE(ID_BUILDDLG), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NULL, 0)
322
                                        && _UpdateResource(hupdate,"PIPL" /* note: caps!! */,MAKEINTRESOURCE(16000), MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),newpipl,(DWORD)piplsize)
258 daniel-mar 323
                                        && _UpdateResource(hupdate, "AETE" /* note: caps!! */, MAKEINTRESOURCE(16000), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), newaete, (DWORD)aetesize)
324
                                        && _UpdateResource(hupdate, RT_MANIFEST, MAKEINTRESOURCE(1), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), newmanifest, (DWORD)manifestsize)
325
                                        && _UpdateResource(hupdate,parm_type,MAKEINTRESOURCE(parm_id), MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),pparm,sizeof(PARM_T)) )
326
                                {
327
                                        discard = false;
328
                                } else {
329
                                        dbglasterror(_strdup("UpdateResource"));
330
                                }
331
                        }
332
 
333
                }else dbglasterror(_strdup("Find-, Load- or LockResource"));
334
 
276 daniel-mar 335
                // Here, the file will be saved
258 daniel-mar 336
                if(!_EndUpdateResource(hupdate,discard))
337
                        dbglasterror(_strdup("EndUpdateResource"));
338
 
276 daniel-mar 339
                if (gdata->obfusc) {
277 daniel-mar 340
                        // We modify the binary code to replace the deobfuscate-seed from <cObfuscV4Seed> to <obfuscseed>
278 daniel-mar 341
                        if (binary_replace_file(dstname, cObfuscV4Seed, obfuscseed) != 1) {
342
                                // The seed must only be exactly 1 time inside the 8BF file,
343
                                // since "const volatile" makes sure that the compiler won't place
344
                                // it at several locations in the code.
276 daniel-mar 345
                                dbg("binary_replace_file failed");
346
                                discard = true;
347
                        }
348
                }
349
 
278 daniel-mar 350
                update_pe_timestamp(dstname, time(0));
351
 
258 daniel-mar 352
                if(pparm) free(pparm);
353
                if(newpipl) free(newpipl);
354
                if(newaete) free(newaete);
355
        }else
356
                dbglasterror(_strdup("BeginUpdateResource"));
357
        return !discard;
358
}
359
 
278 daniel-mar 360
Boolean remove_64_filename_prefix(char* dstname) {
274 daniel-mar 361
        // foobar.8bf => foobar.8bf
362
        // foobar64.8bf => foobar.8bf
276 daniel-mar 363
        size_t i;
274 daniel-mar 364
        for (i = strlen(dstname); i > 2; i--) {
365
                if (dstname[i] == '.') {
366
                        if ((dstname[i - 2] == '6') && (dstname[i - 1] == '4')) {
276 daniel-mar 367
                                size_t tmp = strlen(dstname);
274 daniel-mar 368
                                memcpy(&dstname[i - 2], &dstname[i], strlen(dstname) - i + 1);
369
                                dstname[tmp - 2] = 0;
370
                                return true;
371
                        }
372
                }
373
        }
374
        return false;
375
}
376
 
278 daniel-mar 377
Boolean add_64_filename_prefix(char* dstname) {
274 daniel-mar 378
        // foobar.8bf => foobar64.8bf
276 daniel-mar 379
        size_t i;
274 daniel-mar 380
        for (i = strlen(dstname); i > 2; i--) {
381
                if (dstname[i] == '.') {
276 daniel-mar 382
                        size_t tmp = strlen(dstname);
274 daniel-mar 383
                        memcpy(&dstname[i + 2], &dstname[i], strlen(dstname) - i + 1);
384
                        dstname[i] = '6';
385
                        dstname[i + 1] = '4';
386
                        dstname[tmp + 2] = 0;
387
                        return true;
388
                }
389
        }
390
        return false;
391
}
392
 
393
BOOL FileExists(LPCTSTR szPath) {
394
        DWORD dwAttrib = GetFileAttributes(szPath);
395
        return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
396
                !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
397
}
398
 
399
OSErr do_make_standalone(char* srcname, char* dstname, int bits) {
400
        Boolean res;
401
 
402
        //DeleteFile(dstname);
403
        if (CopyFile(srcname, dstname, false)) {
404
                HMODULE hSrcmod;
405
                hSrcmod = LoadLibraryEx(srcname, NULL, LOAD_LIBRARY_AS_DATAFILE);
406
                if (hSrcmod) {
407
                        res = doresources(hSrcmod, dstname, bits);
408
                        if (!res) {
409
                                DeleteFile(dstname);
410
                        }
411
                        FreeLibrary(hSrcmod);
412
                }
413
                else {
414
                        res = false;
415
                }
416
        }
417
        else {
418
                res = false;
419
        }
420
 
421
        if (!res) {
422
                char err[MAX_PATH + 200];
423
                sprintf(err, "Could not create %d bit standalone plugin.", bits);
424
                alertuser(_strdup(&err[0]), _strdup(""));
425
        }
426
 
427
        return res ? noErr : ioErr;
428
}
429
 
258 daniel-mar 430
OSErr make_standalone(StandardFileReply *sfr){
274 daniel-mar 431
        OSErr tmpErr, outErr;
258 daniel-mar 432
        char dstname[0x100],srcname[MAX_PATH+1];
433
 
434
        if (!isWin32NT()) {
435
                HMODULE hLib;
436
 
437
                hLib = LoadLibraryA("UNICOWS.DLL");
438
                if (!hLib) {
439
                        char* sysdir;
440
 
279 daniel-mar 441
                        // Unicows.dll is required to implement the BeginUpdateResource functionalities in Win9x
442
 
258 daniel-mar 443
                        sysdir = (char*)malloc(MAX_PATH);
444
                        GetSystemDirectoryA(sysdir, MAX_PATH);
445
                        alertuser(_strdup("To build standalone plugins using this version of\nWindows, you need to install UNICOWS.DLL\n\nPlease download it from the Internet\nand place it into following directory:"), sysdir);
446
                        free(sysdir);
447
 
448
                        return false;
449
                }
450
                else {
451
                        FreeLibrary(hLib);
452
                }
453
        }
454
 
274 daniel-mar 455
        outErr = noErr;
258 daniel-mar 456
 
274 daniel-mar 457
#ifdef _WIN64
458
 
459
        //64 bit DLL makes 64 bit:
460
        // Source file = module filename
461
        GetModuleFileName(hDllInstance, srcname, MAX_PATH);
462
        // Destfile = no64_or_32(chosenname) + 64
463
        myp2cstrcpy(dstname, sfr->sfFile.name);
464
        remove_64_filename_prefix(dstname);
465
        add_64_filename_prefix(dstname);
466
        tmpErr = do_make_standalone(&srcname[0], &dstname[0], 64);
467
        if (tmpErr != noErr)
468
                outErr = tmpErr;
469
        else
470
                showmessage(_strdup("64 bit standalone filter was successfully created"));
471
 
472
        //64 bit DLL makes 32 bit:
473
        // Source file = no32(modulefilename)
474
        GetModuleFileName(hDllInstance, srcname, MAX_PATH);
475
        if (!remove_64_filename_prefix(srcname)) {
476
                char err[MAX_PATH + 200];
477
                sprintf(err, "Cannot create the %d bit version of this filter, because the 32-bit variant of this plugin could not be found", 32);
478
                alertuser(_strdup(&err[0]), _strdup(""));
258 daniel-mar 479
        }
274 daniel-mar 480
        else if (!FileExists(srcname)) {
481
                char err[MAX_PATH + 200];
482
                sprintf(err, "%s was not found. Therefore, the %d bit version of the standalone filter could not be created!", srcname, 32);
483
                alertuser(_strdup(&err[0]), _strdup(""));
484
        }
485
        else {
486
                // Destfile = no64_or_32(chosenname)
487
                myp2cstrcpy(dstname, sfr->sfFile.name);
488
                remove_64_filename_prefix(dstname);
489
                tmpErr = do_make_standalone(&srcname[0], &dstname[0], 32);
490
                if (tmpErr != noErr)
491
                        outErr = tmpErr;
492
                else
493
                        showmessage(_strdup("32 bit standalone filter was successfully created"));
277 daniel-mar 494
        }
258 daniel-mar 495
 
274 daniel-mar 496
#else
497
 
498
        //32 bit DLL makes 32 bit:
499
        // Source file = module filename
500
        GetModuleFileName(hDllInstance, srcname, MAX_PATH);
501
        // Destfile = no64_or_32(chosenname)
502
        myp2cstrcpy(dstname, sfr->sfFile.name);
503
        remove_64_filename_prefix(dstname);
504
        tmpErr = do_make_standalone(&srcname[0], &dstname[0], 32);
505
        if (tmpErr != noErr)
506
                outErr = tmpErr;
507
        else
508
                showmessage(_strdup("32 bit standalone filter was successfully created"));
509
 
279 daniel-mar 510
        if (isWin32NT()) {
274 daniel-mar 511
                //32 bit DLL makes 64 bit:
512
                // Source file = module filename + 64
513
                GetModuleFileName(hDllInstance, srcname, MAX_PATH);
514
                add_64_filename_prefix(srcname);
515
                if (!FileExists(srcname)) {
516
                        char err[MAX_PATH + 200];
517
                        sprintf(err, "%s was not found. Therefore, the %d bit version of the standalone filter could not be created!", srcname, 64);
518
                        alertuser(_strdup(&err[0]), _strdup(""));
519
                }
520
                else {
521
                        // Destfile = no64_or_32(chosenname) + 64
522
                        myp2cstrcpy(dstname, sfr->sfFile.name);
523
                        remove_64_filename_prefix(dstname);
524
                        add_64_filename_prefix(dstname);
525
                        tmpErr = do_make_standalone(&srcname[0], &dstname[0], 64);
526
                        if (tmpErr != noErr)
527
                                outErr = tmpErr;
528
                        else
529
                                showmessage(_strdup("64 bit standalone filter was successfully created"));
530
                }
531
        }
279 daniel-mar 532
        else {
533
                // Unicows.dll cannot edit resources of 64 bit DLLs.
534
                // The normal Kernel function BeginUpdateResource can edit 64 bit DLLs, even in NT4.0 SP6
535
                simplealert(_strdup("Note: A 64 bit standalone filter cannot be created with your Windows version"));
536
        }
274 daniel-mar 537
#endif
538
 
539
        return outErr;
258 daniel-mar 540
}