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
24 #define MALLOCHUNK 1000
26 #define GET_USHORT(buffer, i)\
27 (((BYTE)((buffer)[(i)]) + 0x100 * (BYTE)((buffer)[(i)+1])))
28 #define GET_SHORT(buffer, i)\
29 (((BYTE)((buffer)[(i)]) + 0x100 * (signed char)((buffer)[(i)+1])))
30 #define PUT_SHORT(buffer, i, s)\
31 (((buffer)[(i)] = (s) & 0xff, (buffer)[(i)+1] = ((s) >> 8) & 0xff))
33 static BOOL
GRPFILE_ReadFileToBuffer(LPCSTR
, HLOCAL
*, INT
*);
34 static HLOCAL
GRPFILE_ScanGroup(LPCSTR
, INT
, LPCSTR
, BOOL
);
35 static HLOCAL
GRPFILE_ScanProgram(LPCSTR
, INT
, LPCSTR
, INT
,
36 LPCSTR
, HLOCAL
,LPCSTR
);
37 static BOOL
GRPFILE_DoWriteGroupFile(HFILE file
, PROGGROUP
*group
);
39 /***********************************************************************
41 * GRPFILE_ModifyFileName
43 * Change extension `.grp' to `.gr'
46 static VOID
GRPFILE_ModifyFileName(LPSTR lpszNewName
, LPCSTR lpszOrigName
,
47 INT nSize
, BOOL bModify
)
49 lstrcpynA(lpszNewName
, lpszOrigName
, nSize
);
50 lpszNewName
[nSize
-1] = '\0';
52 if (!lstrcmpiA(lpszNewName
+ strlen(lpszNewName
) - 4, ".grp"))
53 lpszNewName
[strlen(lpszNewName
) - 1] = '\0';
56 /***********************************************************************
58 * GRPFILE_ReadGroupFile
61 HLOCAL
GRPFILE_ReadGroupFile(LPCSTR lpszPath
)
63 CHAR szPath_gr
[MAX_PATHNAME_LEN
];
64 BOOL bFileNameModified
= FALSE
;
66 HLOCAL hBuffer
, hGroup
;
69 /* if `.gr' file exists use that */
70 GRPFILE_ModifyFileName(szPath_gr
, lpszPath
, MAX_PATHNAME_LEN
, TRUE
);
71 if (OpenFile(szPath_gr
, &dummy
, OF_EXIST
) != HFILE_ERROR
)
74 bFileNameModified
= TRUE
;
77 /* Read the whole file into a buffer */
78 if (!GRPFILE_ReadFileToBuffer(lpszPath
, &hBuffer
, &size
))
80 MAIN_MessageBoxIDS_s(IDS_GRPFILE_READ_ERROR_s
, lpszPath
, IDS_ERROR
, MB_YESNO
);
84 /* Interpret buffer */
85 hGroup
= GRPFILE_ScanGroup(LocalLock(hBuffer
), size
,
86 lpszPath
, bFileNameModified
);
88 MAIN_MessageBoxIDS_s(IDS_GRPFILE_READ_ERROR_s
, lpszPath
, IDS_ERROR
, MB_YESNO
);
95 /***********************************************************************
97 * GRPFILE_ReadFileToBuffer
100 static BOOL
GRPFILE_ReadFileToBuffer(LPCSTR path
, HLOCAL
*phBuffer
,
105 HLOCAL hBuffer
, hNewBuffer
;
108 file
=_lopen(path
, OF_READ
);
109 if (file
== HFILE_ERROR
) return FALSE
;
112 hBuffer
= LocalAlloc(LMEM_FIXED
, MALLOCHUNK
+ 1);
113 if (!hBuffer
) return FALSE
;
114 buffer
= LocalLock(hBuffer
);
116 while ((len
= _lread(file
, buffer
+ size
, MALLOCHUNK
))
120 hNewBuffer
= LocalReAlloc(hBuffer
, size
+ MALLOCHUNK
+ 1,
127 hBuffer
= hNewBuffer
;
128 buffer
= LocalLock(hBuffer
);
133 if (len
== (UINT
)HFILE_ERROR
)
147 /***********************************************************************
151 static HLOCAL
GRPFILE_ScanGroup(LPCSTR buffer
, INT size
,
153 BOOL bModifiedFileName
)
159 INT x
, y
, width
, height
, iconx
, icony
, nCmdShow
;
160 INT number_of_programs
;
161 BOOL bOverwriteFileOk
;
163 if (buffer
[0] != 'P' || buffer
[1] != 'M') return(0);
164 if (buffer
[2] == 'C' && buffer
[3] == 'C')
165 /* original with checksum */
166 bOverwriteFileOk
= FALSE
;
167 else if (buffer
[2] == 'X' && buffer
[3] == 'X')
168 /* modified without checksum */
169 bOverwriteFileOk
= TRUE
;
172 /* checksum = GET_USHORT(buffer, 4) (ignored) */
174 extension
= buffer
+ GET_USHORT(buffer
, 6);
175 if (extension
== buffer
+ size
) extension
= 0;
176 else if (extension
+ 6 > buffer
+ size
) return(0);
178 nCmdShow
= GET_USHORT(buffer
, 8);
179 x
= GET_SHORT(buffer
, 10);
180 y
= GET_SHORT(buffer
, 12);
181 width
= GET_USHORT(buffer
, 14);
182 height
= GET_USHORT(buffer
, 16);
183 iconx
= GET_SHORT(buffer
, 18);
184 icony
= GET_SHORT(buffer
, 20);
185 lpszName
= buffer
+ GET_USHORT(buffer
, 22);
186 if (lpszName
>= buffer
+ size
) return(0);
188 /* unknown bytes 24 - 31 ignored */
190 Unknown bytes should be:
191 wLogPixelsX = GET_SHORT(buffer, 24);
192 wLogPixelsY = GET_SHORT(buffer, 26);
193 byBitsPerPixel = byte at 28;
194 byPlanes = byte at 29;
195 wReserved = GET_SHORT(buffer, 30);
198 hGroup
= GROUP_AddGroup(lpszName
, lpszGrpFile
, nCmdShow
, x
, y
,
199 width
, height
, iconx
, icony
,
200 bModifiedFileName
, bOverwriteFileOk
,
202 if (!hGroup
) return(0);
204 number_of_programs
= GET_USHORT(buffer
, 32);
205 if (2 * number_of_programs
+ 34 > size
) return(0);
206 for (i
=0, seqnum
=0; i
< number_of_programs
; i
++, seqnum
++)
208 LPCSTR program_ptr
= buffer
+ GET_USHORT(buffer
, 34 + 2*i
);
209 if (program_ptr
+ 24 > buffer
+ size
) return(0);
210 if (!GET_USHORT(buffer
, 34 + 2*i
)) continue;
211 if (!GRPFILE_ScanProgram(buffer
, size
, program_ptr
, seqnum
,
212 extension
, hGroup
, lpszGrpFile
))
214 GROUP_DeleteGroup(hGroup
);
219 /* FIXME shouldn't be necessary */
220 GROUP_ShowGroupWindow(hGroup
);
225 /***********************************************************************
226 * GRPFILE_ScanProgram
229 static HLOCAL
GRPFILE_ScanProgram(LPCSTR buffer
, INT size
,
230 LPCSTR program_ptr
, INT seqnum
,
231 LPCSTR extension
, HLOCAL hGroup
,
236 LPCSTR lpszName
, lpszCmdLine
, lpszIconFile
, lpszWorkDir
;
237 LPCSTR iconinfo_ptr
, iconANDbits_ptr
, iconXORbits_ptr
;
238 INT x
, y
, nIconIndex
, iconANDsize
, iconXORsize
;
239 INT nHotKey
, nCmdShow
;
240 UINT width
, height
, planes
, bpp
;
242 x
= GET_SHORT(program_ptr
, 0);
243 y
= GET_SHORT(program_ptr
, 2);
244 nIconIndex
= GET_USHORT(program_ptr
, 4);
246 /* FIXME is this correct ?? */
247 icontype
= GET_USHORT(program_ptr
, 6);
251 MAIN_MessageBoxIDS_s(IDS_UNKNOWN_FEATURE_s
, lpszGrpFile
,
254 iconXORsize
= GET_USHORT(program_ptr
, 8);
255 iconANDsize
= GET_USHORT(program_ptr
, 10) / 8;
256 iconinfo_ptr
= buffer
+ GET_USHORT(program_ptr
, 12);
257 iconXORbits_ptr
= buffer
+ GET_USHORT(program_ptr
, 14);
258 iconANDbits_ptr
= buffer
+ GET_USHORT(program_ptr
, 16);
259 width
= GET_USHORT(iconinfo_ptr
, 4);
260 height
= GET_USHORT(iconinfo_ptr
, 6);
261 planes
= GET_USHORT(iconinfo_ptr
, 10);
262 bpp
= GET_USHORT(iconinfo_ptr
, 11);
265 iconANDsize
= GET_USHORT(program_ptr
, 8);
266 iconXORsize
= GET_USHORT(program_ptr
, 10);
267 iconinfo_ptr
= buffer
+ GET_USHORT(program_ptr
, 12);
268 iconANDbits_ptr
= buffer
+ GET_USHORT(program_ptr
, 14);
269 iconXORbits_ptr
= buffer
+ GET_USHORT(program_ptr
, 16);
270 width
= GET_USHORT(iconinfo_ptr
, 4);
271 height
= GET_USHORT(iconinfo_ptr
, 6);
272 planes
= GET_USHORT(iconinfo_ptr
, 10);
273 bpp
= GET_USHORT(iconinfo_ptr
, 11);
276 if (iconANDbits_ptr
+ iconANDsize
> buffer
+ size
||
277 iconXORbits_ptr
+ iconXORsize
> buffer
+ size
) return(0);
280 hIcon
= CreateIcon(Globals
.hInstance
, width
, height
, planes
, bpp
, (PBYTE
)iconANDbits_ptr
, (PBYTE
)iconXORbits_ptr
);
282 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
;
515 UINT sizeAnd
, sizeXor
;
517 DWORD sizeAnd
, sizeXor
;
520 LPCSTR lpszTitle
= LocalLock(group
->hName
);
524 GRPFILE_InitChecksum();
526 /* Calculate offsets */
530 need_extension
= FALSE
;
531 hProgram
= group
->hPrograms
;
534 PROGRAM
*program
= LocalLock(hProgram
);
535 LPCSTR lpszWorkDir
= LocalLock(program
->hWorkDir
);
538 GRPFILE_CalculateSizes(program
, &Icons
, &Extension
, &sizeAnd
, &sizeXor
);
540 /* Set a flag if an extension is needed */
541 if (lpszWorkDir
[0] || program
->nHotKey
||
542 program
->nCmdShow
!= SW_SHOWNORMAL
) need_extension
= TRUE
;
544 hProgram
= program
->hNext
;
546 Title
= 34 + NumProg
* 2;
547 Progs
= Title
+ strlen(lpszTitle
) + 1;
557 PUT_SHORT(buffer
, 4, 0); /* Checksum zero for now, written later */
558 PUT_SHORT(buffer
, 6, Extension
);
559 /* Update group->nCmdShow */
560 if (IsIconic(group
->hWnd
)) nCmdShow
= SW_SHOWMINIMIZED
;
561 else if (IsZoomed(group
->hWnd
)) nCmdShow
= SW_SHOWMAXIMIZED
;
562 else nCmdShow
= SW_SHOWNORMAL
;
563 PUT_SHORT(buffer
, 8, nCmdShow
);
564 PUT_SHORT(buffer
, 10, group
->x
);
565 PUT_SHORT(buffer
, 12, group
->y
);
566 PUT_SHORT(buffer
, 14, group
->width
);
567 PUT_SHORT(buffer
, 16, group
->height
);
568 PUT_SHORT(buffer
, 18, group
->iconx
);
569 PUT_SHORT(buffer
, 20, group
->icony
);
570 PUT_SHORT(buffer
, 22, Title
);
571 PUT_SHORT(buffer
, 24, 0x0020); /* unknown */
572 PUT_SHORT(buffer
, 26, 0x0020); /* unknown */
573 PUT_SHORT(buffer
, 28, 0x0108); /* unknown */
574 PUT_SHORT(buffer
, 30, 0x0000); /* unknown */
575 PUT_SHORT(buffer
, 32, NumProg
);
577 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 34)) return FALSE
;
582 hProgram
= group
->hPrograms
;
585 PROGRAM
*program
= LocalLock(hProgram
);
587 PUT_SHORT(buffer
, 0, CurrProg
);
588 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 2))
591 GRPFILE_CalculateSizes(program
, &CurrProg
, &CurrIcon
, &sizeAnd
, &sizeXor
);
592 hProgram
= program
->hNext
;
596 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, lpszTitle
, strlen(lpszTitle
) + 1))
599 /* Program entries */
602 hProgram
= group
->hPrograms
;
605 PROGRAM
*program
= LocalLock(hProgram
);
606 LPCSTR Name
= LocalLock(program
->hName
);
607 LPCSTR CmdLine
= LocalLock(program
->hCmdLine
);
608 LPCSTR IconFile
= LocalLock(program
->hIconFile
);
609 INT next_prog
= CurrProg
;
610 INT next_icon
= CurrIcon
;
612 GRPFILE_CalculateSizes(program
, &next_prog
, &next_icon
, &sizeAnd
, &sizeXor
);
613 PUT_SHORT(buffer
, 0, program
->x
);
614 PUT_SHORT(buffer
, 2, program
->y
);
615 PUT_SHORT(buffer
, 4, program
->nIconIndex
);
616 PUT_SHORT(buffer
, 6, 0x048c); /* unknown */
617 PUT_SHORT(buffer
, 8, sizeXor
);
618 PUT_SHORT(buffer
, 10, sizeAnd
* 8);
619 PUT_SHORT(buffer
, 12, CurrIcon
);
620 PUT_SHORT(buffer
, 14, CurrIcon
+ 12 + sizeAnd
);
621 PUT_SHORT(buffer
, 16, CurrIcon
+ 12);
623 PUT_SHORT(buffer
, 18, ptr
);
624 ptr
+= strlen(Name
) + 1;
625 PUT_SHORT(buffer
, 20, ptr
);
626 ptr
+= strlen(CmdLine
) + 1;
627 PUT_SHORT(buffer
, 22, ptr
);
629 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 24) ||
630 (UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, Name
, strlen(Name
) + 1) ||
631 (UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, CmdLine
, strlen(CmdLine
) + 1) ||
632 (UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, IconFile
, strlen(IconFile
) + 1))
635 CurrProg
= next_prog
;
636 CurrIcon
= next_icon
;
637 hProgram
= program
->hNext
;
641 #if 0 /* FIXME: this is broken anyway */
642 hProgram
= group
->hPrograms
;
645 PROGRAM
*program
= LocalLock(hProgram
);
646 CURSORICONINFO
*iconinfo
= LocalLock(program
->hIcon
);
647 LPVOID XorBits
, AndBits
;
648 INT sizeXor
= iconinfo
->nHeight
* iconinfo
->nWidthBytes
;
649 INT sizeAnd
= iconinfo
->nHeight
* ((iconinfo
->nWidth
+ 15) / 16 * 2);
650 /* DumpIcon16(LocalLock(program->hIcon), 0, &XorBits, &AndBits);*/
652 PUT_SHORT(buffer
, 0, iconinfo
->ptHotSpot
.x
);
653 PUT_SHORT(buffer
, 2, iconinfo
->ptHotSpot
.y
);
654 PUT_SHORT(buffer
, 4, iconinfo
->nWidth
);
655 PUT_SHORT(buffer
, 6, iconinfo
->nHeight
);
656 PUT_SHORT(buffer
, 8, iconinfo
->nWidthBytes
);
657 buffer
[10] = iconinfo
->bPlanes
;
658 buffer
[11] = iconinfo
->bBitsPerPixel
;
660 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 12) ||
661 (UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, AndBits
, sizeAnd
) ||
662 (UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, XorBits
, sizeXor
)) return FALSE
;
664 hProgram
= program
->hNext
;
670 /* write `PMCC' extension */
671 PUT_SHORT(buffer
, 0, 0x8000);
672 PUT_SHORT(buffer
, 2, 0xffff);
673 PUT_SHORT(buffer
, 4, 0x000a);
674 buffer
[6] = 'P', buffer
[7] = 'M';
675 buffer
[8] = 'C', buffer
[9] = 'C';
676 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 10))
680 hProgram
= group
->hPrograms
;
683 PROGRAM
*program
= LocalLock(hProgram
);
684 LPCSTR lpszWorkDir
= LocalLock(program
->hWorkDir
);
686 /* Working directory */
689 PUT_SHORT(buffer
, 0, 0x8101);
690 PUT_SHORT(buffer
, 2, seqnum
);
691 PUT_SHORT(buffer
, 4, 7 + strlen(lpszWorkDir
));
692 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 6) ||
693 (UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, lpszWorkDir
, strlen(lpszWorkDir
) + 1))
698 if (program
->nHotKey
)
700 PUT_SHORT(buffer
, 0, 0x8102);
701 PUT_SHORT(buffer
, 2, seqnum
);
702 PUT_SHORT(buffer
, 4, 8);
703 PUT_SHORT(buffer
, 6, program
->nHotKey
);
704 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 8)) return FALSE
;
708 if (program
->nCmdShow
)
710 PUT_SHORT(buffer
, 0, 0x8103);
711 PUT_SHORT(buffer
, 2, seqnum
);
712 PUT_SHORT(buffer
, 4, 8);
713 PUT_SHORT(buffer
, 6, program
->nCmdShow
);
714 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 8)) return FALSE
;
718 hProgram
= program
->hNext
;
721 /* Write `End' extension */
722 PUT_SHORT(buffer
, 0, 0xffff);
723 PUT_SHORT(buffer
, 2, 0xffff);
724 PUT_SHORT(buffer
, 4, 0x0000);
725 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 6)) return FALSE
;
728 checksum
= GRPFILE_GetChecksum();
729 _llseek(file
, 4, SEEK_SET
);
730 PUT_SHORT(buffer
, 0, checksum
);
731 _lwrite(file
, buffer
, 2);