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
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
);
41 /***********************************************************************
43 * GRPFILE_ModifyFileName
45 * Change extension `.grp' to `.gr'
49 static VOID
GRPFILE_ModifyFileName(LPSTR lpszNewName
, LPCSTR lpszOrigName
,
50 INT nSize
, BOOL bModify
)
52 lstrcpynA(lpszNewName
, lpszOrigName
, nSize
);
53 lpszNewName
[nSize
-1] = '\0';
55 if (!lstrcmpiA(lpszNewName
+ strlen(lpszNewName
) - 4, ".grp"))
56 lpszNewName
[strlen(lpszNewName
) - 1] = '\0';
60 /***********************************************************************
62 * GRPFILE_ReadGroupFile
65 DWORD
GRPFILE_ReadGroupFile(LPCWSTR lpszPath
, BOOL bIsCommonGroup
)
68 CHAR szPath_gr
[MAX_PATHNAME_LEN
];
69 BOOL bFileNameModified
= FALSE
;
71 HLOCAL hBuffer
, hGroup
;
74 /* if `.gr' file exists use that */
75 GRPFILE_ModifyFileName(szPath_gr
, lpszPath
, MAX_PATHNAME_LEN
, TRUE
);
76 if (OpenFile(szPath_gr
, &dummy
, OF_EXIST
) != HFILE_ERROR
)
79 bFileNameModified
= TRUE
;
82 /* Read the whole file into a buffer */
83 if (!GRPFILE_ReadFileToBuffer(lpszPath
, &hBuffer
, &size
))
85 MAIN_MessageBoxIDS_s(IDS_GRPFILE_READ_ERROR_s
, lpszPath
, IDS_ERROR
, MB_YESNO
);
89 /* Interpret buffer */
90 hGroup
= GRPFILE_ScanGroup(LocalLock(hBuffer
), size
,
91 lpszPath
, bFileNameModified
);
93 MAIN_MessageBoxIDS_s(IDS_GRPFILE_READ_ERROR_s
, lpszPath
, IDS_ERROR
, MB_YESNO
);
100 return ERROR_SUCCESS
;
104 /***********************************************************************
106 * GRPFILE_ReadFileToBuffer
110 static BOOL
GRPFILE_ReadFileToBuffer(LPCSTR path
, HLOCAL
*phBuffer
,
115 HLOCAL hBuffer
, hNewBuffer
;
118 file
=_lopen(path
, OF_READ
);
119 if (file
== HFILE_ERROR
) return FALSE
;
122 hBuffer
= LocalAlloc(LMEM_FIXED
, MALLOCHUNK
+ 1);
123 if (!hBuffer
) return FALSE
;
124 buffer
= LocalLock(hBuffer
);
126 while ((len
= _lread(file
, buffer
+ size
, MALLOCHUNK
))
130 hNewBuffer
= LocalReAlloc(hBuffer
, size
+ MALLOCHUNK
+ 1,
137 hBuffer
= hNewBuffer
;
138 buffer
= LocalLock(hBuffer
);
143 if (len
== (UINT
)HFILE_ERROR
)
158 /***********************************************************************
163 static HLOCAL
GRPFILE_ScanGroup(LPCSTR buffer
, INT size
,
165 BOOL bModifiedFileName
)
171 INT x
, y
, width
, height
, iconx
, icony
, nCmdShow
;
172 INT number_of_programs
;
173 BOOL bOverwriteFileOk
;
175 if (buffer
[0] != 'P' || buffer
[1] != 'M') return(0);
176 if (buffer
[2] == 'C' && buffer
[3] == 'C')
177 /* original with checksum */
178 bOverwriteFileOk
= FALSE
;
179 else if (buffer
[2] == 'X' && buffer
[3] == 'X')
180 /* modified without checksum */
181 bOverwriteFileOk
= TRUE
;
184 /* checksum = GET_USHORT(buffer, 4) (ignored) */
186 extension
= buffer
+ GET_USHORT(buffer
, 6);
187 if (extension
== buffer
+ size
) extension
= 0;
188 else if (extension
+ 6 > buffer
+ size
) return(0);
190 nCmdShow
= GET_USHORT(buffer
, 8);
191 x
= GET_SHORT(buffer
, 10);
192 y
= GET_SHORT(buffer
, 12);
193 width
= GET_USHORT(buffer
, 14);
194 height
= GET_USHORT(buffer
, 16);
195 iconx
= GET_SHORT(buffer
, 18);
196 icony
= GET_SHORT(buffer
, 20);
197 lpszName
= buffer
+ GET_USHORT(buffer
, 22);
198 if (lpszName
>= buffer
+ size
) return(0);
200 /* unknown bytes 24 - 31 ignored */
202 Unknown bytes should be:
203 wLogPixelsX = GET_SHORT(buffer, 24);
204 wLogPixelsY = GET_SHORT(buffer, 26);
205 byBitsPerPixel = byte at 28;
206 byPlanes = byte at 29;
207 wReserved = GET_SHORT(buffer, 30);
210 hGroup
= GROUP_AddGroup(lpszName
, lpszGrpFile
, nCmdShow
, x
, y
,
211 width
, height
, iconx
, icony
,
212 bModifiedFileName
, bOverwriteFileOk
,
214 if (!hGroup
) return(0);
216 number_of_programs
= GET_USHORT(buffer
, 32);
217 if (2 * number_of_programs
+ 34 > size
) return(0);
218 for (i
=0, seqnum
=0; i
< number_of_programs
; i
++, seqnum
++)
220 LPCSTR program_ptr
= buffer
+ GET_USHORT(buffer
, 34 + 2*i
);
221 if (program_ptr
+ 24 > buffer
+ size
) return(0);
222 if (!GET_USHORT(buffer
, 34 + 2*i
)) continue;
223 if (!GRPFILE_ScanProgram(buffer
, size
, program_ptr
, seqnum
,
224 extension
, hGroup
, lpszGrpFile
))
226 GROUP_DeleteGroup(hGroup
);
231 /* FIXME shouldn't be necessary */
232 GROUP_ShowGroupWindow(hGroup
);
238 /***********************************************************************
239 * GRPFILE_ScanProgram
243 static HLOCAL
GRPFILE_ScanProgram(LPCSTR buffer
, INT size
,
244 LPCSTR program_ptr
, INT seqnum
,
245 LPCSTR extension
, HLOCAL hGroup
,
250 LPCSTR lpszName
, lpszCmdLine
, lpszIconFile
, lpszWorkDir
;
251 LPCSTR iconinfo_ptr
, iconANDbits_ptr
, iconXORbits_ptr
;
252 INT x
, y
, nIconIndex
, iconANDsize
, iconXORsize
;
253 INT nHotKey
, nCmdShow
;
254 UINT width
, height
, planes
, bpp
;
256 x
= GET_SHORT(program_ptr
, 0);
257 y
= GET_SHORT(program_ptr
, 2);
258 nIconIndex
= GET_USHORT(program_ptr
, 4);
260 /* FIXME is this correct ?? */
261 icontype
= GET_USHORT(program_ptr
, 6);
265 MAIN_MessageBoxIDS_s(IDS_UNKNOWN_FEATURE_s
, lpszGrpFile
,
268 iconXORsize
= GET_USHORT(program_ptr
, 8);
269 iconANDsize
= GET_USHORT(program_ptr
, 10) / 8;
270 iconinfo_ptr
= buffer
+ GET_USHORT(program_ptr
, 12);
271 iconXORbits_ptr
= buffer
+ GET_USHORT(program_ptr
, 14);
272 iconANDbits_ptr
= buffer
+ GET_USHORT(program_ptr
, 16);
273 width
= GET_USHORT(iconinfo_ptr
, 4);
274 height
= GET_USHORT(iconinfo_ptr
, 6);
275 planes
= GET_USHORT(iconinfo_ptr
, 10);
276 bpp
= GET_USHORT(iconinfo_ptr
, 11);
279 iconANDsize
= GET_USHORT(program_ptr
, 8);
280 iconXORsize
= GET_USHORT(program_ptr
, 10);
281 iconinfo_ptr
= buffer
+ GET_USHORT(program_ptr
, 12);
282 iconANDbits_ptr
= buffer
+ GET_USHORT(program_ptr
, 14);
283 iconXORbits_ptr
= buffer
+ GET_USHORT(program_ptr
, 16);
284 width
= GET_USHORT(iconinfo_ptr
, 4);
285 height
= GET_USHORT(iconinfo_ptr
, 6);
286 planes
= GET_USHORT(iconinfo_ptr
, 10);
287 bpp
= GET_USHORT(iconinfo_ptr
, 11);
290 if (iconANDbits_ptr
+ iconANDsize
> buffer
+ size
||
291 iconXORbits_ptr
+ iconXORsize
> buffer
+ size
) return(0);
293 hIcon
= CreateIcon(Globals
.hInstance
, width
, height
, planes
, bpp
, (PBYTE
)iconANDbits_ptr
, (PBYTE
)iconXORbits_ptr
);
295 lpszName
= buffer
+ GET_USHORT(program_ptr
, 18);
296 lpszCmdLine
= buffer
+ GET_USHORT(program_ptr
, 20);
297 lpszIconFile
= buffer
+ GET_USHORT(program_ptr
, 22);
298 if (iconinfo_ptr
+ 6 > buffer
+ size
||
299 lpszName
> buffer
+ size
||
300 lpszCmdLine
> buffer
+ size
||
301 lpszIconFile
> buffer
+ size
) return(0);
303 /* Scan Extensions */
306 nCmdShow
= SW_SHOWNORMAL
;
309 LPCSTR ptr
= extension
;
310 while (ptr
+ 6 <= buffer
+ size
)
312 UINT type
= GET_USHORT(ptr
, 0);
313 UINT number
= GET_USHORT(ptr
, 2);
314 UINT skip
= GET_USHORT(ptr
, 4);
316 if (number
== seqnum
)
321 if (ptr
+ 10 > buffer
+ size
) return(0);
322 if (ptr
[6] != 'P' || ptr
[7] != 'M' ||
323 ptr
[8] != 'C' || ptr
[9] != 'C') return(0);
326 lpszWorkDir
= ptr
+ 6;
329 if (ptr
+ 8 > buffer
+ size
) return(0);
330 nHotKey
= GET_USHORT(ptr
, 6);
333 if (ptr
+ 8 > buffer
+ size
) return(0);
334 nCmdShow
= GET_USHORT(ptr
, 6);
337 MAIN_MessageBoxIDS_s(IDS_UNKNOWN_FEATURE_s
,
338 lpszGrpFile
, IDS_WARNING
, MB_OK
);
346 return (PROGRAM_AddProgram(hGroup
, hIcon
, lpszName
, x
, y
,
347 lpszCmdLine
, lpszIconFile
,
348 nIconIndex
, lpszWorkDir
,
353 /***********************************************************************
355 * GRPFILE_WriteGroupFile
358 BOOL
GRPFILE_WriteGroupFile(PROGGROUP
* hGroup
)
361 CHAR szPath
[MAX_PATHNAME_LEN
];
362 PROGGROUP
*group
= LocalLock(hGroup
);
367 GRPFILE_ModifyFileName(szPath
, LocalLock(group
->hGrpFile
),
369 group
->bFileNameModified
);
371 /* Try not to overwrite original files */
373 /* group->bOverwriteFileOk == TRUE only if a file has the modified format */
374 if (!group
->bOverwriteFileOk
&&
375 OpenFile(szPath
, &dummy
, OF_EXIST
) != HFILE_ERROR
)
377 /* Original file exists, try `.gr' extension */
378 GRPFILE_ModifyFileName(szPath
, LocalLock(group
->hGrpFile
),
379 MAX_PATHNAME_LEN
, TRUE
);
380 if (OpenFile(szPath
, &dummy
, OF_EXIST
) != HFILE_ERROR
)
382 /* File exists. Do not overwrite */
383 MAIN_MessageBoxIDS_s(IDS_FILE_NOT_OVERWRITTEN_s
, szPath
,
387 /* Inform about the modified file name */
389 MAIN_MessageBoxIDS_s(IDS_SAVE_GROUP_AS_s
, szPath
, IDS_INFO
,
390 MB_OKCANCEL
| MB_ICONINFORMATION
))
395 /* Warn about the (possible) incompatibility */
396 CHAR msg
[MAX_PATHNAME_LEN
+ 200];
398 "Group files written by this DRAFT Program Manager "
399 "possibly cannot be read by the Microsoft Program Manager!!\n"
400 "Are you sure to write %s?", szPath
);
401 if (IDOK
!= MessageBoxA(Globals
.hMainWnd
, msg
, "WARNING",
402 MB_OKCANCEL
| MB_DEFBUTTON2
)) return FALSE
;
406 file
= _lcreat(szPath
, 0);
407 if (file
!= HFILE_ERROR
)
409 ret
= GRPFILE_DoWriteGroupFile(file
, group
);
415 MAIN_MessageBoxIDS_s(IDS_FILE_WRITE_ERROR_s
, szPath
, IDS_ERROR
, MB_OK
);
426 /***********************************************************************
428 * GRPFILE_CalculateSizes
431 static VOID
GRPFILE_CalculateSizes(PROGRAM
*program
, INT
*Progs
, INT
*Icons
,
432 UINT
*sizeAnd
, UINT
*sizeXor
)
437 GetIconInfo( program
->hIcon
, &info
);
438 GetObjectW( info
.hbmMask
, sizeof(bmp
), &bmp
);
439 *sizeAnd
= bmp
.bmHeight
* ((bmp
.bmWidth
+ 15) / 16 * 2);
440 GetObjectW( info
.hbmColor
, sizeof(bmp
), &bmp
);
441 *sizeXor
= bmp
.bmHeight
* bmp
.bmWidthBytes
;
442 DeleteObject( info
.hbmMask
);
443 DeleteObject( info
.hbmColor
);
446 *Progs
+= strlen(LocalLock(program
->hName
)) + 1;
447 *Progs
+= strlen(LocalLock(program
->hCmdLine
)) + 1;
448 *Progs
+= strlen(LocalLock(program
->hIconFile
)) + 1;
450 *Icons
+= 12; /* IconInfo */
455 /***********************************************************************/
456 UINT16 GRPFILE_checksum
;
457 BOOL GRPFILE_checksum_half_word
;
458 BYTE GRPFILE_checksum_last_byte
;
459 /***********************************************************************
461 * GRPFILE_InitChecksum
464 static void GRPFILE_InitChecksum(void)
466 GRPFILE_checksum
= 0;
467 GRPFILE_checksum_half_word
= 0;
470 /***********************************************************************
472 * GRPFILE_GetChecksum
475 static UINT16
GRPFILE_GetChecksum(void)
477 return GRPFILE_checksum
;
480 /***********************************************************************
482 * GRPFILE_WriteWithChecksum
484 * Looks crazier than it is:
487 * chksum = cksum - 1. word;
488 * chksum = cksum - 2. word;
491 * if (filelen is even)
497 static UINT
GRPFILE_WriteWithChecksum(HFILE file
, LPCSTR str
, UINT size
)
500 if (GRPFILE_checksum_half_word
) {
501 GRPFILE_checksum
-= GRPFILE_checksum_last_byte
;
503 for (i
=0; i
< size
; i
++) {
504 if (GRPFILE_checksum_half_word
) {
505 GRPFILE_checksum
-= str
[i
] << 8;
507 GRPFILE_checksum
-= str
[i
];
509 GRPFILE_checksum_half_word
^= 1;
512 if (GRPFILE_checksum_half_word
) {
513 GRPFILE_checksum_last_byte
= str
[size
-1];
514 GRPFILE_checksum
+= GRPFILE_checksum_last_byte
;
517 return _lwrite(file
, str
, size
);
521 /***********************************************************************
523 * GRPFILE_DoWriteGroupFile
526 static BOOL
GRPFILE_DoWriteGroupFile(HFILE file
, PROGGROUP
*group
)
530 INT NumProg
, Title
, Progs
, Icons
, Extension
;
531 INT CurrProg
, CurrIcon
, nCmdShow
, ptr
, seqnum
;
533 UINT sizeAnd
, sizeXor
;
536 LPCSTR lpszTitle
= LocalLock(group
->hName
);
540 GRPFILE_InitChecksum();
542 /* Calculate offsets */
546 need_extension
= FALSE
;
547 hProgram
= group
->hPrograms
;
550 PROGRAM
*program
= LocalLock(hProgram
);
551 LPCSTR lpszWorkDir
= LocalLock(program
->hWorkDir
);
554 GRPFILE_CalculateSizes(program
, &Icons
, &Extension
, &sizeAnd
, &sizeXor
);
556 /* Set a flag if an extension is needed */
557 if (lpszWorkDir
[0] || program
->nHotKey
||
558 program
->nCmdShow
!= SW_SHOWNORMAL
) need_extension
= TRUE
;
560 hProgram
= program
->hNext
;
562 Title
= 34 + NumProg
* 2;
563 Progs
= Title
+ strlen(lpszTitle
) + 1;
573 PUT_SHORT(buffer
, 4, 0); /* Checksum zero for now, written later */
574 PUT_SHORT(buffer
, 6, Extension
);
575 /* Update group->nCmdShow */
576 if (IsIconic(group
->hWnd
)) nCmdShow
= SW_SHOWMINIMIZED
;
577 else if (IsZoomed(group
->hWnd
)) nCmdShow
= SW_SHOWMAXIMIZED
;
578 else nCmdShow
= SW_SHOWNORMAL
;
579 PUT_SHORT(buffer
, 8, nCmdShow
);
580 PUT_SHORT(buffer
, 10, group
->x
);
581 PUT_SHORT(buffer
, 12, group
->y
);
582 PUT_SHORT(buffer
, 14, group
->width
);
583 PUT_SHORT(buffer
, 16, group
->height
);
584 PUT_SHORT(buffer
, 18, group
->iconx
);
585 PUT_SHORT(buffer
, 20, group
->icony
);
586 PUT_SHORT(buffer
, 22, Title
);
587 PUT_SHORT(buffer
, 24, 0x0020); /* unknown */
588 PUT_SHORT(buffer
, 26, 0x0020); /* unknown */
589 PUT_SHORT(buffer
, 28, 0x0108); /* unknown */
590 PUT_SHORT(buffer
, 30, 0x0000); /* unknown */
591 PUT_SHORT(buffer
, 32, NumProg
);
593 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 34)) return FALSE
;
598 hProgram
= group
->hPrograms
;
601 PROGRAM
*program
= LocalLock(hProgram
);
603 PUT_SHORT(buffer
, 0, CurrProg
);
604 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 2))
607 GRPFILE_CalculateSizes(program
, &CurrProg
, &CurrIcon
, &sizeAnd
, &sizeXor
);
608 hProgram
= program
->hNext
;
612 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, lpszTitle
, strlen(lpszTitle
) + 1))
615 /* Program entries */
618 hProgram
= group
->hPrograms
;
621 PROGRAM
*program
= LocalLock(hProgram
);
622 LPCSTR Name
= LocalLock(program
->hName
);
623 LPCSTR CmdLine
= LocalLock(program
->hCmdLine
);
624 LPCSTR IconFile
= LocalLock(program
->hIconFile
);
625 INT next_prog
= CurrProg
;
626 INT next_icon
= CurrIcon
;
628 GRPFILE_CalculateSizes(program
, &next_prog
, &next_icon
, &sizeAnd
, &sizeXor
);
629 PUT_SHORT(buffer
, 0, program
->x
);
630 PUT_SHORT(buffer
, 2, program
->y
);
631 PUT_SHORT(buffer
, 4, program
->nIconIndex
);
632 PUT_SHORT(buffer
, 6, 0x048c); /* unknown */
633 PUT_SHORT(buffer
, 8, sizeXor
);
634 PUT_SHORT(buffer
, 10, sizeAnd
* 8);
635 PUT_SHORT(buffer
, 12, CurrIcon
);
636 PUT_SHORT(buffer
, 14, CurrIcon
+ 12 + sizeAnd
);
637 PUT_SHORT(buffer
, 16, CurrIcon
+ 12);
639 PUT_SHORT(buffer
, 18, ptr
);
640 ptr
+= strlen(Name
) + 1;
641 PUT_SHORT(buffer
, 20, ptr
);
642 ptr
+= strlen(CmdLine
) + 1;
643 PUT_SHORT(buffer
, 22, ptr
);
645 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 24) ||
646 (UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, Name
, strlen(Name
) + 1) ||
647 (UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, CmdLine
, strlen(CmdLine
) + 1) ||
648 (UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, IconFile
, strlen(IconFile
) + 1))
651 CurrProg
= next_prog
;
652 CurrIcon
= next_icon
;
653 hProgram
= program
->hNext
;
657 #if 0 /* FIXME: this is broken anyway */
658 hProgram
= group
->hPrograms
;
661 PROGRAM
*program
= LocalLock(hProgram
);
662 CURSORICONINFO
*iconinfo
= LocalLock(program
->hIcon
);
663 LPVOID XorBits
, AndBits
;
664 INT sizeXor
= iconinfo
->nHeight
* iconinfo
->nWidthBytes
;
665 INT sizeAnd
= iconinfo
->nHeight
* ((iconinfo
->nWidth
+ 15) / 16 * 2);
666 /* DumpIcon16(LocalLock(program->hIcon), 0, &XorBits, &AndBits);*/
668 PUT_SHORT(buffer
, 0, iconinfo
->ptHotSpot
.x
);
669 PUT_SHORT(buffer
, 2, iconinfo
->ptHotSpot
.y
);
670 PUT_SHORT(buffer
, 4, iconinfo
->nWidth
);
671 PUT_SHORT(buffer
, 6, iconinfo
->nHeight
);
672 PUT_SHORT(buffer
, 8, iconinfo
->nWidthBytes
);
673 buffer
[10] = iconinfo
->bPlanes
;
674 buffer
[11] = iconinfo
->bBitsPerPixel
;
676 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 12) ||
677 (UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, AndBits
, sizeAnd
) ||
678 (UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, XorBits
, sizeXor
)) return FALSE
;
680 hProgram
= program
->hNext
;
686 /* write `PMCC' extension */
687 PUT_SHORT(buffer
, 0, 0x8000);
688 PUT_SHORT(buffer
, 2, 0xffff);
689 PUT_SHORT(buffer
, 4, 0x000a);
690 buffer
[6] = 'P', buffer
[7] = 'M';
691 buffer
[8] = 'C', buffer
[9] = 'C';
692 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 10))
696 hProgram
= group
->hPrograms
;
699 PROGRAM
*program
= LocalLock(hProgram
);
700 LPCSTR lpszWorkDir
= LocalLock(program
->hWorkDir
);
702 /* Working directory */
705 PUT_SHORT(buffer
, 0, 0x8101);
706 PUT_SHORT(buffer
, 2, seqnum
);
707 PUT_SHORT(buffer
, 4, 7 + strlen(lpszWorkDir
));
708 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 6) ||
709 (UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, lpszWorkDir
, strlen(lpszWorkDir
) + 1))
714 if (program
->nHotKey
)
716 PUT_SHORT(buffer
, 0, 0x8102);
717 PUT_SHORT(buffer
, 2, seqnum
);
718 PUT_SHORT(buffer
, 4, 8);
719 PUT_SHORT(buffer
, 6, program
->nHotKey
);
720 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 8)) return FALSE
;
724 if (program
->nCmdShow
)
726 PUT_SHORT(buffer
, 0, 0x8103);
727 PUT_SHORT(buffer
, 2, seqnum
);
728 PUT_SHORT(buffer
, 4, 8);
729 PUT_SHORT(buffer
, 6, program
->nCmdShow
);
730 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 8)) return FALSE
;
734 hProgram
= program
->hNext
;
737 /* Write `End' extension */
738 PUT_SHORT(buffer
, 0, 0xffff);
739 PUT_SHORT(buffer
, 2, 0xffff);
740 PUT_SHORT(buffer
, 4, 0x0000);
741 if ((UINT
)HFILE_ERROR
== GRPFILE_WriteWithChecksum(file
, buffer
, 6)) return FALSE
;
744 checksum
= GRPFILE_GetChecksum();
745 _llseek(file
, 4, SEEK_SET
);
746 PUT_SHORT(buffer
, 0, checksum
);
747 _lwrite(file
, buffer
, 2);