source: trunk/dll/worker.c@ 1741

Last change on this file since 1741 was 1741, checked in by Gregg Young, 12 years ago

Fix warn readonly yes don't ask to work when recursing directories.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 52.8 KB
Line 
1
2/***********************************************************************
3
4 $Id: worker.c 1741 2014-02-22 23:32:04Z gyoung $
5
6 Worker thread
7
8 Copyright (c) 1993-98 M. Kimes
9 Copyright (c) 2001, 2014 Steven H. Levine
10
11 16 Oct 02 SHL Comments
12 18 Oct 02 SHL MassAction:Archive - force extension so file found
13 06 Jun 05 SHL Indent -i2
14 06 Jun 05 SHL Rework Action for VAC3.65 compat
15 27 Jul 05 SHL IDM_DOITYOURSELF - avoid need to strip in ExecOnList
16 22 Jul 06 SHL Comments
17 22 Jul 06 SHL Check more run time errors
18 03 Nov 06 SHL Renames
19 03 Nov 06 SHL Count thread usage
20 21 Apr 07 GKY Find FM2Utils by path or utils directory
21 16 Jun 07 SHL Update for OpenWatcom
22 06 Aug 07 GKY Reduce DosSleep times (ticket 148)
23 07 Aug 07 SHL Use BldQuotedFileName
24 20 Aug 07 GKY Move #pragma alloc_text to end for OpenWatcom compat
25 26 Aug 07 SHL Revert to DosSleep(0)
26 29 Feb 08 GKY Refactor global command line variables to notebook.h
27 22 Jun 08 GKY Made Felete move to xworkplace trash can on systems that have it
28 16 JUL 08 GKY Use TMP directory for temp files
29 20 Jul 08 GKY Add save/append filename to clipboard.
30 02 Aug 08 GKY Limit use of "trash can" to local writable fixed drives or to trash can supported
31 drives list if it exists. Fix ability to deselect use of trash can.
32 01 Sep 08 GKY Add code to retry on Netdrives "pipe error"
33 04 Dec 08 GKY Add a DosSleep to allow file extract to complete before rescan
34 04 Dec 08 GKY Add mutex semaphore and disable fSyncUpdates for file deletes to prevent the creation
35 on dead CNRITEMS.
36 10 Dec 08 SHL Integrate exception handler support
37 25 Dec 08 GKY Add code to allow write verify to be turned off on a per drive basis
38 25 Dec 08 GKY Add DRIVE_RSCANNED flag to monitor for the first recursive drive scan per session
39 to prevent duplicate directory names in tree following a copy before initial scan.
40 07 Feb 09 GKY Allow user to turn off alert and/or error beeps in settings notebook.
41 08 Mar 09 GKY Removed variable aurguments from docopyf and unlinkf (not used)
42 08 Mar 09 GKY Additional strings move to PCSZs
43 28 Jun 09 GKY Added AddBackslashToPath() to remove repeatative code.
44 26 Jul 09 GKY Fix failure of containers to update when Tree container isn't open in FM2 lite
45 13 Dec 09 GKY Attempt to fix container update issues with FM/2 lite
46 17 JAN 10 GKY Changes to get working with Watcom 1.9 Beta (1/16/10).
47 Mostly cast CHAR CONSTANT * as CHAR *.
48 20 Nov 10 GKY Check that pTmpDir IsValid and recreate if not found; Fixes hangs caused
49 by temp file creation failures.
50 12 Nov 11 GKY Fixed extract failure caused by spaces in the arc file name.
51 04 Aug 12 GKY Changes to use Unlock to unlock files if Unlock.exe is in path both from menu/toolbar and as part of
52 copy, move and delete operations
53 04 Aug 12 GKY Changes to allow copy and move over readonly files with a warning dialog; also added a warning dialog
54 for delete of readonly files
55 10 Mar 13 GKY Improvrd readonly check on delete to allow cancel and don't ask again options
56 Added saymsg2 for this purpose
57 09 Feb 14 GKY Modified wipeallf to allow suppression of the readonly warning on delete
58 of temporary files
59 16 Feb 14 GKY Fixed move to trashcan to work when the trashcan::drives key hadn't been
60 written to OS2.INI. INI check is now only if fTrashCan is TRUE.
61 16 Feb 14 GKY Rework readonly check on delete code so it actually works in a logical way
62 and so it works with move to trashcan inabled.
63 22 Feb 14 GKY Cleanup of readonly check code suppress spurious error on blocked directory
64 delete and eliminated the check on additional temp file deletes
65 22 Feb 14 GKY Fix warn readonly yes don't ask to work when recursing directories.
66
67***********************************************************************/
68
69#include <stdlib.h>
70#include <string.h>
71#include <ctype.h>
72#include <share.h>
73#include <process.h> // _beginthread // 10 Dec 08 SHL
74#include <time.h>
75
76#define INCL_DOS
77#define INCL_DOSERRORS
78// #define INCL_WINPROGRAMLIST // 13 Jul 09 SHL dropped
79// #define INCL_WINHELP // 13 Jul 09 SHL dropped
80#define INCL_LONGLONG
81#define INCL_WINPOINTERS // WinSetFileIcon
82// #define INCL_WINWORKPLACE // 13 Jul 09 SHL dropped
83#define INCL_WINSHELLDATA // PrfQueryProfileData
84
85#include "fm3dll.h"
86#include "fm3dll2.h" // #define's for UM_*, control id's, etc.
87#include "mainwnd2.h" // Data declaration(s)
88#include "arccnrs.h" // Data declaration(s)
89#include "init.h" // Data declaration(s)
90#include "defview.h" // Data declaration(s)
91#include "newview.h" // Data declarations
92#include "fm3dlg.h"
93#include "fm3str.h"
94#include "comp.h" // FCOMPARE
95#include "pathutil.h" // BldQuotedFileName
96#include "makelist.h" // AddToList
97#include "errutil.h" // Dos_Error...
98#include "strutil.h" // GetPString
99#include "notebook.h" // External viewers
100#include "worker.h" // Action
101#include "notify.h" // AddNote
102#include "copyf.h" // AdjustWildcardName, make_deleteable
103#include "attribs.h" // AttrListDlgProc
104#include "chklist.h" // CheckListProc
105#include "info.h" // DrvInfoProc
106#include "extract.h" // ExtractDlgProc
107#include "info.h" // FileInfoProc
108#include "valid.h" // GetDesktopName, IsNewer
109#include "saveclip.h" // ListToClipboardHab
110#include "shadow.h" // MakeShadows
111#include "mkdir.h" // MassMkdir
112#include "uudecode.h" // MergeDlgProc
113#include "objcnr.h" // ObjCnrDlgProc
114#include "printer.h" // PrintDlgProc, PrintListThread
115#include "rename.h" // RenameProc
116#include "srchpath.h" // RunFM2Util
117#include "mainwnd.h" // TopWindowName
118#include "uudecode.h" // UUD
119#include "walkem.h" // WalkCopyDlgProc, WalkDlgProc, WalkMoveDlgProc
120#include "archive.h" // ArchiveDlgProc
121#include "misc.h" // Broadcast
122#include "common.h" // DecrThreadUsage, IncrThreadUsage
123#include "eas.h" // DisplayEAsProc
124#include "systemf.h" // ExecOnList
125#include "avl.h" // SBoxDlgProc
126#include "subj.h" // Subject
127#include "stristr.h" // stristr
128#include "wrappers.h" // xfopen
129#include "fortify.h"
130#include "excputil.h" // 06 May 08 SHL added
131
132// Data definitions
133#pragma data_seg(GLOBAL2)
134FILE *LogFileHandle;
135BOOL fUnlock;
136
137#pragma data_seg(DATA2)
138
139static PSZ pszSrcFile = __FILE__;
140
141#ifdef UNDO
142
143static VOID LINFO undo;
144
145VOID FreeUndo(VOID)
146{
147 if (undo->list)
148 FreeList(undo->list);
149 memset(&undo, 0, sizeof(undo));
150}
151
152VOID Undo(HWND hwndCnr, HWND hwndFrame, HWND hwndClient, HWND hwndParent)
153{
154 LISTINFO *li;
155 WORKER *wk;
156
157 if (undo->type && undo->list && undo->list[0]) {
158 switch (undo->type) {
159 case IDM_MOVE:
160 case IDM_COPY:
161 case IDM_EXTRACT:
162 {
163# ifdef FORTIFY
164 Fortify_EnterScope();
165# endif
166 li = xmallocz(sizeof(LISTINFO), pszSrcFile, __LINE__);
167 if (li) {
168 wk = xmallocz(sizeof(WORKER), pszSrcFile, __LINE__);
169 if (wk) {
170 wk->size = sizeof(WORKER);
171 wk->hwndCnr = hwndCnr;
172 wk->hwndParent = hwndParent;
173 wk->hwndFrame = hwndFrame;
174 wk->hwndClient = hwndClient;
175 wk->li = li;
176 *wk->li = *undo;
177 switch (undo->type) {
178 case IDM_COPY:
179 case IDM_EXTRACT:
180 li->type = IDM_PERMDELETE;
181 break;
182 }
183 if (xbeginthread(MassAction,
184 122880,
185 wk,
186 pszSrcFile,
187 __LINE__) == -1)
188 {
189 FreeListInfo(wk->li);
190 free(wk);
191# ifdef FORTIFY
192 Fortify_LeaveScope();
193# endif
194 }
195 }
196 else
197 FreeListInfo(li);
198 }
199 }
200 break;
201 } // switch
202 }
203 FreeUndo();
204# ifdef FORTIFY
205 Fortify_LeaveScope();
206# endif
207}
208
209#endif // defined(UNDO)
210
211/**
212 * Apply action to file list
213 * Action repeated for each item in list
214 */
215
216VOID Action(VOID * args)
217{
218 WORKER *wk = (WORKER *)args;
219 HAB hab2;
220 HMQ hmq2;
221 CHAR **files = NULL;
222 INT plen = 0;
223 CHAR *p, *pp;
224 CHAR szQuotedDirName[CCHMAXPATH];
225 CHAR szQuotedFileName[CCHMAXPATH];
226
227
228 if (wk) {
229# ifdef FORTIFY
230 Fortify_EnterScope();
231# endif
232 if (wk->li && wk->li->list && wk->li->list[0]) {
233 hab2 = WinInitialize(0);
234 if (hab2) {
235 hmq2 = WinCreateMsgQueue(hab2, 0);
236 if (hmq2) {
237 CHAR message[(CCHMAXPATH * 2) + 80], wildname[CCHMAXPATH];
238 UINT x;
239 BOOL dontask = FALSE, wildcarding = FALSE, overold = FALSE;
240 BOOL overnew = FALSE, usedtarget;
241 BOOL noreadonlywarn = FALSE;
242
243 WinCancelShutdown(hmq2, TRUE);
244 IncrThreadUsage();
245 *wildname = 0;
246 // Do action specific preprocessing
247 switch (wk->li->type) {
248 case IDM_MERGE:
249 if (wk->li->type == IDM_MERGE) {
250 if (TestBinary(wk->li->list[0]))
251 wk->li->type = IDM_MERGEBINARY;
252 else
253 wk->li->type = IDM_MERGETEXT;
254 }
255 strcpy(wk->li->targetpath, wk->li->list[0]);
256 p = strrchr(wk->li->targetpath, '\\');
257 if (p) {
258 p++;
259 *p = 0;
260 }
261 else
262 strcat(wk->li->targetpath, PCSZ_BACKSLASH);
263 sprintf(wk->li->targetpath + strlen(wk->li->targetpath),
264 "MERGE.%03x", (clock() & 4095L));
265 if (!WinDlgBox(HWND_DESKTOP,
266 wk->hwndFrame,
267 MergeDlgProc, FM3ModHandle, MRG_FRAME, (PVOID) wk))
268 goto Abort;
269 if (!wk->li->type ||
270 !*wk->li->targetpath || !wk->li->list || !wk->li->list[0])
271 goto Abort;
272 if (IsFile(wk->li->targetpath) != 1 && !wk->li->list[1]) {
273 saymsg(MB_CANCEL | MB_ICONEXCLAMATION,
274 wk->hwndFrame,
275 GetPString(IDS_AHEMTEXT),
276 GetPString(IDS_SILLYMERGETEXT));
277 goto Abort;
278 }
279 break;
280 case IDM_WILDMOVE:
281 wildcarding = TRUE;
282 wk->li->type = IDM_MOVE;
283 break;
284 case IDM_WILDRENAME:
285 wildcarding = TRUE;
286 wk->li->type = IDM_RENAME;
287 break;
288 case IDM_WILDCOPY:
289 wildcarding = TRUE;
290 wk->li->type = IDM_COPY;
291 break;
292 case IDM_MOVEPRESERVE:
293 {
294 CHAR preserve[CCHMAXPATH], *end;
295
296 wk->li->type = IDM_MOVE;
297 strcpy(preserve, wk->li->list[0] + 2);
298 end = strrchr(preserve, '\\');
299 if (end) {
300 end++;
301 for (x = 1; wk->li->list[x]; x++) {
302 p = preserve;
303 pp = wk->li->list[x] + 2;
304 while (p < end && toupper(*p) == toupper(*pp)) {
305 p++;
306 pp++;
307 }
308 if (*p == '\\')
309 p++;
310 if (p < end)
311 end = p;
312 }
313 *end = 0;
314 }
315 else
316 *preserve = 0;
317 plen = strlen(preserve);
318 if (plen)
319 plen += 2;
320 }
321 break;
322 case IDM_COPYPRESERVE:
323 {
324 CHAR preserve[CCHMAXPATH], *end;
325
326 wk->li->type = IDM_COPY;
327 strcpy(preserve, wk->li->list[0] + 2);
328 end = strrchr(preserve, '\\');
329 if (end) {
330 end++;
331 for (x = 1; wk->li->list[x]; x++) {
332 p = preserve;
333 pp = wk->li->list[x] + 2;
334 while (p < end && toupper(*p) == toupper(*pp)) {
335 p++;
336 pp++;
337 }
338 if (*p == '\\')
339 p++;
340 if (p < end)
341 end = p;
342 }
343 *end = 0;
344 }
345 else
346 *preserve = 0;
347 plen = strlen(preserve);
348 if (plen)
349 plen += 2;
350 }
351 break;
352 }
353 // Process each list item
354 if (wk->li && wk->li->list && wk->li->list[0]) {
355 UINT cFilesModified = 0; // Required for AddToList
356 UINT cItemsAllocated = 0; // Required for AddToList
357 UINT cItemsInList;
358 for (cItemsInList = 0; wk->li->list[cItemsInList]; cItemsInList++); // Count
359 for (x = 0; wk->li->list[x]; x++) {
360 switch (wk->li->type) {
361 case IDM_COLLECTFROMFILE:
362 if (Collector) {
363
364 CHAR *temp = xstrdup(wk->li->list[x], pszSrcFile, __LINE__);
365
366 if (temp) {
367 if (!PostMsg(Collector,
368 UM_COLLECTFROMFILE, MPFROMP(temp), MPVOID))
369 free(temp);
370 }
371 }
372 break;
373
374 case IDM_MERGEBINARY:
375 case IDM_MERGETEXT:
376 case IDM_MERGEBINARYAPPEND:
377 case IDM_MERGETEXTAPPEND:
378 {
379 FILE *in, *out;
380 CHAR *moder, *modew;
381 int c;
382
383 switch (wk->li->type) {
384 case IDM_MERGEBINARY:
385 moder = "rb";
386 modew = "wb";
387 break;
388 case IDM_MERGEBINARYAPPEND:
389 moder = "rb";
390 modew = "a+b";
391 break;
392 case IDM_MERGETEXTAPPEND:
393 moder = "r";
394 modew = "a+";
395 break;
396 default:
397 moder = "r";
398 modew = "w";
399 break;
400 }
401 in = xfsopen(wk->li->list[x], moder, SH_DENYWR, pszSrcFile, __LINE__, TRUE);
402 if (!in) {
403 if (saymsg(MB_ENTERCANCEL,
404 HWND_DESKTOP,
405 GetPString(IDS_MERGEERRORTEXT),
406 GetPString(IDS_CANTOPENINPUTTEXT),
407 wk->li->list[x]) == MBID_CANCEL)
408 goto Abort;
409 }
410 else {
411 out = xfsopen(wk->li->targetpath, modew, SH_DENYWR,
412 pszSrcFile, __LINE__, TRUE);
413 if (out) {
414 fseek(out, 0L, SEEK_END);
415 switch (wk->li->type) {
416 case IDM_MERGEBINARY:
417 wk->li->type = IDM_MERGEBINARYAPPEND;
418 break;
419 default:
420 wk->li->type = IDM_MERGETEXTAPPEND;
421 break;
422 }
423 sprintf(message,
424 GetPString(IDS_MERGINGTEXT),
425 wk->li->list[x], wk->li->targetpath);
426 AddNote(message);
427 while ((c = fgetc(in)) != EOF)
428 fputc(c, out);
429 fclose(out);
430 sprintf(message,
431 GetPString(IDS_MERGECOMPLETETEXT),
432 wk->li->list[x], wk->li->targetpath);
433 AddNote(message);
434 }
435 else {
436 saymsg(MB_CANCEL,
437 HWND_DESKTOP,
438 GetPString(IDS_MERGEERRORTEXT),
439 GetPString(IDS_CANTOPENOUTPUTTEXT),
440 wk->li->targetpath);
441 fclose(in);
442 goto Abort;
443 }
444 fclose(in);
445 }
446 }
447 break;
448
449 case IDM_UUDECODE:
450 {
451 CHAR outname[CCHMAXPATH + 2];
452
453 sprintf(message,
454 GetPString(IDS_UUDECODINGTEXT), wk->li->list[x]);
455 AddNote(message);
456 if (UUD(wk->li->list[x], outname) && *outname) {
457 sprintf(message,
458 GetPString(IDS_UUDECODECOMPLETETEXT),
459 wk->li->list[x]);
460 AddNote(message);
461 if (//fSyncUpdates ||
462 AddToList(outname, &files, &cFilesModified, &cItemsAllocated))
463 Broadcast(hab2,
464 wk->hwndCnr,
465 UM_UPDATERECORD, MPFROMP(outname), MPVOID);
466 }
467 else {
468 sprintf(message,
469 GetPString(IDS_UUDECODEABORTEDTEXT),
470 wk->li->list[x]);
471 AddNote(message);
472 }
473 }
474 break;
475
476 case IDM_UNLOCKFILE:
477 if (IsFile(wk->li->list[x]) > 0 && fUnlock) {
478 runemf2(SEPARATE | INVISIBLE | BACKGROUND | WAIT,
479 HWND_DESKTOP, pszSrcFile, __LINE__,
480 NULL, NULL, "%s %s", PCSZ_UNLOCKEXE, wk->li->list[x]);
481 }
482 break;
483
484 case IDM_VIEWARCHIVE:
485 if (IsFile(wk->li->list[x]) > 0) {
486
487 ARC_TYPE *info = NULL; // Say calling for editing - fixme to know why?
488
489 if (WinDlgBox(HWND_DESKTOP,
490 wk->hwndFrame,
491 SBoxDlgProc,
492 FM3ModHandle,
493 ASEL_FRAME, (PVOID) & info) && info) {
494 WinSendMsg(wk->hwndCnr,
495 UM_OPENWINDOWFORME,
496 MPFROMP(wk->li->list[x]), MPFROMP(info));
497 }
498 }
499 break;
500
501 case IDM_EXTRACT:
502 {
503 EXTRDATA ex;
504 BOOL maskspaces = FALSE;
505 CHAR arcname[CCHMAXPATH];
506
507 memset(&ex, 0, sizeof(EXTRDATA));
508 ex.info = find_type(wk->li->list[x], NULL);
509 if (!ex.info || (!ex.info->extract && !ex.info->exwdirs))
510 break;
511 ex.size = sizeof(EXTRDATA);
512 BldQuotedFileName(arcname, wk->li->list[x]);
513 ex.arcname = arcname;
514 if (!*ex.masks)
515 strcpy(ex.masks, "*");
516 strcpy(ex.extractdir, wk->li->targetpath);
517 if (!WinDlgBox(HWND_DESKTOP,
518 wk->hwndFrame,
519 ExtractDlgProc,
520 FM3ModHandle,
521 EXT_FRAME,
522 (PVOID) & ex) ||
523 !ex.ret ||
524 !*ex.command || !*ex.arcname || !*ex.extractdir)
525 goto Abort;
526 {
527 FILESTATUS3 fsa;
528
529 DosError(FERR_DISABLEHARDERR);
530 if (DosQueryPathInfo(ex.extractdir,
531 FIL_STANDARD,
532 &fsa,
533 (ULONG) sizeof(FILESTATUS3)) ||
534 !(fsa.attrFile & FILE_DIRECTORY))
535 goto Abort;
536 }
537 if (needs_quoting(ex.masks) && !strchr(ex.masks, '\"'))
538 maskspaces = TRUE;
539 if (!runemf2(SEPARATE | WINDOWED | WAIT |
540 fArcStuffVisible ? 0 : (BACKGROUND | MINIMIZED),
541 HWND_DESKTOP, pszSrcFile, __LINE__, ex.extractdir, NULL,
542 "%s %s %s%s%s",
543 ex.command,
544 ex.arcname,
545 maskspaces ? "\"" : NullStr,
546 *ex.masks ? ex.masks : "\"*\"",
547 maskspaces ? "\"" : NullStr) &&
548 !stricmp(ex.extractdir, wk->directory)) {
549 DosSleep(100); // wait for runemf2 to complete so rescan will actually show something
550 if (WinIsWindow((HAB) 0, wk->hwndCnr))
551 WinSendMsg(wk->hwndCnr,
552 WM_COMMAND,
553 MPFROM2SHORT(IDM_RESCAN, 0), MPVOID);
554 }
555 }
556 break;
557
558 case IDM_SUBJECT:
559 {
560 INT ret;
561
562 ret = Subject(wk->hwndFrame, wk->li->list[x]);
563 if (!ret)
564 goto Abort;
565 if (ret == 1) {
566 if (//fSyncUpdates ||
567 AddToList(wk->li->list[x],
568 &files, &cFilesModified, &cItemsAllocated))
569 Broadcast(hab2,
570 wk->hwndCnr,
571 UM_UPDATERECORD,
572 MPFROMP(wk->li->list[x]), MPVOID);
573 }
574 }
575 break;
576
577 case IDM_INFO:
578 if (IsFullName(wk->li->list[x]) &&
579 !(driveflags[toupper(*wk->li->list[x]) - 'A'] &
580 DRIVE_INVALID)) {
581 if (!IsRoot(wk->li->list[x])) {
582
583 CHAR *list[2];
584
585 list[0] = wk->li->list[x];
586 list[1] = NULL;
587 if (!WinDlgBox(HWND_DESKTOP,
588 HWND_DESKTOP,
589 FileInfoProc,
590 FM3ModHandle, FLE_FRAME, (PVOID) list)) {
591 goto Abort;
592 }
593 }
594 else {
595 if (!WinDlgBox(HWND_DESKTOP,
596 HWND_DESKTOP,
597 DrvInfoProc,
598 FM3ModHandle,
599 INFO_FRAME, (PVOID) wk->li->list[x]))
600 goto Abort;
601 }
602 }
603 break;
604
605 case IDM_OPENWINDOW:
606 if (!IsFile(wk->li->list[x]) &&
607 WinIsWindow(hab2, wk->hwndCnr))
608 WinSendMsg(wk->hwndCnr,
609 UM_OPENWINDOWFORME,
610 MPFROMP(wk->li->list[x]), MPVOID);
611 break;
612
613 case IDM_OPENICON:
614 case IDM_OPENDETAILS:
615 case IDM_OPENTREE:
616 {
617 FILESTATUS3 fsa;
618
619 DosError(FERR_DISABLEHARDERR);
620 if (DosQueryPathInfo(wk->li->list[x],
621 FIL_STANDARD,
622 &fsa,
623 (ULONG) sizeof(FILESTATUS3)) ||
624 !(fsa.attrFile & FILE_DIRECTORY))
625 break;
626 }
627 // else intentional fallthru
628 case IDM_OPENDEFAULT:
629 case IDM_OPENSETTINGS:
630 {
631 CHAR *s;
632
633 switch (wk->li->type) {
634 case IDM_OPENICON:
635 s = (PSZ) PCSZ_ICON;
636 break;
637 case IDM_OPENDETAILS:
638 s = (PSZ) Details;
639 break;
640 case IDM_OPENTREE:
641 s = (PSZ) PCSZ_TREE;
642 break;
643 case IDM_OPENSETTINGS:
644 s = (PSZ) Settings;
645 break;
646 default:
647 s = (PSZ) Default;
648 break;
649 }
650 OpenObject(wk->li->list[x], s, wk->hwndFrame);
651 }
652 break;
653
654 case IDM_WPSMOVE:
655 case IDM_WPSCOPY:
656 case IDM_MOVE:
657 case IDM_COPY:
658 case IDM_RENAME:
659 {
660
661 // Select target
662 if (!*wk->li->targetpath && (wk->li->type == IDM_MOVE ||
663 wk->li->type == IDM_COPY ||
664 wk->li->type == IDM_WPSMOVE ||
665 wk->li->type == IDM_WPSCOPY)) {
666
667 APIRET rc = 1;
668 usedtarget = FALSE;
669 if (hwndMain) {
670 if (!*targetdir)
671 TopWindowName(hwndMain,
672 wk->hwndFrame, wk->li->targetpath);
673 else {
674 strcpy(wk->li->targetpath, targetdir);
675 usedtarget = TRUE;
676 }
677 }
678 if (!*wk->li->targetpath)
679 strcpy(wk->li->targetpath, wk->directory);
680 if (!*wk->li->targetpath) {
681 strcpy(wk->li->targetpath, wk->li->list[0]);
682 p = strrchr(wk->li->targetpath, '\\');
683 if (p) {
684 if (*(p - 1) == ':')
685 p++;
686 *p = 0;
687 }
688 }
689 MakeValidDir(wk->li->targetpath);
690 if (fConfirmTarget ||
691 (!*targetdir && strcmp(realappname, "FM/4"))) {
692 RetryPath:
693 // Confirm target
694 usedtarget = FALSE;
695 if (wk->li->type == IDM_MOVE ||
696 wk->li->type == IDM_WPSMOVE) {
697 rc = WinDlgBox(HWND_DESKTOP,
698 wk->hwndFrame,
699 WalkMoveDlgProc,
700 FM3ModHandle,
701 WALK_FRAME, MPFROMP(wk->li->targetpath));
702 }
703 else if (wk->li->type == IDM_COPY ||
704 wk->li->type == IDM_WPSCOPY) {
705 rc = WinDlgBox(HWND_DESKTOP,
706 wk->hwndFrame,
707 WalkCopyDlgProc,
708 FM3ModHandle,
709 WALK_FRAME, MPFROMP(wk->li->targetpath));
710 }
711 else
712 rc = WinDlgBox(HWND_DESKTOP,
713 wk->hwndFrame,
714 WalkDlgProc,
715 FM3ModHandle,
716 WALK_FRAME, MPFROMP(wk->li->targetpath));
717 }
718 if (!rc || !*wk->li->targetpath)
719 goto Abort;
720 // Check target OK
721 if (driveflags[toupper(*wk->li->targetpath) - 'A'] &
722 DRIVE_NOTWRITEABLE) {
723 saymsg(MB_CANCEL,
724 wk->hwndFrame,
725 GetPString(IDS_ERRORTEXT),
726 GetPString(IDS_NOTWRITENOTARGETTEXT));
727 goto RetryPath;
728 }
729 }
730 Retry:
731 {
732 // Target OK so far
733 CHAR newname[CCHMAXPATH];
734 APIRET rc;
735 INT ret;
736 FILESTATUS4L fs4;
737 BOOL isnewer;
738 BOOL existed;
739 BOOL fResetVerify = FALSE;
740 INT type = wk->li->type == IDM_RENAME ?
741 MOVE :
742 wk->li->type == IDM_MOVE ?
743 MOVE : (wk->li->type == IDM_WPSMOVE) ?
744 WPSMOVE : wk->li->type == IDM_WPSCOPY ?
745 WPSCOPY : COPY;
746 PCSZ moving = wk->li->type == IDM_RENAME ?
747 GetPString(IDS_RENAMINGTEXT) :
748 wk->li->type == IDM_MOVE || wk->li->type == IDM_WPSMOVE ?
749 GetPString(IDS_MOVINGTEXT) : GetPString(IDS_COPYINGTEXT);
750 PCSZ move = wk->li->type == IDM_RENAME ?
751 GetPString(IDS_RENAMETEXT) :
752 wk->li->type == IDM_MOVE ||
753 wk->li->type == IDM_WPSMOVE ?
754 GetPString(IDS_MOVETEXT) : GetPString(IDS_COPYTEXT);
755 PCSZ moved = wk->li->type == IDM_RENAME ?
756 GetPString(IDS_RENAMEDTEXT) :
757 wk->li->type == IDM_MOVE || wk->li->type == IDM_WPSMOVE ?
758 GetPString(IDS_MOVEDTEXT) : GetPString(IDS_COPIEDTEXT);
759
760 if (*wk->li->targetpath) {
761 strcpy(newname, wk->li->targetpath);
762 AddBackslashToPath(newname);
763 if (plen)
764 p = wk->li->list[x] + plen;
765 else {
766 p = strrchr(wk->li->list[x], '\\');
767 if (p)
768 p++;
769 else
770 p = wk->li->list[x];
771 }
772 strcat(newname, p);
773 }
774 else
775 strcpy(newname, wk->li->list[x]);
776 if ((wildcarding || wk->li->type == IDM_RENAME) &&
777 *wildname)
778 {
779 CHAR testname[CCHMAXPATH];
780 strcpy(testname, wildname);
781 if (AdjustWildcardName(newname, testname))
782 strcpy(newname, testname);
783 }
784 existed = IsFile(newname) != -1;
785 isnewer = IsNewer(wk->li->list[x], newname);
786 if (existed && wk->li->type != IDM_RENAME && dontask) {
787 if (!overold && !overnew)
788 break;
789 if (!overold && !isnewer)
790 break;
791 if (!overnew && isnewer)
792 break;
793 }
794 // Confirm overwrite unless bypassed
795 if ((wk->li->type == IDM_RENAME &&
796 (!dontask || !*wildname)) ||
797 (!dontask && existed) ||
798 (!dontask && wildcarding) ||
799 (IsFile(newname) == 0 && IsFile(wk->li->list[x]) > 0))
800 {
801 MOVEIT mv;
802 memset(&mv, 0, sizeof(MOVEIT));
803 mv.rename = (wk->li->type == IDM_RENAME);
804 mv.source = wk->li->list[x];
805 strcpy(mv.target, newname);
806 rc = WinDlgBox(HWND_DESKTOP,
807 wk->hwndFrame,
808 RenameProc,
809 FM3ModHandle, REN_FRAME, (PVOID) & mv);
810 if (!rc)
811 goto Abort;
812
813 DosSleep(1);
814 if (mv.skip || !*mv.target)
815 break;
816 if (mv.dontask)
817 dontask = TRUE;
818 if (mv.overold)
819 overold = TRUE;
820 if (mv.overnew)
821 overnew = TRUE;
822 if (mv.noreadonlywarn)
823 noreadonlywarn = TRUE;
824 if (wildcarding || wk->li->type == IDM_RENAME) {
825 p = strrchr(mv.target, '\\');
826 if (p && (strchr(p, '*') || strchr(p, '?'))) {
827 strcpy(wildname, mv.target);
828 AdjustWildcardName(wk->li->list[x], mv.target);
829 }
830 else
831 *wildname = 0;
832 }
833 strcpy(newname, mv.target);
834 existed = (IsFile(newname) != -1);
835 isnewer = IsNewer(wk->li->list[x], newname);
836 if (!mv.overwrite) {
837 if (existed && wk->li->type != IDM_RENAME && dontask) {
838 if (!overold && !overnew)
839 break;
840 if (!overold && !isnewer)
841 break;
842 if (!overnew && isnewer)
843 break;
844 }
845 }
846 }
847 if (!strcmp(wk->li->list[x], newname) ||
848 (wk->li->type == IDM_COPY &&
849 !stricmp(wk->li->list[x], newname)))
850 break;
851 sprintf(message,
852 " %s \"%s\" %s\"%s\"%s [%u %s%u]",
853 moving,
854 wk->li->list[x],
855 GetPString(IDS_TOTEXT), // Has trailing space
856 newname,
857 usedtarget ?
858 GetPString(IDS_TOTARGETTEXT) :
859 NullStr,
860 x + 1,
861 GetPString(IDS_OFTEXT), // Has trailing space
862 cItemsInList);
863 AddNote(message);
864 if (fVerify && (driveflags[toupper(*wk->li->targetpath) - 'A'] & DRIVE_WRITEVERIFYOFF) |
865 (driveflags[toupper(*wk->li->list[x]) - 'A'] & DRIVE_WRITEVERIFYOFF)) {
866 DosSetVerify(FALSE);
867 fResetVerify = TRUE;
868 }
869 if (plen) {
870 // make directory/ies, if required
871
872 CHAR dirpart[CCHMAXPATH];
873
874 strcpy(dirpart, newname);
875 p = strrchr(dirpart, '\\');
876 if (p) {
877 *p = 0;
878 if (p > dirpart + 3)
879 MassMkdir((hwndMain) ? hwndMain : wk->hwndCnr,
880 dirpart);
881 }
882 }
883 if (fRealIdle)
884 priority_idle();
885
886 rc = docopyf(type, wk->li->list[x], newname);
887 if (rc == ERROR_ACCESS_DENIED || rc == ERROR_SHARING_VIOLATION) {
888 ret = make_deleteable(newname, rc, noreadonlywarn);
889 if (ret == SM2_CANCEL)
890 break;
891 if (ret == SM2_DONTASK)
892 noreadonlywarn = TRUE;
893 if (ret == SM2_NO)
894 continue;
895 rc = docopyf(type, wk->li->list[x], newname);
896 }
897 if (rc == ERROR_ACCESS_DENIED || (rc == ERROR_SHARING_VIOLATION && fUnlock))
898 rc = NO_ERROR;
899 if (fResetVerify) {
900 DosSetVerify(fVerify);
901 fResetVerify = FALSE;
902 }
903 priority_normal();
904 if (rc) {
905 if ((rc == ERROR_DISK_FULL ||
906 rc == ERROR_HANDLE_DISK_FULL) &&
907 isalpha(*newname) &&
908 (driveflags[toupper(*newname) - 'A'] &
909 DRIVE_REMOVABLE)
910 && !(driveflags[toupper(*newname) - 'A'] &
911 DRIVE_NOTWRITEABLE)
912 && toupper(*newname) != toupper(*wk->li->list[x])
913 && !DosQueryPathInfo(wk->li->list[x], FIL_QUERYEASIZEL,
914 &fs4, sizeof(fs4))
915 && !(fs4.attrFile & FILE_DIRECTORY)) {
916
917 FSALLOCATE fsa;
918 ULONGLONG ullFreeBytes;
919 CHAR *ptr;
920 INT cntr;
921
922 Notify(GetPString(IDS_FITTINGTEXT));
923 DosError(FERR_DISABLEHARDERR);
924 if (!DosQueryFSInfo(toupper(*newname) - '@',
925 FSIL_ALLOC,
926 &fsa, sizeof(FSALLOCATE))) {
927 // Assume large file support
928 ullFreeBytes = (ULONGLONG) fsa.cUnitAvail * fsa.cSectorUnit *
929 fsa.cbSector;
930 if (ullFreeBytes) {
931 // Find item that will fit in available space
932 for (cntr = x + 1; wk->li->list[cntr]; cntr++) {
933 DosError(FERR_DISABLEHARDERR);
934 if (!DosQueryPathInfo(wk->li->list[cntr],
935 FIL_QUERYEASIZEL,
936 &fs4,
937 sizeof(fs4)) &&
938 !(fs4.attrFile & FILE_DIRECTORY) &&
939 // fixme to use CBLIST_TO_EASIZE?
940 fs4.cbFile + fs4.cbList <= ullFreeBytes) {
941 // Swap with failing item
942 ptr = wk->li->list[x];
943 wk->li->list[x] = wk->li->list[cntr];
944 wk->li->list[cntr] = ptr;
945 goto Retry;
946 }
947 }
948 Notify(GetPString(IDS_COULDNTFITTEXT));
949 }
950 }
951 rc = saymsg(MB_ABORTRETRYIGNORE | MB_ICONEXCLAMATION,
952 wk->hwndFrame,
953 GetPString(IDS_DISKFULLTEXT),
954 GetPString(IDS_ANOTHERDISKTEXT));
955 if (rc == MBID_RETRY)
956 goto Retry;
957 if (rc == MBID_ABORT)
958 goto Abort;
959 }
960 else {
961 if (LogFileHandle) {
962 fprintf(LogFileHandle,
963 GetPString(IDS_LOGTOFAILEDTEXT),
964 move, wk->li->list[x], newname, rc);
965 }
966 rc = Dos_Error(MB_ENTERCANCEL,
967 rc,
968 wk->hwndFrame,
969 pszSrcFile,
970 __LINE__,
971 "%s %s\"%s\" %s\"%s\" %s.",
972 move, // move, copy, rename etc.
973 GetPString(IDS_OFTEXT), // "of " - note trailing space
974 wk->li->list[x],
975 GetPString(IDS_TOTEXT), // "to "
976 newname, GetPString(IDS_FAILEDTEXT)); // "failed"
977 if (rc == MBID_CANCEL)
978 goto Abort;
979 }
980 }
981 else {
982 if (LogFileHandle) {
983 fprintf(LogFileHandle,
984 "%s \"%s\" %s\"%s\"\n",
985 moved,
986 wk->li->list[x],
987 GetPString(IDS_TOTEXT), newname);
988 }
989 if (!strcmp(realappname, "FM/4") ||
990 ((driveflags[*wk->li->targetpath - 'A'] & DRIVE_RSCANNED) &&
991 AddToList(wk->li->list[x],
992 &files, &cFilesModified, &cItemsAllocated)))
993 Broadcast(hab2,
994 wk->hwndCnr,
995 UM_UPDATERECORD,
996 MPFROMP(wk->li->list[x]), MPVOID);
997 if (!strcmp(realappname, "FM/4") ||
998 (driveflags[*wk->li->targetpath - 'A'] & DRIVE_RSCANNED) &&
999 AddToList(newname, &files, &cFilesModified, &cItemsAllocated))
1000 Broadcast(hab2,
1001 wk->hwndCnr,
1002 UM_UPDATERECORD, MPFROMP(newname), MPVOID);
1003 }
1004 }
1005 break;
1006 }
1007
1008 case IDM_COMPARE:
1009 if ((!IsFile(wk->li->targetpath) ||
1010 IsRoot(wk->li->targetpath)) &&
1011 (!IsFile(wk->li->list[x]) || IsRoot(wk->li->list[x]))) {
1012 if (!*dircompare && WinIsWindow(hab2, wk->hwndCnr))
1013 WinSendMsg(wk->hwndCnr,
1014 UM_COMPARE,
1015 MPFROMP(wk->li->targetpath),
1016 MPFROMP(wk->li->list[x]));
1017 else {
1018 runemf2(SEPARATE,
1019 HWND_DESKTOP, pszSrcFile, __LINE__,
1020 NULL, NULL,
1021 "%s %s %s",
1022 dircompare,
1023 BldQuotedFileName(szQuotedDirName, wk->li->targetpath),
1024 BldQuotedFileName(szQuotedFileName, wk->li->list[x]));
1025 }
1026 }
1027 else if (*compare) {
1028 CHAR *fakelist[3];
1029
1030 fakelist[0] = wk->li->list[x];
1031 fakelist[1] = wk->li->targetpath;
1032 fakelist[2] = NULL;
1033 ExecOnList(wk->hwndFrame,
1034 compare,
1035 WINDOWED | SEPARATEKEEP, NULL, NULL, fakelist, NULL,
1036 pszSrcFile, __LINE__);
1037 }
1038 else {
1039 FCOMPARE fc;
1040
1041 memset(&fc, 0, sizeof(fc));
1042 fc.size = sizeof(fc);
1043 fc.hwndParent = wk->hwndParent;
1044 strcpy(fc.file1, wk->li->list[x]);
1045 strcpy(fc.file2, wk->li->targetpath);
1046 if (WinDlgBox(HWND_DESKTOP,
1047 wk->hwndFrame,
1048 CFileDlgProc,
1049 FM3ModHandle, FCMP_FRAME, (PVOID) & fc))
1050 goto Abort;
1051 }
1052 break;
1053 } // switch
1054 DosSleep(0);
1055 } // for list
1056
1057 // Do action specific post-processing
1058 switch (wk->li->type) {
1059 case IDM_MOVE:
1060 case IDM_COPY:
1061 case IDM_WPSMOVE:
1062 case IDM_WPSCOPY:
1063 case IDM_RENAME:
1064 sprintf(message,
1065 GetPString(IDS_OPSCOMPLETETEXT),
1066 wk->li->type == IDM_MOVE ?
1067 GetPString(IDS_MOVETEXT) :
1068 wk->li->type == IDM_COPY ?
1069 GetPString(IDS_COPYTEXT) :
1070 wk->li->type == IDM_WPSMOVE ?
1071 GetPString(IDS_WPSMOVETEXT) :
1072 wk->li->type == IDM_WPSCOPY ?
1073 GetPString(IDS_WPSCOPYTEXT) :
1074 GetPString(IDS_RENAMETEXT),
1075 &"s"[x == 1], // s or nul
1076 (wk->li->type == IDM_MOVE ||
1077 wk->li->type == IDM_COPY ||
1078 wk->li->type == IDM_WPSMOVE ||
1079 wk->li->type == IDM_WPSCOPY) ?
1080 GetPString(IDS_TOTEXT) : NullStr,
1081 (wk->li->type == IDM_MOVE ||
1082 wk->li->type == IDM_COPY ||
1083 wk->li->type == IDM_WPSMOVE ||
1084 wk->li->type == IDM_WPSCOPY) ?
1085 wk->li->targetpath : NullStr,
1086 GetPString(x != 1 ? IDS_ARETEXT : IDS_ISTEXT));
1087 Notify(message);
1088 if (toupper(*wk->li->targetpath) < 'C' && !fAlertBeepOff)
1089 DosBeep(1000, 25); // Wake up user
1090 DosSleep(16);//05 Aug 07 GKY 33
1091 if (wk->li->type == IDM_WPSMOVE || wk->li->type == IDM_WPSCOPY)
1092 DosSleep(48);//05 Aug 07 GKY 96
1093 break;
1094 default:
1095 break;
1096 }
1097 } // if have non-empty list
1098
1099 Abort:
1100
1101 if (files) {
1102 if (!strcmp(realappname, "FM/4") || !hwndTree ||
1103 (driveflags[*wk->li->targetpath - 'A'] & DRIVE_RSCANNED))
1104 Broadcast(hab2,
1105 wk->hwndCnr,
1106 UM_UPDATERECORDLIST, MPFROMP(files), MPVOID);
1107 FreeList(files);
1108 }
1109
1110 if (WinIsWindow(hab2, wk->hwndCnr))
1111 PostMsg(wk->hwndCnr, UM_RESCAN, MPVOID, MPVOID);
1112
1113 WinDestroyMsgQueue(hmq2);
1114 } // if queue
1115 DecrThreadUsage();
1116 WinTerminate(hab2);
1117 } // if hab2
1118 } // if list not empty
1119
1120 if (wk->li)
1121 FreeListInfo(wk->li);
1122 free(wk);
1123# ifdef FORTIFY
1124 Fortify_LeaveScope();
1125# endif
1126 DosPostEventSem(CompactSem);
1127 }
1128}
1129
1130/**
1131 * Apply file list to action
1132 * All items in list processed as a group, if possible
1133 */
1134
1135VOID MassAction(VOID * args)
1136{
1137 WORKER *wk = (WORKER *) args;
1138 HAB hab2;
1139 HMQ hmq2;
1140 CHAR **files = NULL;
1141 CHAR *p, *pp;
1142 UINT numfiles = 0, numalloc = 0;
1143
1144
1145 if (wk) {
1146# ifdef FORTIFY
1147 // Fortify_BecomeOwner(wk);
1148 Fortify_EnterScope();
1149# endif
1150 if (wk->li && wk->li->list && wk->li->list[0]) {
1151 hab2 = WinInitialize(0);
1152 if (hab2) {
1153 hmq2 = WinCreateMsgQueue(hab2, 0);
1154 if (hmq2) {
1155 WinCancelShutdown(hmq2, TRUE);
1156 IncrThreadUsage();
1157 DosError(FERR_DISABLEHARDERR);
1158 if (IsRoot(wk->li->list[0]) || !IsFile(wk->li->list[0])) {
1159 if (wk->li->type == IDM_VIEW)
1160 wk->li->type = IDM_INFO;
1161 if (wk->li->type == IDM_EDIT)
1162 wk->li->type = IDM_EAS;
1163 }
1164 switch (wk->li->type) {
1165 case IDM_INFO:
1166 if (WinDlgBox(HWND_DESKTOP,
1167 wk->hwndFrame,
1168 FileInfoProc,
1169 FM3ModHandle, FLE_FRAME, (PVOID) wk->li->list) != 2)
1170 {
1171 break;
1172 }
1173 // else intentional fallthru
1174 case IDM_UPDATE:
1175 Broadcast(hab2,
1176 wk->hwndCnr,
1177 UM_UPDATERECORDLIST, MPFROMP(wk->li->list), MPVOID);
1178 break;
1179
1180 case IDM_EAS:
1181 if (WinDlgBox(HWND_DESKTOP,
1182 wk->hwndFrame,
1183 DisplayEAsProc,
1184 FM3ModHandle, EA_FRAME, (PVOID) wk->li->list))
1185 Broadcast(hab2,
1186 wk->hwndCnr,
1187 UM_UPDATERECORDLIST, MPFROMP(wk->li->list), MPVOID);
1188 break;
1189
1190 case IDM_DOITYOURSELF:
1191 ExecOnList(wk->hwndFrame,
1192 "%a",
1193 WINDOWED | SEPARATE | PROMPT, NULL,
1194 NULL, wk->li->list, GetPString(IDS_DOITYOURSELFTEXT),
1195 pszSrcFile, __LINE__);
1196 break;
1197
1198 case IDM_MCIPLAY:
1199 {
1200 UINT x;
1201 UINT MaxFM2playStrLen = 24;
1202 ULONG total;
1203 CHAR fbuf[CCHMAXPATH];
1204
1205 if (DosSearchPath(SEARCH_IGNORENETERRS | SEARCH_ENVIRONMENT |
1206 SEARCH_CUR_DIRECTORY,
1207 (CHAR *) PCSZ_PATH, (CHAR *) PCSZ_FM2PLAYEXE, (PBYTE)fbuf, CCHMAXPATH - 1))
1208 total += MaxFM2playStrLen;
1209 else
1210 total = strlen(fbuf);
1211 for (x = 0; wk->li->list[x]; x++)
1212 total += (strlen(wk->li->list[x]) + 1 +
1213 (needs_quoting(wk->li->list[x]) * 2));
1214 if (total > 1000) {
1215
1216 FILE *fp;
1217 CHAR szTempFile[CCHMAXPATH];
1218 CHAR *modew = "w";
1219
1220 if (pTmpDir && !IsValidDir(pTmpDir))
1221 DosCreateDir(pTmpDir, 0);
1222 BldFullPathName(szTempFile, pTmpDir, PCSZ_FM2PLAYTEMP);
1223 fp = xfopen(szTempFile, modew, pszSrcFile, __LINE__, FALSE);
1224 if (fp) {
1225 fprintf(fp, "%s", ";AV/2-built FM2Play listfile\n");
1226 for (x = 0; wk->li->list[x]; x++)
1227 fprintf(fp, "%s\n", wk->li->list[x]);
1228 fprintf(fp, ";end\n");
1229 fclose(fp);
1230 strrev(szTempFile);
1231 strcat(szTempFile, "@/");
1232 strrev(szTempFile);
1233 RunFM2Util(PCSZ_FM2PLAYEXE, szTempFile);
1234 }
1235 }
1236 }
1237 // intentional fallthru
1238 case IDM_FAKEEXTRACT:
1239 case IDM_FAKEEXTRACTM:
1240 if (wk->li->type == IDM_MCIPLAY ||
1241 (*wk->li->arcname && wk->li->info &&
1242 wk->li->info->extract && *wk->li->targetpath)) {
1243
1244 CHAR szBuffer[1025];
1245 CHAR fbuf[CCHMAXPATH];
1246 UINT x;
1247
1248 if (wk->li->type == IDM_FAKEEXTRACT ||
1249 wk->li->type == IDM_FAKEEXTRACTM) {
1250 strcpy(szBuffer,
1251 (wk->li->info->exwdirs) ?
1252 wk->li->info->exwdirs : wk->li->info->extract);
1253 strcat(szBuffer, " ");
1254 BldQuotedFileName(szBuffer + strlen(szBuffer), wk->li->arcname);
1255 }
1256 else {
1257 if (DosSearchPath(SEARCH_IGNORENETERRS | SEARCH_ENVIRONMENT |
1258 SEARCH_CUR_DIRECTORY,
1259 (CHAR *) PCSZ_PATH, (CHAR *) PCSZ_FM2PLAYEXE, (PBYTE)fbuf, CCHMAXPATH - 1))
1260 strcpy(szBuffer, "UTILS\\FM2PLAY.EXE");
1261 else
1262 strcpy(szBuffer, PCSZ_FM2PLAYEXE);
1263 }
1264 p = &szBuffer[strlen(szBuffer)];
1265 strcat(szBuffer, " ");
1266 x = 0;
1267 while (wk->li->list[x]) {
1268 pp = wk->li->list[x];
1269 while (*pp) {
1270 if (*pp == '/')
1271 *pp = '\\';
1272 pp++;
1273 }
1274 BldQuotedFileName(szBuffer + strlen(szBuffer), wk->li->list[x]);
1275 x++;
1276 if (!wk->li->list[x] || strlen(szBuffer) +
1277 strlen(wk->li->list[x]) + 5 > 1024) {
1278 runemf2(SEPARATE | WINDOWED | BACKGROUND | MINIMIZED | WAIT,
1279 HWND_DESKTOP, pszSrcFile, __LINE__,
1280 (wk->li->type == IDM_FAKEEXTRACT ||
1281 wk->li->type == IDM_FAKEEXTRACTM) ?
1282 wk->li->targetpath : NULL,
1283 NULL,
1284 "%s", szBuffer);
1285 DosSleep(1);
1286 *p = 0;
1287 }
1288 strcat(szBuffer, " ");
1289 }
1290 if (wk->li->type == IDM_MCIPLAY)
1291 break;
1292 strcpy(szBuffer, wk->li->targetpath);
1293 AddBackslashToPath(wk->li->targetpath);
1294 //if (wk->li->targetpath[strlen(wk->li->targetpath) - 1] != '\\')
1295 // strcat(szBuffer, "\\");
1296 p = szBuffer + strlen(szBuffer);
1297 for (x = 0; wk->li->list[x]; x++) {
1298 strcpy(p, wk->li->list[x]);
1299 free(wk->li->list[x]);
1300 wk->li->list[x] = xstrdup(szBuffer, pszSrcFile, __LINE__);
1301 }
1302 if (wk->li->list[0])
1303 Broadcast(hab2,
1304 wk->hwndCnr,
1305 UM_UPDATERECORDLIST, MPFROMP(wk->li->list), MPVOID);
1306 }
1307 break;
1308
1309 case IDM_SETICON:
1310 if (*wk->li->targetpath) {
1311
1312 ICONINFO ici;
1313
1314 memset(&ici, 0, sizeof(ICONINFO));
1315 ici.cb = sizeof(ICONINFO);
1316 ici.fFormat = ICON_FILE;
1317 ici.pszFileName = wk->li->list[0];
1318 if (!WinSetFileIcon((PSZ) wk->li->targetpath,
1319 (PICONINFO) & ici)) {
1320 ici.fFormat = ICON_CLEAR;
1321 WinSetFileIcon((PSZ) wk->li->targetpath, (PICONINFO) & ici);
1322 }
1323 Broadcast(hab2,
1324 wk->hwndCnr,
1325 UM_UPDATERECORD, MPFROMP(wk->li->targetpath), MPVOID);
1326 }
1327 break;
1328
1329 case IDM_APPENDTOCLIP:
1330 case IDM_SAVETOCLIP:
1331 case IDM_SAVETOCLIPFILENAME:
1332 case IDM_APPENDTOCLIPFILENAME:
1333 ListToClipboardHab(hab2,
1334 wk->li->list,
1335 wk->li->type);
1336 break;
1337
1338 case IDM_ARCHIVEM:
1339 case IDM_ARCHIVE:
1340 {
1341 DIRCNRDATA ad;
1342 CHAR szBuffer[1025];
1343 ARC_TYPE *info = NULL;
1344 char *pch;
1345 UINT x;
1346
1347 memset(&ad, 0, sizeof(DIRCNRDATA));
1348 strcpy(ad.arcname, wk->li->targetpath);
1349 if (*wk->li->targetpath && IsFile(wk->li->targetpath) > 0) {
1350 info = find_type(wk->li->targetpath, NULL);
1351 ad.namecanchange = 0;
1352 }
1353 else {
1354 if (*wk->li->targetpath && !IsFile(wk->li->targetpath))
1355 AddBackslashToPath(wk->li->targetpath);
1356 ad.namecanchange = 1;
1357 }
1358 strcpy(ad.arcname, wk->li->targetpath);
1359 if (wk->li->type == IDM_ARCHIVEM)
1360 ad.fmoving = TRUE;
1361 if (!info) {
1362 ad.info = arcsighead; // Hide dups
1363 if (!WinDlgBox(HWND_DESKTOP,
1364 wk->hwndFrame,
1365 SBoxDlgProc,
1366 FM3ModHandle,
1367 ASEL_FRAME, (PVOID) & ad.info) || !ad.info) {
1368 break; // we blew it
1369 }
1370 }
1371 else
1372 ad.info = info;
1373 if (!ad.info || (!ad.info->create &&
1374 !ad.info->move &&
1375 !ad.info->createwdirs &&
1376 !ad.info->movewdirs &&
1377 !ad.info->createrecurse))
1378 break;
1379 if (!*wk->li->targetpath && *wk->directory) {
1380 strcpy(ad.arcname, wk->directory);
1381 AddBackslashToPath(ad.arcname);
1382 }
1383 if (!WinDlgBox(HWND_DESKTOP, wk->hwndFrame, ArchiveDlgProc, FM3ModHandle,
1384 ARCH_FRAME, (PVOID) & ad) || !*ad.arcname || !*ad.command) // we blew it
1385 break;
1386 // Provide extension so containers work
1387 pch = strrchr(ad.arcname, '\\');
1388 if (pch)
1389 pch = strrchr(pch, '.');
1390 else
1391 pch = strrchr(ad.arcname, '.');
1392 if (!pch && ad.info->ext) {
1393 strcat(ad.arcname, ".");
1394 strcat(ad.arcname, ad.info->ext);
1395 }
1396 // build the sucker
1397 strcpy(szBuffer, ad.command);
1398 strcat(szBuffer, " ");
1399 BldQuotedFileName(szBuffer + strlen(szBuffer), ad.arcname);
1400 p = &szBuffer[strlen(szBuffer)];
1401 if (ad.mask.szMask) {
1402 strcat(szBuffer, " ");
1403 strcat(szBuffer, ad.mask.szMask);
1404 }
1405 strcat(szBuffer, " ");
1406 x = 0;
1407 while (wk->li->list[x]) {
1408 FILESTATUS3 fsa;
1409 memset(&fsa, 0, sizeof(FILESTATUS3));
1410 DosError(FERR_DISABLEHARDERR);
1411 DosQueryPathInfo(wk->li->list[x],
1412 FIL_STANDARD,
1413 &fsa, (ULONG) sizeof(FILESTATUS3));
1414 if (fsa.attrFile & FILE_DIRECTORY) {
1415 BldQuotedFullPathName(szBuffer + strlen(szBuffer), wk->li->list[x], "*");
1416 }
1417 else
1418 BldQuotedFileName(szBuffer + strlen(szBuffer), wk->li->list[x]);
1419 x++;
1420 if (!wk->li->list[x] ||
1421 strlen(szBuffer) + strlen(wk->li->list[x]) + 5 > 1024) {
1422 runemf2(SEPARATE | WINDOWED | WAIT |
1423 (fArcStuffVisible ? 0 : (BACKGROUND | MINIMIZED)),
1424 HWND_DESKTOP, pszSrcFile, __LINE__, NULL, NULL,
1425 "%s", szBuffer);
1426 DosSleep(1);
1427 *p = 0;
1428 }
1429 strcat(szBuffer, " ");
1430 }
1431 Broadcast(hab2,
1432 wk->hwndCnr,
1433 UM_UPDATERECORDLIST, MPFROMP(wk->li->list), MPVOID);
1434 Broadcast(hab2,
1435 wk->hwndCnr,
1436 UM_UPDATERECORD, MPFROMP(ad.arcname), MPVOID);
1437 }
1438 break;
1439
1440 case IDM_VIEW:
1441 if (!TestBinary(wk->li->list[0])) {
1442 wk->li->type = IDM_VIEWTEXT;
1443 goto SkipViewing;
1444 }
1445 else
1446 wk->li->type = IDM_VIEWBINARY;
1447 // intentional fallthru
1448 case IDM_VIEWBINARY:
1449 if (*binview) {
1450 ExecOnList((HWND) 0,
1451 binview,
1452 WINDOWED | SEPARATE, NULL, NULL, wk->li->list, NULL,
1453 pszSrcFile, __LINE__);
1454 break;
1455 }
1456 // else intentional fallthru
1457 case IDM_VIEWTEXT:
1458 SkipViewing:
1459 if (*viewer)
1460 ExecOnList((HWND) 0, viewer,
1461 WINDOWED | SEPARATE |
1462 ((fViewChild) ? CHILD : 0),
1463 NULL, NULL, wk->li->list, NULL,
1464 pszSrcFile, __LINE__);
1465 else {
1466
1467 CHAR *temp;
1468 UINT x;
1469 ULONG viewtype;
1470
1471 viewtype = (wk->li->type == IDM_VIEWTEXT) ? 8 :
1472 (wk->li->type == IDM_VIEWBINARY) ? 16 : 0;
1473 for (x = 0; wk->li->list[x]; x++) {
1474 temp = xstrdup(wk->li->list[x], pszSrcFile, __LINE__);
1475 if (temp && WinIsWindow(hab2, wk->hwndCnr)) {
1476 if (!PostMsg(wk->hwndCnr,
1477 UM_LOADFILE,
1478 MPFROMLONG(5 + viewtype), MPFROMP(temp)))
1479 free(temp);
1480 }
1481 DosSleep(1);
1482 }
1483 }
1484 break;
1485
1486 case IDM_EDIT:
1487 if (!TestBinary(wk->li->list[0])) {
1488 wk->li->type = IDM_EDITTEXT;
1489 goto SkipEditing;
1490 }
1491 else
1492 wk->li->type = IDM_EDITBINARY;
1493 // intentional fallthru
1494 case IDM_EDITBINARY:
1495 if (*bined) {
1496 ExecOnList((HWND) 0,
1497 bined,
1498 WINDOWED | SEPARATE, NULL, NULL, wk->li->list, NULL,
1499 pszSrcFile, __LINE__);
1500 break;
1501 }
1502 // else intentional fallthru
1503 case IDM_EDITTEXT:
1504 SkipEditing:
1505 if (*editor)
1506 ExecOnList((HWND) 0,
1507 editor,
1508 WINDOWED | SEPARATE, NULL, NULL, wk->li->list, NULL,
1509 pszSrcFile, __LINE__);
1510 else {
1511
1512 CHAR *temp;
1513 UINT x;
1514 ULONG viewtype;
1515
1516 viewtype = (wk->li->type == IDM_EDITTEXT) ? 8 :
1517 (wk->li->type == IDM_EDITBINARY) ? 16 : 0;
1518 for (x = 0; wk->li->list[x]; x++) {
1519 temp = xstrdup(wk->li->list[x], pszSrcFile, __LINE__);
1520 if (temp && WinIsWindow(hab2, wk->hwndCnr)) {
1521 if (!PostMsg(wk->hwndCnr,
1522 UM_LOADFILE,
1523 MPFROMLONG(4 + viewtype), MPFROMP(temp)))
1524 free(temp);
1525 }
1526 DosSleep(1);
1527 }
1528 }
1529 break;
1530
1531 case IDM_SHADOW2:
1532 case IDM_OBJECT:
1533 case IDM_SHADOW:
1534 {
1535 CHAR objectpath[CCHMAXPATH];
1536 APIRET rc;
1537
1538 if (!*wk->li->targetpath || IsFile(wk->li->targetpath)) {
1539 GetDesktopName(objectpath, sizeof(objectpath));
1540 rc = WinDlgBox(HWND_DESKTOP,
1541 wk->hwndFrame,
1542 ObjCnrDlgProc,
1543 FM3ModHandle,
1544 OBJCNR_FRAME, MPFROMP(objectpath));
1545 if (rc) {
1546 if (rc > 1)
1547 strcpy(objectpath, "<WP_DESKTOP>");
1548 }
1549 else
1550 break;
1551 }
1552 else
1553 strcpy(objectpath, wk->li->targetpath);
1554 AddNote(GetPString(IDS_MAKINGOBJSTEXT));
1555 MakeShadows(wk->hwndFrame,
1556 wk->li->list,
1557 (wk->li->type == IDM_SHADOW) +
1558 (wk->li->type == IDM_SHADOW2) * 2,
1559 objectpath, NULL);
1560 AddNote(GetPString(IDS_MADEOBJSTEXT));
1561 }
1562 break;
1563
1564 case IDM_PRINT:
1565 if (WinDlgBox(HWND_DESKTOP,
1566 wk->hwndFrame,
1567 PrintDlgProc,
1568 FM3ModHandle, PRN_FRAME, MPFROMP(wk->li))) {
1569 if (wk->li && wk->li->list && wk->li->list[0]) {
1570 strcpy(wk->li->targetpath, printer);
1571 if (xbeginthread(PrintListThread,
1572 65536,
1573 wk->li,
1574 pszSrcFile,
1575 __LINE__) != -1)
1576 {
1577 wk->li = NULL; // prevent LISTINFO li from being freed here
1578 }
1579 }
1580 }
1581 break;
1582
1583 case IDM_ATTRS:
1584 if (WinDlgBox(HWND_DESKTOP,
1585 wk->hwndFrame,
1586 AttrListDlgProc,
1587 FM3ModHandle, ATR_FRAME, MPFROMP(wk->li))) {
1588 if (wk->li && wk->li->list && wk->li->list[0])
1589 Broadcast(hab2,
1590 wk->hwndCnr,
1591 UM_UPDATERECORDLIST, MPFROMP(wk->li->list), MPVOID);
1592 }
1593 break;
1594
1595 case IDM_PERMDELETE:
1596 case IDM_DELETE:
1597 {
1598 CHECKLIST cl;
1599 INT isdir = 0, sysdir = 0, ro = 0, hs = 0;
1600 UINT x;
1601 FILESTATUS3 fsa;
1602 CHAR prompt[CCHMAXPATH * 3];
1603 APIRET error = 0, rc;
1604 HOBJECT hObjectdest, hObjectofObject;
1605 BYTE G_abSupportedDrives[24] = {0};
1606 ULONG cbSupportedDrives = sizeof(G_abSupportedDrives);
1607 INT retrn = 0;
1608
1609 for (x = 0; wk->li->list[x]; x++) {
1610 if (IsRoot(wk->li->list[x])) {
1611 wk->li->list = RemoveFromList(wk->li->list,
1612 wk->li->list[x]);
1613 if (!wk->li->list)
1614 break;
1615 x--;
1616 continue;
1617 }
1618 DosError(FERR_DISABLEHARDERR);
1619 if (DosQueryPathInfo(wk->li->list[x],
1620 FIL_STANDARD, &fsa,
1621 (ULONG) sizeof(FILESTATUS3))) {
1622 wk->li->list = RemoveFromList(wk->li->list,
1623 wk->li->list[x]);
1624 if (!wk->li->list)
1625 break;
1626 x--;
1627 continue;
1628 }
1629 if (fsa.attrFile & FILE_DIRECTORY) {
1630 isdir++;
1631 if (stristr(wk->li->list[x], ":\\OS2\\") ||
1632 !stricmp(wk->li->list[x] + 1, ":\\OS2"))
1633 sysdir++;
1634 }
1635 else {
1636 if (fsa.attrFile & (FILE_HIDDEN | FILE_SYSTEM))
1637 hs++;
1638 if (fsa.attrFile & FILE_READONLY)
1639 ro++;
1640 }
1641 }
1642 if (!wk->li->list)
1643 break;
1644 if (fConfirmDelete || isdir || hs || ro) {
1645 memset(&cl, 0, sizeof(cl));
1646 cl.size = sizeof(cl);
1647 cl.list = wk->li->list;
1648 cl.prompt = prompt;
1649 cl.flags |= CHECK_FILES;
1650 cl.cmd = wk->li->type;
1651 sprintf(prompt,
1652 GetPString(IDS_DELPROMPT1TEXT),
1653 (wk->li->type == IDM_DELETE) ?
1654 NullStr :
1655 GetPString(IDS_PERMANENTLYTEXT),
1656 &"s"[wk->li->list[1] == NULL]);
1657 if (isdir) {
1658 sprintf(&prompt[strlen(prompt)],
1659 GetPString(IDS_DELPROMPT2TEXT),
1660 isdir,
1661 (isdir > 1) ?
1662 GetPString(IDS_ARETEXT) :
1663 GetPString(IDS_ISTEXT),
1664 (isdir == 1) ?
1665 GetPString(IDS_ATEXT) :
1666 NullStr,
1667 (isdir > 1) ?
1668 GetPString(IDS_IESTEXT) : GetPString(IDS_YTEXT));
1669 if (sysdir)
1670 sprintf(&prompt[strlen(prompt)],
1671 GetPString(IDS_DELPROMPT3TEXT),
1672 sysdir,
1673 (sysdir == 1) ?
1674 GetPString(IDS_YTEXT) : GetPString(IDS_IESTEXT));
1675 }
1676 if (ro)
1677 sprintf(&prompt[strlen(prompt)],
1678 GetPString(IDS_DELPROMPT4TEXT),
1679 ro,
1680 &"s"[ro == 1],
1681 (ro > 1) ?
1682 GetPString(IDS_ARETEXT) : GetPString(IDS_ISTEXT));
1683 if (hs)
1684 sprintf(&prompt[strlen(prompt)],
1685 GetPString(IDS_DELPROMPT5TEXT),
1686 hs,
1687 &"s"[hs == 1],
1688 (hs > 1) ?
1689 GetPString(IDS_ARETEXT) : GetPString(IDS_ISTEXT));
1690 if ((ro || hs || sysdir) && !fAlertBeepOff)
1691 DosBeep(300, 100); // Wake up user
1692 strcat(prompt, GetPString(IDS_DELPROMPT6TEXT));
1693 error = WinDlgBox(HWND_DESKTOP,
1694 wk->hwndFrame,
1695 CheckListProc,
1696 FM3ModHandle, CHECK_FRAME, MPFROMP(&cl));
1697 if (!error || error == 65535)
1698 break;
1699 wk->li->list = cl.list;
1700 if (!wk->li->list || !wk->li->list[0])
1701 break;
1702 }
1703 if (fVerify && driveflags[toupper(*wk->li->list[0]) - 'A'] & DRIVE_WRITEVERIFYOFF)
1704 DosSetVerify(FALSE);
1705 DosRequestMutexSem(hmtxFM2Delete, SEM_INDEFINITE_WAIT); // Prevent race 12-3-08 GKY
1706 for (x = 0; wk->li->list[x]; x++) {
1707 fsa.attrFile = 0;
1708 DosError(FERR_DISABLEHARDERR);
1709 DosQueryPathInfo(wk->li->list[x],
1710 FIL_STANDARD,
1711 &fsa, (ULONG) sizeof(FILESTATUS3));
1712 if (fsa.attrFile & FILE_DIRECTORY) {
1713 error = (APIRET) wipeallf(ignorereadonly, "%s%s*",
1714 wk->li->list[x],
1715 (*wk->li->list[x] &&
1716 wk->li->
1717 list[x][strlen(wk->li->list[x]) - 1]
1718 != '\\') ? PCSZ_BACKSLASH : NullStr);
1719 DosError(FERR_DISABLEHARDERR);
1720 if (!error)
1721 error = DosDeleteDir(wk->li->list[x]);
1722 else
1723 DosDeleteDir(wk->li->list[x]);
1724 }
1725 else {
1726
1727 DosError(FERR_DISABLEHARDERR);
1728 if (wk->li->type == IDM_DELETE) {
1729 if (fTrashCan) {
1730 hObjectdest = WinQueryObject("<XWP_TRASHCAN>");
1731 rc = PrfQueryProfileData(HINI_USER,
1732 "XWorkplace",
1733 "TrashCan::Drives",
1734 G_abSupportedDrives,
1735 &cbSupportedDrives);
1736 if (hObjectdest != NULLHANDLE &&
1737 (rc ? (G_abSupportedDrives[toupper(*wk->li->list[x]) - 'C'] & 1)
1738 :((driveflags[toupper(*wk->li->list[x]) - 'A'] &
1739 DRIVE_LOCALHD )))) {
1740 hObjectofObject = WinQueryObject(wk->li->list[x]);
1741 retrn = make_deleteable(wk->li->list[x], error, ignorereadonly);
1742 if (retrn == SM2_CANCEL)
1743 break;
1744 if (retrn == SM2_DONTASK)
1745 ignorereadonly = TRUE;
1746 if (retrn == SM2_NO)
1747 continue;
1748 error = WinMoveObject(hObjectofObject, hObjectdest, 0);
1749 }
1750 else
1751 error = DosDelete(wk->li->list[x]);
1752 }
1753 else
1754 error = DosDelete(wk->li->list[x]);
1755 }
1756 else
1757 error = DosForceDelete(wk->li->list[x]);
1758 if (error) {
1759
1760 DosError(FERR_DISABLEHARDERR);
1761 retrn = make_deleteable(wk->li->list[x], error, ignorereadonly);
1762 if (retrn == SM2_CANCEL)
1763 break;
1764 if (retrn == SM2_DONTASK)
1765 ignorereadonly = TRUE;
1766 if (retrn == SM2_NO)
1767 continue;
1768 if (wk->li->type == IDM_DELETE) {
1769 if (fTrashCan) {
1770 hObjectdest = WinQueryObject("<XWP_TRASHCAN>");
1771 rc = PrfQueryProfileData(HINI_USER,
1772 "XWorkplace",
1773 "TrashCan::Drives",
1774 G_abSupportedDrives,
1775 &cbSupportedDrives);
1776 if (hObjectdest != NULLHANDLE &&
1777 (rc ? (G_abSupportedDrives[toupper(*wk->li->list[x]) - 'C'] & 1)
1778 :((driveflags[toupper(*wk->li->list[x]) - 'A'] &
1779 DRIVE_LOCALHD )))) {
1780 hObjectofObject = WinQueryObject(wk->li->list[x]);
1781 error = WinMoveObject(hObjectofObject, hObjectdest, 0);
1782 }
1783 else
1784 error = DosDelete(wk->li->list[x]);
1785 }
1786 else
1787 error = DosDelete(wk->li->list[x]);
1788 }
1789 else
1790 error = DosForceDelete(wk->li->list[x]);
1791 }
1792 DosReleaseMutexSem(hmtxFM2Delete);
1793 }
1794 //DbgMsg(pszSrcFile, __LINE__, "error %i retrn %i", error, retrn);
1795 if (fWarnReadOnly && error == ERROR_FILE_EXISTS) {
1796 error = ERROR_ACCESS_DENIED;
1797 retrn = SM2_NO;
1798 }
1799 if (error && (error != ERROR_ACCESS_DENIED ||
1800 (error == ERROR_ACCESS_DENIED &&
1801 (retrn == SM2_YES || retrn == SM2_DONTASK || retrn == 0)))) {
1802 if (LogFileHandle)
1803 fprintf(LogFileHandle,
1804 GetPString(IDS_DELETEFAILED1TEXT),
1805 wk->li->list[x], error);
1806 if (Dos_Error(MB_ENTERCANCEL,
1807 error,
1808 wk->hwndFrame,
1809 pszSrcFile,
1810 __LINE__,
1811 GetPString(IDS_DELETEFAILED2TEXT),
1812 wk->li->list[x]) == MBID_CANCEL) {
1813 DosSetVerify(fVerify);
1814 break;
1815 }
1816 }
1817 else {
1818 if (LogFileHandle)
1819 fprintf(LogFileHandle,
1820 GetPString(IDS_DELETEDTEXT), wk->li->list[x]);
1821 sprintf(prompt,
1822 GetPString(IDS_DELETEDTEXT), wk->li->list[x]);
1823 AddNote(prompt);
1824 }
1825 if (//fSyncUpdates ||
1826 AddToList(wk->li->list[x], &files, &numfiles, &numalloc)) {
1827 Broadcast(hab2,
1828 wk->hwndCnr,
1829 UM_UPDATERECORD,
1830 MPFROMP(wk->li->list[x]), MPVOID);
1831 } ;
1832 } // for
1833 }
1834 if (fVerify)
1835 DosSetVerify(fVerify);
1836 break;
1837 } // switch
1838 if (files) {
1839 Broadcast(hab2,
1840 wk->hwndCnr,
1841 UM_UPDATERECORDLIST, MPFROMP(files), MPVOID);
1842 FreeList(files);
1843 }
1844 if (WinIsWindow(hab2, wk->hwndCnr))
1845 PostMsg(wk->hwndCnr, UM_RESCAN, MPVOID, MPVOID);
1846
1847 WinDestroyMsgQueue(hmq2);
1848 }
1849 DecrThreadUsage();
1850 WinTerminate(hab2);
1851 }
1852 }
1853 FreeListInfo(wk->li);
1854 free(wk);
1855# ifdef FORTIFY
1856 Fortify_LeaveScope();
1857# endif
1858 DosPostEventSem(CompactSem);
1859 }
1860}
1861
1862#pragma alloc_text(MASSACTION,MassAction)
1863#pragma alloc_text(ACTION,Action)
1864#pragma alloc_text(UNDO,FreeUndo,Undo)
Note: See TracBrowser for help on using the repository browser.