4 * Copyright 1996 Ulrich Schmid
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define WIN32_LEAN_AND_MEAN
28 #define MALLOCHUNK 1000
30 #define GET_USHORT(buffer, i)\
31 (((BYTE)((buffer)[(i)]) + 0x100 * (BYTE)((buffer)[(i)+1])))
32 #define GET_SHORT(buffer, i)\
33 (((BYTE)((buffer)[(i)]) + 0x100 * (signed char)((buffer)[(i)+1])))
34 #define PUT_SHORT(buffer, i, s)\
35 (((buffer)[(i)] = (BYTE)((s) & 0xff), (buffer)[(i)+1] = (BYTE)(((s) >> 8) & 0xff)))
37 static BOOL
GRPFILE_ReadFileToBuffer(LPCSTR
, HLOCAL
*, INT
*);
38 static HLOCAL
GRPFILE_ScanGroup(LPCSTR
, INT
, LPCSTR
, BOOL
);
39 static HLOCAL
GRPFILE_ScanProgram(LPCSTR
, INT
, LPCSTR
, INT
,
40 LPCSTR
, HLOCAL
,LPCSTR
);
41 static BOOL
GRPFILE_DoWriteGroupFile(HFILE file
, PROGGROUP
*group
);
43 /***********************************************************************
45 * GRPFILE_ModifyFileName
47 * Change extension `.grp' to `.gr'
50 static VOID
GRPFILE_ModifyFileName(LPSTR lpszNewName
, LPCSTR lpszOrigName
,
51 INT nSize
, BOOL bModify
)
53 lstrcpynA(lpszNewName
, lpszOrigName
, nSize
);
54 lpszNewName
[nSize
-1] = '\0';
56 if (!lstrcmpiA(lpszNewName
+ strlen(lpszNewName
) - 4, ".grp"))
57 lpszNewName
[strlen(lpszNewName
) - 1] = '\0';
60 /***********************************************************************
62 * GRPFILE_ReadGroupFile
65 HLOCAL
GRPFILE_ReadGroupFile(LPCSTR lpszPath
)
67 CHAR szPath_gr
[MAX_PATHNAME_LEN
];
68 BOOL bFileNameModified
= FALSE
;
70 HLOCAL hBuffer
, hGroup
;
73 /* if `.gr' file exists use that */
74 GRPFILE_ModifyFileName(szPath_gr
, lpszPath
, MAX_PATHNAME_LEN
, TRUE
);
75 if (OpenFile(szPath_gr
, &dummy
, OF_EXIST
) != HFILE_ERROR
)
78 bFileNameModified
= TRUE
;
81 /* Read the whole file into a buffer */
82 if (!GRPFILE_ReadFileToBuffer(lpszPath
, &hBuffer
, &size
))
84 MAIN_MessageBoxIDS_s(IDS_GRPFILE_READ_ERROR_s
, lpszPath
, IDS_ERROR
, MB_YESNO
);
88 /* Interpret buffer */
89 hGroup
= GRPFILE_ScanGroup(LocalLock(hBuffer
), size
,
90 lpszPath
, bFileNameModified
);
92 MAIN_MessageBoxIDS_s(IDS_GRPFILE_READ_ERROR_s
, lpszPath
, IDS_ERROR
, MB_YESNO
);
99 /***********************************************************************
101 * GRPFILE_ReadFileToBuffer
104 static BOOL
GRPFILE_ReadFileToBuffer(LPCSTR path
, HLOCAL
*phBuffer
,
109 HLOCAL hBuffer
, hNewBuffer
;
112 file
=_lopen(path
, OF_READ
);
113 if (file
== HFILE_ERROR
) return FALSE
;
116 hBuffer
= LocalAlloc(LMEM_FIXED
, MALLOCHUNK
+ 1);
117 if (!hBuffer
) return FALSE
;
118 buffer
= LocalLock(hBuffer
);
120 while ((len
= _lread(file
, buffer
+ size
, MALLOCHUNK
))
124 hNewBuffer
= LocalReAlloc(hBuffer
, size
+ MALLOCHUNK
+ 1,
131 hBuffer
= hNewBuffer
;
132 buffer
= LocalLock(hBuffer
);
137 if (len
== (UINT
)HFILE_ERROR
)
151 /***********************************************************************
155 static HLOCAL
GRPFILE_ScanGroup(LPCSTR buffer
, INT size
,
157 BOOL bModifiedFileName
)
163 INT x
, y
, width
, height
, iconx
, icony
, nCmdShow
;
164 INT number_of_programs
;
165 BOOL bOverwriteFileOk
;
167 if (buffer
[0] != 'P' || buffer
[1] != 'M') return(0);
168 if (buffer
[2] == 'C' && buffer
[3] == 'C')
169 /* original with checksum */
170 bOverwriteFileOk
= FALSE
;
171 else if (buffer
[2] == 'X' && buffer
[3] == 'X')
172 /* modified without checksum */
173 bOverwriteFileOk
= TRUE
;
176 /* checksum = GET_USHORT(buffer, 4) (ignored) */
178 extension
= buffer
+ GET_USHORT(buffer
, 6);
179 if (extension
== buffer
+ size
) extension
= 0;
180 else if (extension
+ 6 > buffer
+ size
) return(0);
182 nCmdShow
= GET_USHORT(buffer
, 8);
183 x
= GET_SHORT(buffer
, 10);
184 y
= GET_SHORT(buffer
, 12);
185 width
= GET_USHORT(buffer
, 14);
186 height
= GET_USHORT(buffer
, 16);
187 iconx
= GET_SHORT(buffer
, 18);
188 icony
= GET_SHORT(buffer
, 20);
189 lpszName
= buffer
+ GET_USHORT(buffer
, 22);
190 if (lpszName
>= buffer
+ size
) return(0);
192 /* unknown bytes 24 - 31 ignored */
194 Unknown bytes should be:
195 wLogPixelsX = GET_SHORT(buffer, 24);
196 wLogPixelsY = GET_SHORT(buffer, 26);
197 byBitsPerPixel = byte at 28;
198 byPlanes = byte at 29;
199 wReserved = GET_SHORT(buffer, 30);
202 hGroup
= GROUP_AddGroup(lpszName
, lpszGrpFile
, nCmdShow
, x
, y
,
203 width
, height
, iconx
, icony
,
204 bModifiedFileName
, bOverwriteFileOk
,
206 if (!hGroup
) return(0);
208 number_of_programs
= GET_USHORT(buffer
, 32);
209 if (2 * number_of_programs
+ 34 > size
) return(0);
210 for (i
=0, seqnum
=0; i
< number_of_programs
; i
++, seqnum
++)
212 LPCSTR program_ptr
= buffer
+ GET_USHORT(buffer
, 34 + 2*i
);
213 if (program_ptr
+ 24 > buffer
+ size
) return(0);
214 if (!GET_USHORT(buffer
, 34 + 2*i
)) continue;
215 if (!GRPFILE_ScanProgram(buffer
, size
, program_ptr
, seqnum
,
216 extension
, hGroup
, lpszGrpFile
))
218 GROUP_DeleteGroup(hGroup
);
223 /* FIXME shouldn't be necessary */
224 GROUP_ShowGroupWindow(hGroup
);
229 /***********************************************************************
230 * GRPFILE_ScanProgram
233 static HLOCAL
GRPFILE_ScanProgram(LPCSTR buffer
, INT size
,
234 LPCSTR program_ptr
, INT seqnum
,
235 LPCSTR extension
, HLOCAL hGroup
,
240 LPCSTR lpszName
, lpszCmdLine
, lpszIconFile
, lpszWorkDir
;
241 LPCSTR iconinfo_ptr
, iconANDbits_ptr
, iconXORbits_ptr
;
242 INT x
, y
, nIconIndex
, iconANDsize
, iconXORsize
;
243 INT nHotKey
, nCmdShow
;
244 UINT width
, height
, planes
, bpp
;
246 x
= GET_SHORT(program_ptr
, 0);
247 y
= GET_SHORT(program_ptr
, 2);
248 nIconIndex
= GET_USHORT(program_ptr
, 4);
250 /* FIXME is this correct ?? */
251 icontype
= GET_USHORT(program_ptr
, 6);
255 MAIN_MessageBoxIDS_s(IDS_UNKNOWN_FEATURE_s
, lpszGrpFile
,
258 iconXORsize
= GET_USHORT(program_ptr
, 8);
259 iconANDsize
= GET_USHORT(program_ptr
, 10) / 8;
260 iconinfo_ptr
= buffer
+ GET_USHORT(program_ptr
, 12);
261 iconXORbits_ptr
= buffer
+ GET_USHORT(program_ptr
, 14);
262 iconANDbits_ptr
= buffer
+ GET_USHORT(program_ptr
, 16);
263 width
= GET_USHORT(iconinfo_ptr
, 4);
264 height
= GET_USHORT(iconinfo_ptr
, 6);
265 planes
= GET_USHORT(iconinfo_ptr
, 10);
266 bpp
= GET_USHORT(iconinfo_ptr
, 11);
269 iconANDsize
= GET_USHORT(program_ptr
, 8);
270 iconXORsize
= GET_USHORT(program_ptr
, 10);
271 iconinfo_ptr
= buffer
+ GET_USHORT(program_ptr
, 12);
272 iconANDbits_ptr
= buffer
+ GET_USHORT(program_ptr
, 14);
273 iconXORbits_ptr
= buffer
+ GET_USHORT(program_ptr
, 16);
274 width
= GET_USHORT(iconinfo_ptr
, 4);
275 height
= GET_USHORT(iconinfo_ptr
, 6);
276 planes
= GET_USHORT(iconinfo_ptr
, 10);
277 bpp
= GET_USHORT(iconinfo_ptr
, 11);
280 if (iconANDbits_ptr
+ iconANDsize
> buffer
+ size
||
281 iconXORbits_ptr
+ iconXORsize
> buffer
+ size
) return(0);
283 hIcon
= CreateIcon( Globals
.hInstance
, width
, height
, planes
, bpp
, iconANDbits_ptr
, iconXORbits_ptr
);
285 lpszName
= buffer
+ GET_USHORT(program_ptr
, 18);
286 lpszCmdLine
= buffer
+ GET_USHORT(program_ptr
, 20);
287 lpszIconFile
= buffer
+ GET_USHORT(program_ptr
, 22);
288 if (iconinfo_ptr
+ 6 > buffer
+ size
||
289 lpszName
> buffer
+ size
||
290 lpszCmdLine
> buffer
+ size
||
291 lpszIconFile
> buffer
+ size
) return(0);
293 /* Scan Extensions */
296 nCmdShow
= SW_SHOWNORMAL
;
299 LPCSTR ptr
= extension
;
300 while (ptr
+ 6 <= buffer
+ size
)
302 UINT type
= GET_USHORT(ptr
, 0);
303 UINT number
= GET_USHORT(ptr
, 2);
304 UINT skip
= GET_USHORT(ptr
, 4);
306 if (number
== seqnum
)
311 if (ptr
+ 10 > buffer
+ size
) return(0);
312 if (ptr
[6] != 'P' || ptr
[7] != 'M' ||
313 ptr
[8] != 'C' || ptr
[9] != 'C') return(0);
316 lpszWorkDir
= ptr
+ 6;
319 if (ptr
+ 8 > buffer
+ size
) return(0);
320 nHotKey
= GET_USHORT(ptr
, 6);
323 if (ptr
+ 8 > buffer
+ size
) return(0);
324 nCmdShow
= GET_USHORT(ptr
, 6);
327 MAIN_MessageBoxIDS_s(IDS_UNKNOWN_FEATURE_s
,
328 lpszGrpFile
, IDS_WARNING
, MB_OK
);
336 return (PROGRAM_AddProgram(hGroup
, hIcon
, lpszName
, x
, y
,
337 lpszCmdLine
, lpszIconFile
,
338 nIconIndex
, lpszWorkDir
,
342 /***********************************************************************
344 * GRPFILE_WriteGroupFile
347 BOOL
GRPFILE_WriteGroupFile(HLOCAL hGroup
)
349 CHAR szPath
[MAX_PATHNAME_LEN
];
350 PROGGROUP
*group
= LocalLock(hGroup
);
355 GRPFILE_ModifyFileName(szPath
, LocalLock(group
->hGrpFile
),
357 group
->bFileNameModified
);
359 /* Try not to overwrite original files */
361 /* group->bOverwriteFileOk == TRUE only if a file has the modified format */
362 if (!group
->bOverwriteFileOk
&&
363 OpenFile(szPath
, &dummy
, OF_EXIST
) != HFILE_ERROR
)
365 /* Original file exists, try `.gr' extension */
366 GRPFILE_ModifyFileName(szPath
, LocalLock(group
->hGrpFile
),
367 MAX_PATHNAME_LEN
, TRUE
);
368 if (OpenFile(szPath
, &dummy
, OF_EXIST
) != HFILE_ERROR
)
370 /* File exists. Do not overwrite */
371 MAIN_MessageBoxIDS_s(IDS_FILE_NOT_OVERWRITTEN_s
, szPath
,
375 /* Inform about the modified file name */
377 MAIN_MessageBoxIDS_s(IDS_SAVE_GROUP_AS_s
, szPath
, IDS_INFO
,
378 MB_OKCANCEL
| MB_ICONINFORMATION
))
383 /* Warn about the (possible) incompatibility */
384 CHAR msg
[MAX_PATHNAME_LEN
+ 200];
386 "Group files written by this DRAFT Program Manager "
387 "possibly cannot be read by the Microsoft Program Manager!!\n"
388 "Are you sure to write %s?", szPath
);
389 if (IDOK
!= MessageBoxA(Globals
.hMainWnd
, msg
, "WARNING",
390 MB_OKCANCEL
| MB_DEFBUTTON2
)) return FALSE
;
394 file
= _lcreat(szPath
, 0);
395 if (file
!= HFILE_ERROR
)
397 ret
= GRPFILE_DoWriteGroupFile(file
, group
);
403 MAIN_MessageBoxIDS_s(IDS_FILE_WRITE_ERROR_s
, szPath
, IDS_ERROR
, MB_OK
);
408 /***********************************************************************
410 * GRPFILE_CalculateSizes
413 static VOID
GRPFILE_CalculateSizes(PROGRAM
*program
, INT
*Progs
, INT
*Icons
,
414 UINT
*sizeAnd
, UINT
*sizeXor
)
419 GetIconInfo( program
->hIcon
, &info
);
420 GetObjectW( info
.hbmMask
, sizeof(bmp
), &bmp
);
421 *sizeAnd
= bmp
.bmHeight
* ((bmp
.bmWidth
+ 15) / 16 * 2);
422 GetObjectW( info
.hbmColor
, sizeof(bmp
), &bmp
);
423 *sizeXor
= bmp
.bmHeight
* bmp
.bmWidthBytes
;
424 DeleteObject( info
.hbmMask
);
425 DeleteObject( info
.hbmColor
);
428 *Progs
+= strlen(LocalLock(program
->hName
)) + 1;
429 *Progs
+= strlen(LocalLock(program
->hCmdLine
)) + 1;
430 *Progs
+= strlen(LocalLock(program
->hIconFile
)) + 1;
432 *Icons
+= 12; /* IconInfo */
437 /***********************************************************************/
438 UINT16 GRPFILE_checksum
;
439 BOOL GRPFILE_checksum_half_word
;
440 BYTE GRPFILE_checksum_last_byte
;
441 /***********************************************************************
443 * GRPFILE_InitChecksum
446 static void GRPFILE_InitChecksum(void)
448 GRPFILE_checksum
= 0;
449 GRPFILE_checksum_half_word
= 0;
452 /***********************************************************************
454 * GRPFILE_GetChecksum
457 static UINT16
GRPFILE_GetChecksum(void)
459 return GRPFILE_checksum
;
462 /***********************************************************************
464 * GRPFILE_WriteWithChecksum
466 * Looks crazier than it is:
469 * chksum = cksum - 1. word;
470 * chksum = cksum - 2. word;
473 * if (filelen is even)
479 static UINT
GRPFILE_WriteWithChecksum(HFILE file
, LPCSTR str
, UINT size
)
482 if (GRPFILE_checksum_half_word
) {
483 GRPFILE_checksum
-= GRPFILE_checksum_last_byte
;
485 for (i
=0; i
< size
; i
++) {
486 if (GRPFILE_checksum_half_word
) {
487 GRPFILE_checksum
-= str
[i
] << 8;
489 GRPFILE_checksum
-= str
[i
];
491 GRPFILE_checksum_half_word
^= 1;
494 if (GRPFILE_checksum_half_word
) {
495 GRPFILE_checksum_last_byte
= str
[size
-1];
496 GRPFILE_checksum
+= GRPFILE_checksum_last_byte
;
499 return _lwrite(file
, str
, size
);
503 /***********************************************************************
505 * GRPFILE_DoWriteGroupFile
508 static BOOL
GRPFILE_DoWriteGroupFile(HFILE file
, PROGGROUP
*group
)
512 INT NumProg
, Title
, Progs
, Icons
, Extension
;
513 INT CurrProg
, CurrIcon
, nCmdShow
, ptr
, seqnum
;
514 UINT sizeAnd
, sizeXor
;
516 LPCSTR lpszTitle
= LocalLock(group
->hName
);
520 GRPFILE_InitChecksum();
522 /* Calculate offsets */
526 need_extension
= FALSE
;
527 hProgram
= group
->hPrograms
;
530 PROGRAM
*program
= LocalLock(hProgram
);
531 LPCSTR lpszWorkDir
= LocalLock(program
->hWorkDir
);
534 GRPFILE_CalculateSizes(program
, &Icons
, &Extension
, &sizeAnd
, &sizeXor
);
536 /* Set a flag if an extension is needed */
537 if (lpszWorkDir
[0] || program
->nHotKey
||
538 program
->nCmdShow
!= SW_SHOWNORMAL
) need_extension
= TRUE
;
540 hProgram
= program
->hNext
;
542 Title
= 34 + NumProg
* 2;
543 Progs
= Title
+ strlen(lpszTitle
) + 1;
553 PUT_SHORT(buffer
, 4, 0); /* Checksum zero for now, written later */
554 PUT_SHORT(buffer
, 6, Extension
);
555 /* Update group->nCmdShow */
556 if (IsIconic(group
->hWnd
)) nCmdShow
= SW_SHOWMINIMIZED
;
557 else if (IsZoomed(group
->hWnd
)) nCmdShow
= SW_SHOWMAXIMIZED
;
558 else nCmdShow
= SW_SHOWNORMAL
;
559 PUT_SHORT(buffer
, 8, nCmdShow
);
560 PUT_SHORT(buffer
, 10, group
->x
);
561 PUT_SHORT(buffer
, 12, group
->y
);
562 PUT_SHORT(buffer
, 14, group
->width
);
563 PUT_SHORT(buffer
, 16, group
->height
);
564 PUT_SHORT(buffer
, 18, group
->iconx
);
565 PUT_SHORT(buffer
, 20, group
->icony
);
566 PUT_SHORT(buffer
, 22, Title
);
567 PUT_SHORT(buffer
, 24, 0x0020); /* unknown */
568 PUT_SHORT(buffer
, 26, 0x0020); /* unknown */
569 PUT_SHORT(buffer
, 28, 0x0108); /* unknown */
570 PUT_SHORT(buffer
, 30, 0x0000); /* unknown */
571 PUT_SHORT(buffer
, 32, NumProg
);
573 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 34)) return FALSE
;
578 hProgram
= group
->hPrograms
;
581 PROGRAM
*program
= LocalLock(hProgram
);
583 PUT_SHORT(buffer
, 0, CurrProg
);
584 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 2))
587 GRPFILE_CalculateSizes(program
, &CurrProg
, &CurrIcon
, &sizeAnd
, &sizeXor
);
588 hProgram
= program
->hNext
;
592 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, lpszTitle
, strlen(lpszTitle
) + 1))
595 /* Program entries */
598 hProgram
= group
->hPrograms
;
601 PROGRAM
*program
= LocalLock(hProgram
);
602 LPCSTR Name
= LocalLock(program
->hName
);
603 LPCSTR CmdLine
= LocalLock(program
->hCmdLine
);
604 LPCSTR IconFile
= LocalLock(program
->hIconFile
);
605 INT next_prog
= CurrProg
;
606 INT next_icon
= CurrIcon
;
608 GRPFILE_CalculateSizes(program
, &next_prog
, &next_icon
, &sizeAnd
, &sizeXor
);
609 PUT_SHORT(buffer
, 0, program
->x
);
610 PUT_SHORT(buffer
, 2, program
->y
);
611 PUT_SHORT(buffer
, 4, program
->nIconIndex
);
612 PUT_SHORT(buffer
, 6, 0x048c); /* unknown */
613 PUT_SHORT(buffer
, 8, sizeXor
);
614 PUT_SHORT(buffer
, 10, sizeAnd
* 8);
615 PUT_SHORT(buffer
, 12, CurrIcon
);
616 PUT_SHORT(buffer
, 14, CurrIcon
+ 12 + sizeAnd
);
617 PUT_SHORT(buffer
, 16, CurrIcon
+ 12);
619 PUT_SHORT(buffer
, 18, ptr
);
620 ptr
+= strlen(Name
) + 1;
621 PUT_SHORT(buffer
, 20, ptr
);
622 ptr
+= strlen(CmdLine
) + 1;
623 PUT_SHORT(buffer
, 22, ptr
);
625 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 24) ||
626 (UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, Name
, strlen(Name
) + 1) ||
627 (UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, CmdLine
, strlen(CmdLine
) + 1) ||
628 (UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, IconFile
, strlen(IconFile
) + 1))
631 CurrProg
= next_prog
;
632 CurrIcon
= next_icon
;
633 hProgram
= program
->hNext
;
637 #if 0 /* FIXME: this is broken anyway */
638 hProgram
= group
->hPrograms
;
641 PROGRAM
*program
= LocalLock(hProgram
);
642 CURSORICONINFO
*iconinfo
= LocalLock(program
->hIcon
);
643 LPVOID XorBits
, AndBits
;
644 INT sizeXor
= iconinfo
->nHeight
* iconinfo
->nWidthBytes
;
645 INT sizeAnd
= iconinfo
->nHeight
* ((iconinfo
->nWidth
+ 15) / 16 * 2);
646 /* DumpIcon16(LocalLock(program->hIcon), 0, &XorBits, &AndBits);*/
648 PUT_SHORT(buffer
, 0, iconinfo
->ptHotSpot
.x
);
649 PUT_SHORT(buffer
, 2, iconinfo
->ptHotSpot
.y
);
650 PUT_SHORT(buffer
, 4, iconinfo
->nWidth
);
651 PUT_SHORT(buffer
, 6, iconinfo
->nHeight
);
652 PUT_SHORT(buffer
, 8, iconinfo
->nWidthBytes
);
653 buffer
[10] = iconinfo
->bPlanes
;
654 buffer
[11] = iconinfo
->bBitsPerPixel
;
656 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 12) ||
657 (UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, AndBits
, sizeAnd
) ||
658 (UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, XorBits
, sizeXor
)) return FALSE
;
660 hProgram
= program
->hNext
;
666 /* write `PMCC' extension */
667 PUT_SHORT(buffer
, 0, 0x8000);
668 PUT_SHORT(buffer
, 2, 0xffff);
669 PUT_SHORT(buffer
, 4, 0x000a);
670 buffer
[6] = 'P'; buffer
[7] = 'M';
671 buffer
[8] = 'C'; buffer
[9] = 'C';
672 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 10))
676 hProgram
= group
->hPrograms
;
679 PROGRAM
*program
= LocalLock(hProgram
);
680 LPCSTR lpszWorkDir
= LocalLock(program
->hWorkDir
);
682 /* Working directory */
685 PUT_SHORT(buffer
, 0, 0x8101);
686 PUT_SHORT(buffer
, 2, seqnum
);
687 PUT_SHORT(buffer
, 4, 7 + strlen(lpszWorkDir
));
688 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 6) ||
689 (UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, lpszWorkDir
, strlen(lpszWorkDir
) + 1))
694 if (program
->nHotKey
)
696 PUT_SHORT(buffer
, 0, 0x8102);
697 PUT_SHORT(buffer
, 2, seqnum
);
698 PUT_SHORT(buffer
, 4, 8);
699 PUT_SHORT(buffer
, 6, program
->nHotKey
);
700 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 8)) return FALSE
;
704 if (program
->nCmdShow
)
706 PUT_SHORT(buffer
, 0, 0x8103);
707 PUT_SHORT(buffer
, 2, seqnum
);
708 PUT_SHORT(buffer
, 4, 8);
709 PUT_SHORT(buffer
, 6, program
->nCmdShow
);
710 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 8)) return FALSE
;
714 hProgram
= program
->hNext
;
717 /* Write `End' extension */
718 PUT_SHORT(buffer
, 0, 0xffff);
719 PUT_SHORT(buffer
, 2, 0xffff);
720 PUT_SHORT(buffer
, 4, 0x0000);
721 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 6)) return FALSE
;
724 checksum
= GRPFILE_GetChecksum();
725 _llseek(file
, 4, SEEK_SET
);
726 PUT_SHORT(buffer
, 0, checksum
);
727 _lwrite(file
, buffer
, 2);