[DCOMLAUNCH] Add a DcomLaunch service stub
[reactos.git] / 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
24 #if 0
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 #endif
40
41 /***********************************************************************
42 *
43 * GRPFILE_ModifyFileName
44 *
45 * Change extension `.grp' to `.gr'
46 */
47
48 #if 0
49 static VOID GRPFILE_ModifyFileName(LPSTR lpszNewName, LPCSTR lpszOrigName,
50 INT nSize, BOOL bModify)
51 {
52 lstrcpynA(lpszNewName, lpszOrigName, nSize);
53 lpszNewName[nSize-1] = '\0';
54 if (!bModify) return;
55 if (!lstrcmpiA(lpszNewName + strlen(lpszNewName) - 4, ".grp"))
56 lpszNewName[strlen(lpszNewName) - 1] = '\0';
57 }
58 #endif
59
60 /***********************************************************************
61 *
62 * GRPFILE_ReadGroupFile
63 */
64
65 DWORD GRPFILE_ReadGroupFile(LPCWSTR lpszPath, BOOL bIsCommonGroup)
66 {
67 #if 0
68 CHAR szPath_gr[MAX_PATHNAME_LEN];
69 BOOL bFileNameModified = FALSE;
70 OFSTRUCT dummy;
71 HLOCAL hBuffer, hGroup;
72 INT size;
73
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)
77 {
78 lpszPath = szPath_gr;
79 bFileNameModified = TRUE;
80 }
81
82 /* Read the whole file into a buffer */
83 if (!GRPFILE_ReadFileToBuffer(lpszPath, &hBuffer, &size))
84 {
85 MAIN_MessageBoxIDS_s(IDS_GRPFILE_READ_ERROR_s, lpszPath, IDS_ERROR, MB_YESNO);
86 return(0);
87 }
88
89 /* Interpret buffer */
90 hGroup = GRPFILE_ScanGroup(LocalLock(hBuffer), size,
91 lpszPath, bFileNameModified);
92 if (!hGroup)
93 MAIN_MessageBoxIDS_s(IDS_GRPFILE_READ_ERROR_s, lpszPath, IDS_ERROR, MB_YESNO);
94
95 LocalFree(hBuffer);
96
97 return(hGroup);
98
99 #else
100 return ERROR_SUCCESS;
101 #endif
102 }
103
104 /***********************************************************************
105 *
106 * GRPFILE_ReadFileToBuffer
107 */
108
109 #if 0
110 static BOOL GRPFILE_ReadFileToBuffer(LPCSTR path, HLOCAL *phBuffer,
111 INT *piSize)
112 {
113 UINT len, size;
114 LPSTR buffer;
115 HLOCAL hBuffer, hNewBuffer;
116 HFILE file;
117
118 file=_lopen(path, OF_READ);
119 if (file == HFILE_ERROR) return FALSE;
120
121 size = 0;
122 hBuffer = LocalAlloc(LMEM_FIXED, MALLOCHUNK + 1);
123 if (!hBuffer) return FALSE;
124 buffer = LocalLock(hBuffer);
125
126 while ((len = _lread(file, buffer + size, MALLOCHUNK))
127 == MALLOCHUNK)
128 {
129 size += len;
130 hNewBuffer = LocalReAlloc(hBuffer, size + MALLOCHUNK + 1,
131 LMEM_MOVEABLE);
132 if (!hNewBuffer)
133 {
134 LocalFree(hBuffer);
135 return FALSE;
136 }
137 hBuffer = hNewBuffer;
138 buffer = LocalLock(hBuffer);
139 }
140
141 _lclose(file);
142
143 if (len == (UINT)HFILE_ERROR)
144 {
145 LocalFree(hBuffer);
146 return FALSE;
147 }
148
149 size += len;
150 buffer[size] = 0;
151
152 *phBuffer = hBuffer;
153 *piSize = size;
154 return TRUE;
155 }
156 #endif
157
158 /***********************************************************************
159 * GRPFILE_ScanGroup
160 */
161
162 #if 0
163 static HLOCAL GRPFILE_ScanGroup(LPCSTR buffer, INT size,
164 LPCSTR lpszGrpFile,
165 BOOL bModifiedFileName)
166 {
167 HLOCAL hGroup;
168 INT i, seqnum;
169 LPCSTR extension;
170 LPCSTR lpszName;
171 INT x, y, width, height, iconx, icony, nCmdShow;
172 INT number_of_programs;
173 BOOL bOverwriteFileOk;
174
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;
182 else return(0);
183
184 /* checksum = GET_USHORT(buffer, 4) (ignored) */
185
186 extension = buffer + GET_USHORT(buffer, 6);
187 if (extension == buffer + size) extension = 0;
188 else if (extension + 6 > buffer + size) return(0);
189
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);
199
200 /* unknown bytes 24 - 31 ignored */
201 /*
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);
208 */
209
210 hGroup = GROUP_AddGroup(lpszName, lpszGrpFile, nCmdShow, x, y,
211 width, height, iconx, icony,
212 bModifiedFileName, bOverwriteFileOk,
213 TRUE);
214 if (!hGroup) return(0);
215
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++)
219 {
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))
225 {
226 GROUP_DeleteGroup(hGroup);
227 return(0);
228 }
229 }
230
231 /* FIXME shouldn't be necessary */
232 GROUP_ShowGroupWindow(hGroup);
233
234 return hGroup;
235 }
236 #endif
237
238 /***********************************************************************
239 * GRPFILE_ScanProgram
240 */
241
242 #if 0
243 static HLOCAL GRPFILE_ScanProgram(LPCSTR buffer, INT size,
244 LPCSTR program_ptr, INT seqnum,
245 LPCSTR extension, HLOCAL hGroup,
246 LPCSTR lpszGrpFile)
247 {
248 INT icontype;
249 HICON hIcon;
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;
255
256 x = GET_SHORT(program_ptr, 0);
257 y = GET_SHORT(program_ptr, 2);
258 nIconIndex = GET_USHORT(program_ptr, 4);
259
260 /* FIXME is this correct ?? */
261 icontype = GET_USHORT(program_ptr, 6);
262 switch (icontype)
263 {
264 default:
265 MAIN_MessageBoxIDS_s(IDS_UNKNOWN_FEATURE_s, lpszGrpFile,
266 IDS_WARNING, MB_OK);
267 case 0x048c:
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);
277 break;
278 case 0x000c:
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);
288 }
289
290 if (iconANDbits_ptr + iconANDsize > buffer + size ||
291 iconXORbits_ptr + iconXORsize > buffer + size) return(0);
292
293 hIcon = CreateIcon(Globals.hInstance, width, height, planes, bpp, (PBYTE)iconANDbits_ptr, (PBYTE)iconXORbits_ptr);
294
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);
302
303 /* Scan Extensions */
304 lpszWorkDir = "";
305 nHotKey = 0;
306 nCmdShow = SW_SHOWNORMAL;
307 if (extension)
308 {
309 LPCSTR ptr = extension;
310 while (ptr + 6 <= buffer + size)
311 {
312 UINT type = GET_USHORT(ptr, 0);
313 UINT number = GET_USHORT(ptr, 2);
314 UINT skip = GET_USHORT(ptr, 4);
315
316 if (number == seqnum)
317 {
318 switch (type)
319 {
320 case 0x8000:
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);
324 break;
325 case 0x8101:
326 lpszWorkDir = ptr + 6;
327 break;
328 case 0x8102:
329 if (ptr + 8 > buffer + size) return(0);
330 nHotKey = GET_USHORT(ptr, 6);
331 break;
332 case 0x8103:
333 if (ptr + 8 > buffer + size) return(0);
334 nCmdShow = GET_USHORT(ptr, 6);
335 break;
336 default:
337 MAIN_MessageBoxIDS_s(IDS_UNKNOWN_FEATURE_s,
338 lpszGrpFile, IDS_WARNING, MB_OK);
339 }
340 }
341 if (!skip) break;
342 ptr += skip;
343 }
344 }
345
346 return (PROGRAM_AddProgram(hGroup, hIcon, lpszName, x, y,
347 lpszCmdLine, lpszIconFile,
348 nIconIndex, lpszWorkDir,
349 nHotKey, nCmdShow));
350 }
351 #endif
352
353 /***********************************************************************
354 *
355 * GRPFILE_WriteGroupFile
356 */
357
358 BOOL GRPFILE_WriteGroupFile(PROGGROUP* hGroup)
359 {
360 #if 0
361 CHAR szPath[MAX_PATHNAME_LEN];
362 PROGGROUP *group = LocalLock(hGroup);
363 OFSTRUCT dummy;
364 HFILE file;
365 BOOL ret;
366
367 GRPFILE_ModifyFileName(szPath, LocalLock(group->hGrpFile),
368 MAX_PATHNAME_LEN,
369 group->bFileNameModified);
370
371 /* Try not to overwrite original files */
372
373 /* group->bOverwriteFileOk == TRUE only if a file has the modified format */
374 if (!group->bOverwriteFileOk &&
375 OpenFile(szPath, &dummy, OF_EXIST) != HFILE_ERROR)
376 {
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)
381 {
382 /* File exists. Do not overwrite */
383 MAIN_MessageBoxIDS_s(IDS_FILE_NOT_OVERWRITTEN_s, szPath,
384 IDS_INFO, MB_OK);
385 return FALSE;
386 }
387 /* Inform about the modified file name */
388 if (IDCANCEL ==
389 MAIN_MessageBoxIDS_s(IDS_SAVE_GROUP_AS_s, szPath, IDS_INFO,
390 MB_OKCANCEL | MB_ICONINFORMATION))
391 return FALSE;
392 }
393
394 {
395 /* Warn about the (possible) incompatibility */
396 CHAR msg[MAX_PATHNAME_LEN + 200];
397 wsprintfA(msg,
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;
403 }
404
405 /* Open file */
406 file = _lcreat(szPath, 0);
407 if (file != HFILE_ERROR)
408 {
409 ret = GRPFILE_DoWriteGroupFile(file, group);
410 _lclose(file);
411 }
412 else ret = FALSE;
413
414 if (!ret)
415 MAIN_MessageBoxIDS_s(IDS_FILE_WRITE_ERROR_s, szPath, IDS_ERROR, MB_OK);
416
417 return(ret);
418
419 #else
420 return TRUE;
421 #endif
422 }
423
424 #if 0
425
426 /***********************************************************************
427 *
428 * GRPFILE_CalculateSizes
429 */
430
431 static VOID GRPFILE_CalculateSizes(PROGRAM *program, INT *Progs, INT *Icons,
432 UINT *sizeAnd, UINT *sizeXor)
433 {
434 ICONINFO info;
435 BITMAP bmp;
436
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 );
444
445 *Progs += 24;
446 *Progs += strlen(LocalLock(program->hName)) + 1;
447 *Progs += strlen(LocalLock(program->hCmdLine)) + 1;
448 *Progs += strlen(LocalLock(program->hIconFile)) + 1;
449
450 *Icons += 12; /* IconInfo */
451 *Icons += *sizeAnd;
452 *Icons += *sizeXor;
453 }
454
455 /***********************************************************************/
456 UINT16 GRPFILE_checksum;
457 BOOL GRPFILE_checksum_half_word;
458 BYTE GRPFILE_checksum_last_byte;
459 /***********************************************************************
460 *
461 * GRPFILE_InitChecksum
462 */
463
464 static void GRPFILE_InitChecksum(void)
465 {
466 GRPFILE_checksum = 0;
467 GRPFILE_checksum_half_word = 0;
468 }
469
470 /***********************************************************************
471 *
472 * GRPFILE_GetChecksum
473 */
474
475 static UINT16 GRPFILE_GetChecksum(void)
476 {
477 return GRPFILE_checksum;
478 }
479
480 /***********************************************************************
481 *
482 * GRPFILE_WriteWithChecksum
483 *
484 * Looks crazier than it is:
485 *
486 * chksum = 0;
487 * chksum = cksum - 1. word;
488 * chksum = cksum - 2. word;
489 * ...
490 *
491 * if (filelen is even)
492 * great I'm finished
493 * else
494 * ignore last byte
495 */
496
497 static UINT GRPFILE_WriteWithChecksum(HFILE file, LPCSTR str, UINT size)
498 {
499 UINT i;
500 if (GRPFILE_checksum_half_word) {
501 GRPFILE_checksum -= GRPFILE_checksum_last_byte;
502 }
503 for (i=0; i < size; i++) {
504 if (GRPFILE_checksum_half_word) {
505 GRPFILE_checksum -= str[i] << 8;
506 } else {
507 GRPFILE_checksum -= str[i];
508 }
509 GRPFILE_checksum_half_word ^= 1;
510 }
511
512 if (GRPFILE_checksum_half_word) {
513 GRPFILE_checksum_last_byte = str[size-1];
514 GRPFILE_checksum += GRPFILE_checksum_last_byte;
515 }
516
517 return _lwrite(file, str, size);
518 }
519
520
521 /***********************************************************************
522 *
523 * GRPFILE_DoWriteGroupFile
524 */
525
526 static BOOL GRPFILE_DoWriteGroupFile(HFILE file, PROGGROUP *group)
527 {
528 CHAR buffer[34];
529 HLOCAL hProgram;
530 INT NumProg, Title, Progs, Icons, Extension;
531 INT CurrProg, CurrIcon, nCmdShow, ptr, seqnum;
532
533 UINT sizeAnd, sizeXor;
534
535 BOOL need_extension;
536 LPCSTR lpszTitle = LocalLock(group->hName);
537
538 UINT16 checksum;
539
540 GRPFILE_InitChecksum();
541
542 /* Calculate offsets */
543 NumProg = 0;
544 Icons = 0;
545 Extension = 0;
546 need_extension = FALSE;
547 hProgram = group->hPrograms;
548 while(hProgram)
549 {
550 PROGRAM *program = LocalLock(hProgram);
551 LPCSTR lpszWorkDir = LocalLock(program->hWorkDir);
552
553 NumProg++;
554 GRPFILE_CalculateSizes(program, &Icons, &Extension, &sizeAnd, &sizeXor);
555
556 /* Set a flag if an extension is needed */
557 if (lpszWorkDir[0] || program->nHotKey ||
558 program->nCmdShow != SW_SHOWNORMAL) need_extension = TRUE;
559
560 hProgram = program->hNext;
561 }
562 Title = 34 + NumProg * 2;
563 Progs = Title + strlen(lpszTitle) + 1;
564 Icons += Progs;
565 Extension += Icons;
566
567 /* Header */
568 buffer[0] = 'P';
569 buffer[1] = 'M';
570 buffer[2] = 'C';
571 buffer[3] = 'C';
572
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);
592
593 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 34)) return FALSE;
594
595 /* Program table */
596 CurrProg = Progs;
597 CurrIcon = Icons;
598 hProgram = group->hPrograms;
599 while(hProgram)
600 {
601 PROGRAM *program = LocalLock(hProgram);
602
603 PUT_SHORT(buffer, 0, CurrProg);
604 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 2))
605 return FALSE;
606
607 GRPFILE_CalculateSizes(program, &CurrProg, &CurrIcon, &sizeAnd, &sizeXor);
608 hProgram = program->hNext;
609 }
610
611 /* Title */
612 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, lpszTitle, strlen(lpszTitle) + 1))
613 return FALSE;
614
615 /* Program entries */
616 CurrProg = Progs;
617 CurrIcon = Icons;
618 hProgram = group->hPrograms;
619 while(hProgram)
620 {
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;
627
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);
638 ptr = CurrProg + 24;
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);
644
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))
649 return FALSE;
650
651 CurrProg = next_prog;
652 CurrIcon = next_icon;
653 hProgram = program->hNext;
654 }
655
656 /* Icons */
657 #if 0 /* FIXME: this is broken anyway */
658 hProgram = group->hPrograms;
659 while(hProgram)
660 {
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);*/
667
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;
675
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;
679
680 hProgram = program->hNext;
681 }
682 #endif
683
684 if (need_extension)
685 {
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))
693 return FALSE;
694
695 seqnum = 0;
696 hProgram = group->hPrograms;
697 while(hProgram)
698 {
699 PROGRAM *program = LocalLock(hProgram);
700 LPCSTR lpszWorkDir = LocalLock(program->hWorkDir);
701
702 /* Working directory */
703 if (lpszWorkDir[0])
704 {
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))
710 return FALSE;
711 }
712
713 /* Hot key */
714 if (program->nHotKey)
715 {
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;
721 }
722
723 /* Show command */
724 if (program->nCmdShow)
725 {
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;
731 }
732
733 seqnum++;
734 hProgram = program->hNext;
735 }
736
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;
742 }
743
744 checksum = GRPFILE_GetChecksum();
745 _llseek(file, 4, SEEK_SET);
746 PUT_SHORT(buffer, 0, checksum);
747 _lwrite(file, buffer, 2);
748
749 return TRUE;
750 }
751
752 #endif