dc024a9a11879b591a7cd3ec471ae09693677f4a
[reactos.git] / reactos / base / shell / progman / grpfile.c
1 /*
2 * Program Manager
3 *
4 * Copyright 1996 Ulrich Schmid
5 * 1997 Peter Schlaile
6 *
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.
11 *
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.
16 *
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
20 */
21
22 #include "progman.h"
23 // #include <mmsystem.h>
24
25 #define MALLOCHUNK 1000
26
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))
33
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);
39
40 /***********************************************************************
41 *
42 * GRPFILE_ModifyFileName
43 *
44 * Change extension `.grp' to `.gr'
45 */
46
47 static VOID GRPFILE_ModifyFileName(LPSTR lpszNewName, LPCSTR lpszOrigName,
48 INT nSize, BOOL bModify)
49 {
50 lstrcpynA(lpszNewName, lpszOrigName, nSize);
51 lpszNewName[nSize-1] = '\0';
52 if (!bModify) return;
53 if (!lstrcmpiA(lpszNewName + strlen(lpszNewName) - 4, ".grp"))
54 lpszNewName[strlen(lpszNewName) - 1] = '\0';
55 }
56
57 /***********************************************************************
58 *
59 * GRPFILE_ReadGroupFile
60 */
61
62 HLOCAL GRPFILE_ReadGroupFile(LPCSTR lpszPath)
63 {
64 CHAR szPath_gr[MAX_PATHNAME_LEN];
65 BOOL bFileNameModified = FALSE;
66 OFSTRUCT dummy;
67 HLOCAL hBuffer, hGroup;
68 INT size;
69
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)
73 {
74 lpszPath = szPath_gr;
75 bFileNameModified = TRUE;
76 }
77
78 /* Read the whole file into a buffer */
79 if (!GRPFILE_ReadFileToBuffer(lpszPath, &hBuffer, &size))
80 {
81 MAIN_MessageBoxIDS_s(IDS_GRPFILE_READ_ERROR_s, lpszPath, IDS_ERROR, MB_YESNO);
82 return(0);
83 }
84
85 /* Interpret buffer */
86 hGroup = GRPFILE_ScanGroup(LocalLock(hBuffer), size,
87 lpszPath, bFileNameModified);
88 if (!hGroup)
89 MAIN_MessageBoxIDS_s(IDS_GRPFILE_READ_ERROR_s, lpszPath, IDS_ERROR, MB_YESNO);
90
91 LocalFree(hBuffer);
92
93 return(hGroup);
94 }
95
96 /***********************************************************************
97 *
98 * GRPFILE_ReadFileToBuffer
99 */
100
101 static BOOL GRPFILE_ReadFileToBuffer(LPCSTR path, HLOCAL *phBuffer,
102 INT *piSize)
103 {
104 UINT len, size;
105 LPSTR buffer;
106 HLOCAL hBuffer, hNewBuffer;
107 HFILE file;
108
109 file=_lopen(path, OF_READ);
110 if (file == HFILE_ERROR) return FALSE;
111
112 size = 0;
113 hBuffer = LocalAlloc(LMEM_FIXED, MALLOCHUNK + 1);
114 if (!hBuffer) return FALSE;
115 buffer = LocalLock(hBuffer);
116
117 while ((len = _lread(file, buffer + size, MALLOCHUNK))
118 == MALLOCHUNK)
119 {
120 size += len;
121 hNewBuffer = LocalReAlloc(hBuffer, size + MALLOCHUNK + 1,
122 LMEM_MOVEABLE);
123 if (!hNewBuffer)
124 {
125 LocalFree(hBuffer);
126 return FALSE;
127 }
128 hBuffer = hNewBuffer;
129 buffer = LocalLock(hBuffer);
130 }
131
132 _lclose(file);
133
134 if (len == (UINT)HFILE_ERROR)
135 {
136 LocalFree(hBuffer);
137 return FALSE;
138 }
139
140 size += len;
141 buffer[size] = 0;
142
143 *phBuffer = hBuffer;
144 *piSize = size;
145 return TRUE;
146 }
147
148 /***********************************************************************
149 * GRPFILE_ScanGroup
150 */
151
152 static HLOCAL GRPFILE_ScanGroup(LPCSTR buffer, INT size,
153 LPCSTR lpszGrpFile,
154 BOOL bModifiedFileName)
155 {
156 HLOCAL hGroup;
157 INT i, seqnum;
158 LPCSTR extension;
159 LPCSTR lpszName;
160 INT x, y, width, height, iconx, icony, nCmdShow;
161 INT number_of_programs;
162 BOOL bOverwriteFileOk;
163
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;
171 else return(0);
172
173 /* checksum = GET_USHORT(buffer, 4) (ignored) */
174
175 extension = buffer + GET_USHORT(buffer, 6);
176 if (extension == buffer + size) extension = 0;
177 else if (extension + 6 > buffer + size) return(0);
178
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);
188
189 /* unknown bytes 24 - 31 ignored */
190 /*
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);
197 */
198
199 hGroup = GROUP_AddGroup(lpszName, lpszGrpFile, nCmdShow, x, y,
200 width, height, iconx, icony,
201 bModifiedFileName, bOverwriteFileOk,
202 TRUE);
203 if (!hGroup) return(0);
204
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++)
208 {
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))
214 {
215 GROUP_DeleteGroup(hGroup);
216 return(0);
217 }
218 }
219
220 /* FIXME shouldn't be necessary */
221 GROUP_ShowGroupWindow(hGroup);
222
223 return hGroup;
224 }
225
226 /***********************************************************************
227 * GRPFILE_ScanProgram
228 */
229
230 static HLOCAL GRPFILE_ScanProgram(LPCSTR buffer, INT size,
231 LPCSTR program_ptr, INT seqnum,
232 LPCSTR extension, HLOCAL hGroup,
233 LPCSTR lpszGrpFile)
234 {
235 INT icontype;
236 HICON hIcon;
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;
242
243 x = GET_SHORT(program_ptr, 0);
244 y = GET_SHORT(program_ptr, 2);
245 nIconIndex = GET_USHORT(program_ptr, 4);
246
247 /* FIXME is this correct ?? */
248 icontype = GET_USHORT(program_ptr, 6);
249 switch (icontype)
250 {
251 default:
252 MAIN_MessageBoxIDS_s(IDS_UNKNOWN_FEATURE_s, lpszGrpFile,
253 IDS_WARNING, MB_OK);
254 case 0x048c:
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);
264 break;
265 case 0x000c:
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);
275 }
276
277 if (iconANDbits_ptr + iconANDsize > buffer + size ||
278 iconXORbits_ptr + iconXORsize > buffer + size) return(0);
279
280 hIcon = CreateIcon( Globals.hInstance, width, height, planes, bpp, (PBYTE)iconANDbits_ptr, (PBYTE)iconXORbits_ptr );
281
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);
289
290 /* Scan Extensions */
291 lpszWorkDir = "";
292 nHotKey = 0;
293 nCmdShow = SW_SHOWNORMAL;
294 if (extension)
295 {
296 LPCSTR ptr = extension;
297 while (ptr + 6 <= buffer + size)
298 {
299 UINT type = GET_USHORT(ptr, 0);
300 UINT number = GET_USHORT(ptr, 2);
301 UINT skip = GET_USHORT(ptr, 4);
302
303 if (number == seqnum)
304 {
305 switch (type)
306 {
307 case 0x8000:
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);
311 break;
312 case 0x8101:
313 lpszWorkDir = ptr + 6;
314 break;
315 case 0x8102:
316 if (ptr + 8 > buffer + size) return(0);
317 nHotKey = GET_USHORT(ptr, 6);
318 break;
319 case 0x8103:
320 if (ptr + 8 > buffer + size) return(0);
321 nCmdShow = GET_USHORT(ptr, 6);
322 break;
323 default:
324 MAIN_MessageBoxIDS_s(IDS_UNKNOWN_FEATURE_s,
325 lpszGrpFile, IDS_WARNING, MB_OK);
326 }
327 }
328 if (!skip) break;
329 ptr += skip;
330 }
331 }
332
333 return (PROGRAM_AddProgram(hGroup, hIcon, lpszName, x, y,
334 lpszCmdLine, lpszIconFile,
335 nIconIndex, lpszWorkDir,
336 nHotKey, nCmdShow));
337 }
338
339 /***********************************************************************
340 *
341 * GRPFILE_WriteGroupFile
342 */
343
344 BOOL GRPFILE_WriteGroupFile(HLOCAL hGroup)
345 {
346 CHAR szPath[MAX_PATHNAME_LEN];
347 PROGGROUP *group = LocalLock(hGroup);
348 OFSTRUCT dummy;
349 HFILE file;
350 BOOL ret;
351
352 GRPFILE_ModifyFileName(szPath, LocalLock(group->hGrpFile),
353 MAX_PATHNAME_LEN,
354 group->bFileNameModified);
355
356 /* Try not to overwrite original files */
357
358 /* group->bOverwriteFileOk == TRUE only if a file has the modified format */
359 if (!group->bOverwriteFileOk &&
360 OpenFile(szPath, &dummy, OF_EXIST) != HFILE_ERROR)
361 {
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)
366 {
367 /* File exists. Do not overwrite */
368 MAIN_MessageBoxIDS_s(IDS_FILE_NOT_OVERWRITTEN_s, szPath,
369 IDS_INFO, MB_OK);
370 return FALSE;
371 }
372 /* Inform about the modified file name */
373 if (IDCANCEL ==
374 MAIN_MessageBoxIDS_s(IDS_SAVE_GROUP_AS_s, szPath, IDS_INFO,
375 MB_OKCANCEL | MB_ICONINFORMATION))
376 return FALSE;
377 }
378
379 {
380 /* Warn about the (possible) incompatibility */
381 CHAR msg[MAX_PATHNAME_LEN + 200];
382 wsprintfA(msg,
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;
388 }
389
390 /* Open file */
391 file = _lcreat(szPath, 0);
392 if (file != HFILE_ERROR)
393 {
394 ret = GRPFILE_DoWriteGroupFile(file, group);
395 _lclose(file);
396 }
397 else ret = FALSE;
398
399 if (!ret)
400 MAIN_MessageBoxIDS_s(IDS_FILE_WRITE_ERROR_s, szPath, IDS_ERROR, MB_OK);
401
402 return(ret);
403 }
404
405 /***********************************************************************
406 *
407 * GRPFILE_CalculateSizes
408 */
409
410 static VOID GRPFILE_CalculateSizes(PROGRAM *program, INT *Progs, INT *Icons,
411 UINT *sizeAnd, UINT *sizeXor)
412 {
413 ICONINFO info;
414 BITMAP bmp;
415
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 );
423
424 *Progs += 24;
425 *Progs += strlen(LocalLock(program->hName)) + 1;
426 *Progs += strlen(LocalLock(program->hCmdLine)) + 1;
427 *Progs += strlen(LocalLock(program->hIconFile)) + 1;
428
429 *Icons += 12; /* IconInfo */
430 *Icons += *sizeAnd;
431 *Icons += *sizeXor;
432 }
433
434 /***********************************************************************/
435 UINT16 GRPFILE_checksum;
436 BOOL GRPFILE_checksum_half_word;
437 BYTE GRPFILE_checksum_last_byte;
438 /***********************************************************************
439 *
440 * GRPFILE_InitChecksum
441 */
442
443 static void GRPFILE_InitChecksum(void)
444 {
445 GRPFILE_checksum = 0;
446 GRPFILE_checksum_half_word = 0;
447 }
448
449 /***********************************************************************
450 *
451 * GRPFILE_GetChecksum
452 */
453
454 static UINT16 GRPFILE_GetChecksum(void)
455 {
456 return GRPFILE_checksum;
457 }
458
459 /***********************************************************************
460 *
461 * GRPFILE_WriteWithChecksum
462 *
463 * Looks crazier than it is:
464 *
465 * chksum = 0;
466 * chksum = cksum - 1. word;
467 * chksum = cksum - 2. word;
468 * ...
469 *
470 * if (filelen is even)
471 * great I'm finished
472 * else
473 * ignore last byte
474 */
475
476 static UINT GRPFILE_WriteWithChecksum(HFILE file, LPCSTR str, UINT size)
477 {
478 UINT i;
479 if (GRPFILE_checksum_half_word) {
480 GRPFILE_checksum -= GRPFILE_checksum_last_byte;
481 }
482 for (i=0; i < size; i++) {
483 if (GRPFILE_checksum_half_word) {
484 GRPFILE_checksum -= str[i] << 8;
485 } else {
486 GRPFILE_checksum -= str[i];
487 }
488 GRPFILE_checksum_half_word ^= 1;
489 }
490
491 if (GRPFILE_checksum_half_word) {
492 GRPFILE_checksum_last_byte = str[size-1];
493 GRPFILE_checksum += GRPFILE_checksum_last_byte;
494 }
495
496 return _lwrite(file, str, size);
497 }
498
499
500 /***********************************************************************
501 *
502 * GRPFILE_DoWriteGroupFile
503 */
504
505 static BOOL GRPFILE_DoWriteGroupFile(HFILE file, PROGGROUP *group)
506 {
507 CHAR buffer[34];
508 HLOCAL hProgram;
509 INT NumProg, Title, Progs, Icons, Extension;
510 INT CurrProg, CurrIcon, nCmdShow, ptr, seqnum;
511 UINT sizeAnd, sizeXor;
512 BOOL need_extension;
513 LPCSTR lpszTitle = LocalLock(group->hName);
514
515 UINT16 checksum;
516
517 GRPFILE_InitChecksum();
518
519 /* Calculate offsets */
520 NumProg = 0;
521 Icons = 0;
522 Extension = 0;
523 need_extension = FALSE;
524 hProgram = group->hPrograms;
525 while(hProgram)
526 {
527 PROGRAM *program = LocalLock(hProgram);
528 LPCSTR lpszWorkDir = LocalLock(program->hWorkDir);
529
530 NumProg++;
531 GRPFILE_CalculateSizes(program, &Icons, &Extension, &sizeAnd, &sizeXor);
532
533 /* Set a flag if an extension is needed */
534 if (lpszWorkDir[0] || program->nHotKey ||
535 program->nCmdShow != SW_SHOWNORMAL) need_extension = TRUE;
536
537 hProgram = program->hNext;
538 }
539 Title = 34 + NumProg * 2;
540 Progs = Title + strlen(lpszTitle) + 1;
541 Icons += Progs;
542 Extension += Icons;
543
544 /* Header */
545 buffer[0] = 'P';
546 buffer[1] = 'M';
547 buffer[2] = 'C';
548 buffer[3] = 'C';
549
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);
569
570 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 34)) return FALSE;
571
572 /* Program table */
573 CurrProg = Progs;
574 CurrIcon = Icons;
575 hProgram = group->hPrograms;
576 while(hProgram)
577 {
578 PROGRAM *program = LocalLock(hProgram);
579
580 PUT_SHORT(buffer, 0, CurrProg);
581 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 2))
582 return FALSE;
583
584 GRPFILE_CalculateSizes(program, &CurrProg, &CurrIcon, &sizeAnd, &sizeXor);
585 hProgram = program->hNext;
586 }
587
588 /* Title */
589 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, lpszTitle, strlen(lpszTitle) + 1))
590 return FALSE;
591
592 /* Program entries */
593 CurrProg = Progs;
594 CurrIcon = Icons;
595 hProgram = group->hPrograms;
596 while(hProgram)
597 {
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;
604
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);
615 ptr = CurrProg + 24;
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);
621
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))
626 return FALSE;
627
628 CurrProg = next_prog;
629 CurrIcon = next_icon;
630 hProgram = program->hNext;
631 }
632
633 /* Icons */
634 #if 0 /* FIXME: this is broken anyway */
635 hProgram = group->hPrograms;
636 while(hProgram)
637 {
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);*/
644
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;
652
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;
656
657 hProgram = program->hNext;
658 }
659 #endif
660
661 if (need_extension)
662 {
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))
670 return FALSE;
671
672 seqnum = 0;
673 hProgram = group->hPrograms;
674 while(hProgram)
675 {
676 PROGRAM *program = LocalLock(hProgram);
677 LPCSTR lpszWorkDir = LocalLock(program->hWorkDir);
678
679 /* Working directory */
680 if (lpszWorkDir[0])
681 {
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))
687 return FALSE;
688 }
689
690 /* Hot key */
691 if (program->nHotKey)
692 {
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;
698 }
699
700 /* Show command */
701 if (program->nCmdShow)
702 {
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;
708 }
709
710 seqnum++;
711 hProgram = program->hNext;
712 }
713
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;
719 }
720
721 checksum = GRPFILE_GetChecksum();
722 _llseek(file, 4, SEEK_SET);
723 PUT_SHORT(buffer, 0, checksum);
724 _lwrite(file, buffer, 2);
725
726 return TRUE;
727 }