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
23 // #include <mmsystem.h>
25 #define MALLOCHUNK 1000
27 #define GET_USHORT(buffer, i)\
28 (((BYTE)((buffer)[(i)]) + 0x100 * (BYTE)((buffer)[(i)+1])))
29 #define GET_SHORT(buffer, i)\
30 (((BYTE)((buffer)[(i)]) + 0x100 * (signed char)((buffer)[(i)+1])))
31 #define PUT_SHORT(buffer, i, s)\
32 (((buffer)[(i)] = (s) & 0xff, (buffer)[(i)+1] = ((s) >> 8) & 0xff))
34 static BOOL
GRPFILE_ReadFileToBuffer(LPCSTR
, HLOCAL
*, INT
*);
35 static HLOCAL
GRPFILE_ScanGroup(LPCSTR
, INT
, LPCSTR
, BOOL
);
36 static HLOCAL
GRPFILE_ScanProgram(LPCSTR
, INT
, LPCSTR
, INT
,
37 LPCSTR
, HLOCAL
,LPCSTR
);
38 static BOOL
GRPFILE_DoWriteGroupFile(HFILE file
, PROGGROUP
*group
);
40 /***********************************************************************
42 * GRPFILE_ModifyFileName
44 * Change extension `.grp' to `.gr'
47 static VOID
GRPFILE_ModifyFileName(LPSTR lpszNewName
, LPCSTR lpszOrigName
,
48 INT nSize
, BOOL bModify
)
50 lstrcpynA(lpszNewName
, lpszOrigName
, nSize
);
51 lpszNewName
[nSize
-1] = '\0';
53 if (!lstrcmpiA(lpszNewName
+ strlen(lpszNewName
) - 4, ".grp"))
54 lpszNewName
[strlen(lpszNewName
) - 1] = '\0';
57 /***********************************************************************
59 * GRPFILE_ReadGroupFile
62 HLOCAL
GRPFILE_ReadGroupFile(LPCSTR lpszPath
)
64 CHAR szPath_gr
[MAX_PATHNAME_LEN
];
65 BOOL bFileNameModified
= FALSE
;
67 HLOCAL hBuffer
, hGroup
;
70 /* if `.gr' file exists use that */
71 GRPFILE_ModifyFileName(szPath_gr
, lpszPath
, MAX_PATHNAME_LEN
, TRUE
);
72 if (OpenFile(szPath_gr
, &dummy
, OF_EXIST
) != HFILE_ERROR
)
75 bFileNameModified
= TRUE
;
78 /* Read the whole file into a buffer */
79 if (!GRPFILE_ReadFileToBuffer(lpszPath
, &hBuffer
, &size
))
81 MAIN_MessageBoxIDS_s(IDS_GRPFILE_READ_ERROR_s
, lpszPath
, IDS_ERROR
, MB_YESNO
);
85 /* Interpret buffer */
86 hGroup
= GRPFILE_ScanGroup(LocalLock(hBuffer
), size
,
87 lpszPath
, bFileNameModified
);
89 MAIN_MessageBoxIDS_s(IDS_GRPFILE_READ_ERROR_s
, lpszPath
, IDS_ERROR
, MB_YESNO
);
96 /***********************************************************************
98 * GRPFILE_ReadFileToBuffer
101 static BOOL
GRPFILE_ReadFileToBuffer(LPCSTR path
, HLOCAL
*phBuffer
,
106 HLOCAL hBuffer
, hNewBuffer
;
109 file
=_lopen(path
, OF_READ
);
110 if (file
== HFILE_ERROR
) return FALSE
;
113 hBuffer
= LocalAlloc(LMEM_FIXED
, MALLOCHUNK
+ 1);
114 if (!hBuffer
) return FALSE
;
115 buffer
= LocalLock(hBuffer
);
117 while ((len
= _lread(file
, buffer
+ size
, MALLOCHUNK
))
121 hNewBuffer
= LocalReAlloc(hBuffer
, size
+ MALLOCHUNK
+ 1,
128 hBuffer
= hNewBuffer
;
129 buffer
= LocalLock(hBuffer
);
134 if (len
== (UINT
)HFILE_ERROR
)
148 /***********************************************************************
152 static HLOCAL
GRPFILE_ScanGroup(LPCSTR buffer
, INT size
,
154 BOOL bModifiedFileName
)
160 INT x
, y
, width
, height
, iconx
, icony
, nCmdShow
;
161 INT number_of_programs
;
162 BOOL bOverwriteFileOk
;
164 if (buffer
[0] != 'P' || buffer
[1] != 'M') return(0);
165 if (buffer
[2] == 'C' && buffer
[3] == 'C')
166 /* original with checksum */
167 bOverwriteFileOk
= FALSE
;
168 else if (buffer
[2] == 'X' && buffer
[3] == 'X')
169 /* modified without checksum */
170 bOverwriteFileOk
= TRUE
;
173 /* checksum = GET_USHORT(buffer, 4) (ignored) */
175 extension
= buffer
+ GET_USHORT(buffer
, 6);
176 if (extension
== buffer
+ size
) extension
= 0;
177 else if (extension
+ 6 > buffer
+ size
) return(0);
179 nCmdShow
= GET_USHORT(buffer
, 8);
180 x
= GET_SHORT(buffer
, 10);
181 y
= GET_SHORT(buffer
, 12);
182 width
= GET_USHORT(buffer
, 14);
183 height
= GET_USHORT(buffer
, 16);
184 iconx
= GET_SHORT(buffer
, 18);
185 icony
= GET_SHORT(buffer
, 20);
186 lpszName
= buffer
+ GET_USHORT(buffer
, 22);
187 if (lpszName
>= buffer
+ size
) return(0);
189 /* unknown bytes 24 - 31 ignored */
191 Unknown bytes should be:
192 wLogPixelsX = GET_SHORT(buffer, 24);
193 wLogPixelsY = GET_SHORT(buffer, 26);
194 byBitsPerPixel = byte at 28;
195 byPlanes = byte at 29;
196 wReserved = GET_SHORT(buffer, 30);
199 hGroup
= GROUP_AddGroup(lpszName
, lpszGrpFile
, nCmdShow
, x
, y
,
200 width
, height
, iconx
, icony
,
201 bModifiedFileName
, bOverwriteFileOk
,
203 if (!hGroup
) return(0);
205 number_of_programs
= GET_USHORT(buffer
, 32);
206 if (2 * number_of_programs
+ 34 > size
) return(0);
207 for (i
=0, seqnum
=0; i
< number_of_programs
; i
++, seqnum
++)
209 LPCSTR program_ptr
= buffer
+ GET_USHORT(buffer
, 34 + 2*i
);
210 if (program_ptr
+ 24 > buffer
+ size
) return(0);
211 if (!GET_USHORT(buffer
, 34 + 2*i
)) continue;
212 if (!GRPFILE_ScanProgram(buffer
, size
, program_ptr
, seqnum
,
213 extension
, hGroup
, lpszGrpFile
))
215 GROUP_DeleteGroup(hGroup
);
220 /* FIXME shouldn't be necessary */
221 GROUP_ShowGroupWindow(hGroup
);
226 /***********************************************************************
227 * GRPFILE_ScanProgram
230 static HLOCAL
GRPFILE_ScanProgram(LPCSTR buffer
, INT size
,
231 LPCSTR program_ptr
, INT seqnum
,
232 LPCSTR extension
, HLOCAL hGroup
,
237 LPCSTR lpszName
, lpszCmdLine
, lpszIconFile
, lpszWorkDir
;
238 LPCSTR iconinfo_ptr
, iconANDbits_ptr
, iconXORbits_ptr
;
239 INT x
, y
, nIconIndex
, iconANDsize
, iconXORsize
;
240 INT nHotKey
, nCmdShow
;
241 UINT width
, height
, planes
, bpp
;
243 x
= GET_SHORT(program_ptr
, 0);
244 y
= GET_SHORT(program_ptr
, 2);
245 nIconIndex
= GET_USHORT(program_ptr
, 4);
247 /* FIXME is this correct ?? */
248 icontype
= GET_USHORT(program_ptr
, 6);
252 MAIN_MessageBoxIDS_s(IDS_UNKNOWN_FEATURE_s
, lpszGrpFile
,
255 iconXORsize
= GET_USHORT(program_ptr
, 8);
256 iconANDsize
= GET_USHORT(program_ptr
, 10) / 8;
257 iconinfo_ptr
= buffer
+ GET_USHORT(program_ptr
, 12);
258 iconXORbits_ptr
= buffer
+ GET_USHORT(program_ptr
, 14);
259 iconANDbits_ptr
= buffer
+ GET_USHORT(program_ptr
, 16);
260 width
= GET_USHORT(iconinfo_ptr
, 4);
261 height
= GET_USHORT(iconinfo_ptr
, 6);
262 planes
= GET_USHORT(iconinfo_ptr
, 10);
263 bpp
= GET_USHORT(iconinfo_ptr
, 11);
266 iconANDsize
= GET_USHORT(program_ptr
, 8);
267 iconXORsize
= GET_USHORT(program_ptr
, 10);
268 iconinfo_ptr
= buffer
+ GET_USHORT(program_ptr
, 12);
269 iconANDbits_ptr
= buffer
+ GET_USHORT(program_ptr
, 14);
270 iconXORbits_ptr
= buffer
+ GET_USHORT(program_ptr
, 16);
271 width
= GET_USHORT(iconinfo_ptr
, 4);
272 height
= GET_USHORT(iconinfo_ptr
, 6);
273 planes
= GET_USHORT(iconinfo_ptr
, 10);
274 bpp
= GET_USHORT(iconinfo_ptr
, 11);
277 if (iconANDbits_ptr
+ iconANDsize
> buffer
+ size
||
278 iconXORbits_ptr
+ iconXORsize
> buffer
+ size
) return(0);
280 hIcon
= CreateIcon( Globals
.hInstance
, width
, height
, planes
, bpp
, (PBYTE
)iconANDbits_ptr
, (PBYTE
)iconXORbits_ptr
);
282 lpszName
= buffer
+ GET_USHORT(program_ptr
, 18);
283 lpszCmdLine
= buffer
+ GET_USHORT(program_ptr
, 20);
284 lpszIconFile
= buffer
+ GET_USHORT(program_ptr
, 22);
285 if (iconinfo_ptr
+ 6 > buffer
+ size
||
286 lpszName
> buffer
+ size
||
287 lpszCmdLine
> buffer
+ size
||
288 lpszIconFile
> buffer
+ size
) return(0);
290 /* Scan Extensions */
293 nCmdShow
= SW_SHOWNORMAL
;
296 LPCSTR ptr
= extension
;
297 while (ptr
+ 6 <= buffer
+ size
)
299 UINT type
= GET_USHORT(ptr
, 0);
300 UINT number
= GET_USHORT(ptr
, 2);
301 UINT skip
= GET_USHORT(ptr
, 4);
303 if (number
== seqnum
)
308 if (ptr
+ 10 > buffer
+ size
) return(0);
309 if (ptr
[6] != 'P' || ptr
[7] != 'M' ||
310 ptr
[8] != 'C' || ptr
[9] != 'C') return(0);
313 lpszWorkDir
= ptr
+ 6;
316 if (ptr
+ 8 > buffer
+ size
) return(0);
317 nHotKey
= GET_USHORT(ptr
, 6);
320 if (ptr
+ 8 > buffer
+ size
) return(0);
321 nCmdShow
= GET_USHORT(ptr
, 6);
324 MAIN_MessageBoxIDS_s(IDS_UNKNOWN_FEATURE_s
,
325 lpszGrpFile
, IDS_WARNING
, MB_OK
);
333 return (PROGRAM_AddProgram(hGroup
, hIcon
, lpszName
, x
, y
,
334 lpszCmdLine
, lpszIconFile
,
335 nIconIndex
, lpszWorkDir
,
339 /***********************************************************************
341 * GRPFILE_WriteGroupFile
344 BOOL
GRPFILE_WriteGroupFile(HLOCAL hGroup
)
346 CHAR szPath
[MAX_PATHNAME_LEN
];
347 PROGGROUP
*group
= LocalLock(hGroup
);
352 GRPFILE_ModifyFileName(szPath
, LocalLock(group
->hGrpFile
),
354 group
->bFileNameModified
);
356 /* Try not to overwrite original files */
358 /* group->bOverwriteFileOk == TRUE only if a file has the modified format */
359 if (!group
->bOverwriteFileOk
&&
360 OpenFile(szPath
, &dummy
, OF_EXIST
) != HFILE_ERROR
)
362 /* Original file exists, try `.gr' extension */
363 GRPFILE_ModifyFileName(szPath
, LocalLock(group
->hGrpFile
),
364 MAX_PATHNAME_LEN
, TRUE
);
365 if (OpenFile(szPath
, &dummy
, OF_EXIST
) != HFILE_ERROR
)
367 /* File exists. Do not overwrite */
368 MAIN_MessageBoxIDS_s(IDS_FILE_NOT_OVERWRITTEN_s
, szPath
,
372 /* Inform about the modified file name */
374 MAIN_MessageBoxIDS_s(IDS_SAVE_GROUP_AS_s
, szPath
, IDS_INFO
,
375 MB_OKCANCEL
| MB_ICONINFORMATION
))
380 /* Warn about the (possible) incompatibility */
381 CHAR msg
[MAX_PATHNAME_LEN
+ 200];
383 "Group files written by this DRAFT Program Manager "
384 "possibly cannot be read by the Microsoft Program Manager!!\n"
385 "Are you sure to write %s?", szPath
);
386 if (IDOK
!= MessageBoxA(Globals
.hMainWnd
, msg
, "WARNING",
387 MB_OKCANCEL
| MB_DEFBUTTON2
)) return FALSE
;
391 file
= _lcreat(szPath
, 0);
392 if (file
!= HFILE_ERROR
)
394 ret
= GRPFILE_DoWriteGroupFile(file
, group
);
400 MAIN_MessageBoxIDS_s(IDS_FILE_WRITE_ERROR_s
, szPath
, IDS_ERROR
, MB_OK
);
405 /***********************************************************************
407 * GRPFILE_CalculateSizes
410 static VOID
GRPFILE_CalculateSizes(PROGRAM
*program
, INT
*Progs
, INT
*Icons
,
411 UINT
*sizeAnd
, UINT
*sizeXor
)
416 GetIconInfo( program
->hIcon
, &info
);
417 GetObjectW( info
.hbmMask
, sizeof(bmp
), &bmp
);
418 *sizeAnd
= bmp
.bmHeight
* ((bmp
.bmWidth
+ 15) / 16 * 2);
419 GetObjectW( info
.hbmColor
, sizeof(bmp
), &bmp
);
420 *sizeXor
= bmp
.bmHeight
* bmp
.bmWidthBytes
;
421 DeleteObject( info
.hbmMask
);
422 DeleteObject( info
.hbmColor
);
425 *Progs
+= strlen(LocalLock(program
->hName
)) + 1;
426 *Progs
+= strlen(LocalLock(program
->hCmdLine
)) + 1;
427 *Progs
+= strlen(LocalLock(program
->hIconFile
)) + 1;
429 *Icons
+= 12; /* IconInfo */
434 /***********************************************************************/
435 UINT16 GRPFILE_checksum
;
436 BOOL GRPFILE_checksum_half_word
;
437 BYTE GRPFILE_checksum_last_byte
;
438 /***********************************************************************
440 * GRPFILE_InitChecksum
443 static void GRPFILE_InitChecksum(void)
445 GRPFILE_checksum
= 0;
446 GRPFILE_checksum_half_word
= 0;
449 /***********************************************************************
451 * GRPFILE_GetChecksum
454 static UINT16
GRPFILE_GetChecksum(void)
456 return GRPFILE_checksum
;
459 /***********************************************************************
461 * GRPFILE_WriteWithChecksum
463 * Looks crazier than it is:
466 * chksum = cksum - 1. word;
467 * chksum = cksum - 2. word;
470 * if (filelen is even)
476 static UINT
GRPFILE_WriteWithChecksum(HFILE file
, LPCSTR str
, UINT size
)
479 if (GRPFILE_checksum_half_word
) {
480 GRPFILE_checksum
-= GRPFILE_checksum_last_byte
;
482 for (i
=0; i
< size
; i
++) {
483 if (GRPFILE_checksum_half_word
) {
484 GRPFILE_checksum
-= str
[i
] << 8;
486 GRPFILE_checksum
-= str
[i
];
488 GRPFILE_checksum_half_word
^= 1;
491 if (GRPFILE_checksum_half_word
) {
492 GRPFILE_checksum_last_byte
= str
[size
-1];
493 GRPFILE_checksum
+= GRPFILE_checksum_last_byte
;
496 return _lwrite(file
, str
, size
);
500 /***********************************************************************
502 * GRPFILE_DoWriteGroupFile
505 static BOOL
GRPFILE_DoWriteGroupFile(HFILE file
, PROGGROUP
*group
)
509 INT NumProg
, Title
, Progs
, Icons
, Extension
;
510 INT CurrProg
, CurrIcon
, nCmdShow
, ptr
, seqnum
;
511 UINT sizeAnd
, sizeXor
;
513 LPCSTR lpszTitle
= LocalLock(group
->hName
);
517 GRPFILE_InitChecksum();
519 /* Calculate offsets */
523 need_extension
= FALSE
;
524 hProgram
= group
->hPrograms
;
527 PROGRAM
*program
= LocalLock(hProgram
);
528 LPCSTR lpszWorkDir
= LocalLock(program
->hWorkDir
);
531 GRPFILE_CalculateSizes(program
, &Icons
, &Extension
, &sizeAnd
, &sizeXor
);
533 /* Set a flag if an extension is needed */
534 if (lpszWorkDir
[0] || program
->nHotKey
||
535 program
->nCmdShow
!= SW_SHOWNORMAL
) need_extension
= TRUE
;
537 hProgram
= program
->hNext
;
539 Title
= 34 + NumProg
* 2;
540 Progs
= Title
+ strlen(lpszTitle
) + 1;
550 PUT_SHORT(buffer
, 4, 0); /* Checksum zero for now, written later */
551 PUT_SHORT(buffer
, 6, Extension
);
552 /* Update group->nCmdShow */
553 if (IsIconic(group
->hWnd
)) nCmdShow
= SW_SHOWMINIMIZED
;
554 else if (IsZoomed(group
->hWnd
)) nCmdShow
= SW_SHOWMAXIMIZED
;
555 else nCmdShow
= SW_SHOWNORMAL
;
556 PUT_SHORT(buffer
, 8, nCmdShow
);
557 PUT_SHORT(buffer
, 10, group
->x
);
558 PUT_SHORT(buffer
, 12, group
->y
);
559 PUT_SHORT(buffer
, 14, group
->width
);
560 PUT_SHORT(buffer
, 16, group
->height
);
561 PUT_SHORT(buffer
, 18, group
->iconx
);
562 PUT_SHORT(buffer
, 20, group
->icony
);
563 PUT_SHORT(buffer
, 22, Title
);
564 PUT_SHORT(buffer
, 24, 0x0020); /* unknown */
565 PUT_SHORT(buffer
, 26, 0x0020); /* unknown */
566 PUT_SHORT(buffer
, 28, 0x0108); /* unknown */
567 PUT_SHORT(buffer
, 30, 0x0000); /* unknown */
568 PUT_SHORT(buffer
, 32, NumProg
);
570 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 34)) return FALSE
;
575 hProgram
= group
->hPrograms
;
578 PROGRAM
*program
= LocalLock(hProgram
);
580 PUT_SHORT(buffer
, 0, CurrProg
);
581 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 2))
584 GRPFILE_CalculateSizes(program
, &CurrProg
, &CurrIcon
, &sizeAnd
, &sizeXor
);
585 hProgram
= program
->hNext
;
589 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, lpszTitle
, strlen(lpszTitle
) + 1))
592 /* Program entries */
595 hProgram
= group
->hPrograms
;
598 PROGRAM
*program
= LocalLock(hProgram
);
599 LPCSTR Name
= LocalLock(program
->hName
);
600 LPCSTR CmdLine
= LocalLock(program
->hCmdLine
);
601 LPCSTR IconFile
= LocalLock(program
->hIconFile
);
602 INT next_prog
= CurrProg
;
603 INT next_icon
= CurrIcon
;
605 GRPFILE_CalculateSizes(program
, &next_prog
, &next_icon
, &sizeAnd
, &sizeXor
);
606 PUT_SHORT(buffer
, 0, program
->x
);
607 PUT_SHORT(buffer
, 2, program
->y
);
608 PUT_SHORT(buffer
, 4, program
->nIconIndex
);
609 PUT_SHORT(buffer
, 6, 0x048c); /* unknown */
610 PUT_SHORT(buffer
, 8, sizeXor
);
611 PUT_SHORT(buffer
, 10, sizeAnd
* 8);
612 PUT_SHORT(buffer
, 12, CurrIcon
);
613 PUT_SHORT(buffer
, 14, CurrIcon
+ 12 + sizeAnd
);
614 PUT_SHORT(buffer
, 16, CurrIcon
+ 12);
616 PUT_SHORT(buffer
, 18, ptr
);
617 ptr
+= strlen(Name
) + 1;
618 PUT_SHORT(buffer
, 20, ptr
);
619 ptr
+= strlen(CmdLine
) + 1;
620 PUT_SHORT(buffer
, 22, ptr
);
622 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 24) ||
623 (UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, Name
, strlen(Name
) + 1) ||
624 (UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, CmdLine
, strlen(CmdLine
) + 1) ||
625 (UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, IconFile
, strlen(IconFile
) + 1))
628 CurrProg
= next_prog
;
629 CurrIcon
= next_icon
;
630 hProgram
= program
->hNext
;
634 #if 0 /* FIXME: this is broken anyway */
635 hProgram
= group
->hPrograms
;
638 PROGRAM
*program
= LocalLock(hProgram
);
639 CURSORICONINFO
*iconinfo
= LocalLock(program
->hIcon
);
640 LPVOID XorBits
, AndBits
;
641 INT sizeXor
= iconinfo
->nHeight
* iconinfo
->nWidthBytes
;
642 INT sizeAnd
= iconinfo
->nHeight
* ((iconinfo
->nWidth
+ 15) / 16 * 2);
643 /* DumpIcon16(LocalLock(program->hIcon), 0, &XorBits, &AndBits);*/
645 PUT_SHORT(buffer
, 0, iconinfo
->ptHotSpot
.x
);
646 PUT_SHORT(buffer
, 2, iconinfo
->ptHotSpot
.y
);
647 PUT_SHORT(buffer
, 4, iconinfo
->nWidth
);
648 PUT_SHORT(buffer
, 6, iconinfo
->nHeight
);
649 PUT_SHORT(buffer
, 8, iconinfo
->nWidthBytes
);
650 buffer
[10] = iconinfo
->bPlanes
;
651 buffer
[11] = iconinfo
->bBitsPerPixel
;
653 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 12) ||
654 (UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, AndBits
, sizeAnd
) ||
655 (UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, XorBits
, sizeXor
)) return FALSE
;
657 hProgram
= program
->hNext
;
663 /* write `PMCC' extension */
664 PUT_SHORT(buffer
, 0, 0x8000);
665 PUT_SHORT(buffer
, 2, 0xffff);
666 PUT_SHORT(buffer
, 4, 0x000a);
667 buffer
[6] = 'P', buffer
[7] = 'M';
668 buffer
[8] = 'C', buffer
[9] = 'C';
669 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 10))
673 hProgram
= group
->hPrograms
;
676 PROGRAM
*program
= LocalLock(hProgram
);
677 LPCSTR lpszWorkDir
= LocalLock(program
->hWorkDir
);
679 /* Working directory */
682 PUT_SHORT(buffer
, 0, 0x8101);
683 PUT_SHORT(buffer
, 2, seqnum
);
684 PUT_SHORT(buffer
, 4, 7 + strlen(lpszWorkDir
));
685 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 6) ||
686 (UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, lpszWorkDir
, strlen(lpszWorkDir
) + 1))
691 if (program
->nHotKey
)
693 PUT_SHORT(buffer
, 0, 0x8102);
694 PUT_SHORT(buffer
, 2, seqnum
);
695 PUT_SHORT(buffer
, 4, 8);
696 PUT_SHORT(buffer
, 6, program
->nHotKey
);
697 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 8)) return FALSE
;
701 if (program
->nCmdShow
)
703 PUT_SHORT(buffer
, 0, 0x8103);
704 PUT_SHORT(buffer
, 2, seqnum
);
705 PUT_SHORT(buffer
, 4, 8);
706 PUT_SHORT(buffer
, 6, program
->nCmdShow
);
707 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 8)) return FALSE
;
711 hProgram
= program
->hNext
;
714 /* Write `End' extension */
715 PUT_SHORT(buffer
, 0, 0xffff);
716 PUT_SHORT(buffer
, 2, 0xffff);
717 PUT_SHORT(buffer
, 4, 0x0000);
718 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 6)) return FALSE
;
721 checksum
= GRPFILE_GetChecksum();
722 _llseek(file
, 4, SEEK_SET
);
723 PUT_SHORT(buffer
, 0, checksum
);
724 _lwrite(file
, buffer
, 2);