Reimplemented Read/WriteFile to use server file descriptors.
[wine/multimedia.git] / programs / progman / grpfile.c
blob01c83de18f6ee5a417bc285fcbdb1a4d286e73b8
1 /*
2 * Program Manager
4 * Copyright 1996 Ulrich Schmid
5 * 1997 Peter Schlaile
6 */
8 #include "windows.h"
9 #include "progman.h"
10 #include "mmsystem.h"
12 #define MALLOCHUNK 1000
14 #define GET_USHORT(buffer, i)\
15 (((BYTE)((buffer)[(i)]) + 0x100 * (BYTE)((buffer)[(i)+1])))
16 #define GET_SHORT(buffer, i)\
17 (((BYTE)((buffer)[(i)]) + 0x100 * (signed char)((buffer)[(i)+1])))
18 #define PUT_SHORT(buffer, i, s)\
19 (((buffer)[(i)] = (s) & 0xff, (buffer)[(i)+1] = ((s) >> 8) & 0xff))
21 static BOOL GRPFILE_ReadFileToBuffer(LPCSTR, HLOCAL*, INT*);
22 static HLOCAL GRPFILE_ScanGroup(LPCSTR, INT, LPCSTR, BOOL);
23 static HLOCAL GRPFILE_ScanProgram(LPCSTR, INT, LPCSTR, INT,
24 LPCSTR, HLOCAL,LPCSTR);
25 static BOOL GRPFILE_DoWriteGroupFile(HFILE file, GROUP *group);
27 /***********************************************************************
29 * GRPFILE_ModifyFileName
31 * Change extension `.grp' to `.gr'
34 static VOID GRPFILE_ModifyFileName(LPSTR lpszNewName, LPCSTR lpszOrigName,
35 INT nSize, BOOL bModify)
37 lstrcpyn(lpszNewName, lpszOrigName, nSize);
38 lpszNewName[nSize-1] = '\0';
39 if (!bModify) return;
40 if (!lstrcmpi(lpszNewName + strlen(lpszNewName) - 4, ".grp"))
41 lpszNewName[strlen(lpszNewName) - 1] = '\0';
44 /***********************************************************************
46 * GRPFILE_ReadGroupFile
49 HLOCAL GRPFILE_ReadGroupFile(LPCSTR lpszPath)
51 CHAR szPath_gr[MAX_PATHNAME_LEN];
52 BOOL bFileNameModified = FALSE;
53 OFSTRUCT dummy;
54 HLOCAL hBuffer, hGroup;
55 INT size;
57 /* if `.gr' file exists use that */
58 GRPFILE_ModifyFileName(szPath_gr, lpszPath, MAX_PATHNAME_LEN, TRUE);
59 if (OpenFile(szPath_gr, &dummy, OF_EXIST) != HFILE_ERROR)
61 lpszPath = szPath_gr;
62 bFileNameModified = TRUE;
65 /* Read the whole file into a buffer */
66 if (!GRPFILE_ReadFileToBuffer(lpszPath, &hBuffer, &size))
68 MAIN_MessageBoxIDS_s(IDS_GRPFILE_READ_ERROR_s, lpszPath, IDS_ERROR, MB_YESNO);
69 return(0);
72 /* Interpret buffer */
73 hGroup = GRPFILE_ScanGroup(LocalLock(hBuffer), size,
74 lpszPath, bFileNameModified);
75 if (!hGroup)
76 MAIN_MessageBoxIDS_s(IDS_GRPFILE_READ_ERROR_s, lpszPath, IDS_ERROR, MB_YESNO);
78 LocalFree(hBuffer);
80 return(hGroup);
83 /***********************************************************************
85 * GRPFILE_ReadFileToBuffer
88 static BOOL GRPFILE_ReadFileToBuffer(LPCSTR path, HLOCAL *phBuffer,
89 INT *piSize)
91 INT len, size;
92 LPSTR buffer;
93 HLOCAL hBuffer, hNewBuffer;
94 HFILE file;
96 file=_lopen(path, OF_READ);
97 if (file == HFILE_ERROR) return FALSE;
99 size = 0;
100 hBuffer = LocalAlloc(LMEM_FIXED, size + MALLOCHUNK + 1);
101 if (!hBuffer) return FALSE;
102 buffer = LocalLock(hBuffer);
104 while ((len = _lread(file, buffer + size, MALLOCHUNK))
105 == MALLOCHUNK)
107 size += len;
108 hNewBuffer = LocalReAlloc(hBuffer, size + MALLOCHUNK + 1,
109 LMEM_FIXED);
110 if (!hNewBuffer)
112 LocalFree(hBuffer);
113 return FALSE;
115 hBuffer = hNewBuffer;
116 buffer = LocalLock(hBuffer);
119 _lclose(file);
121 if (len == HFILE_ERROR)
123 LocalFree(hBuffer);
124 return FALSE;
127 size += len;
128 buffer[size] = 0;
130 *phBuffer = hBuffer;
131 *piSize = size;
132 return TRUE;
135 /***********************************************************************
136 * GRPFILE_ScanGroup
139 static HLOCAL GRPFILE_ScanGroup(LPCSTR buffer, INT size,
140 LPCSTR lpszGrpFile,
141 BOOL bModifiedFileName)
143 HLOCAL hGroup;
144 INT i, seqnum;
145 LPCSTR extension;
146 LPCSTR lpszName;
147 INT x, y, width, height, iconx, icony, nCmdShow;
148 INT number_of_programs;
149 BOOL bOverwriteFileOk;
151 if (buffer[0] != 'P' || buffer[1] != 'M') return(0);
152 if (buffer[2] == 'C' && buffer[3] == 'C')
153 /* original with checksum */
154 bOverwriteFileOk = FALSE;
155 else if (buffer[2] == 'X' && buffer[3] == 'X')
156 /* modified without checksum */
157 bOverwriteFileOk = TRUE;
158 else return(0);
160 /* checksum = GET_USHORT(buffer, 4) (ignored) */
162 extension = buffer + GET_USHORT(buffer, 6);
163 if (extension == buffer + size) extension = 0;
164 else if (extension + 6 > buffer + size) return(0);
166 nCmdShow = GET_USHORT(buffer, 8);
167 x = GET_SHORT(buffer, 10);
168 y = GET_SHORT(buffer, 12);
169 width = GET_USHORT(buffer, 14);
170 height = GET_USHORT(buffer, 16);
171 iconx = GET_SHORT(buffer, 18);
172 icony = GET_SHORT(buffer, 20);
173 lpszName = buffer + GET_USHORT(buffer, 22);
174 if (lpszName >= buffer + size) return(0);
176 /* unknown bytes 24 - 31 ignored */
178 Unknown bytes should be:
179 wLogPixelsX = GET_SHORT(buffer, 24);
180 wLogPixelsY = GET_SHORT(buffer, 26);
181 byBitsPerPixel = byte at 28;
182 byPlanes = byte at 29;
183 wReserved = GET_SHORT(buffer, 30);
186 hGroup = GROUP_AddGroup(lpszName, lpszGrpFile, nCmdShow, x, y,
187 width, height, iconx, icony,
188 bModifiedFileName, bOverwriteFileOk,
189 TRUE);
190 if (!hGroup) return(0);
192 number_of_programs = GET_USHORT(buffer, 32);
193 if (2 * number_of_programs + 34 > size) return(0);
194 for (i=0, seqnum=0; i < number_of_programs; i++, seqnum++)
196 LPCSTR program_ptr = buffer + GET_USHORT(buffer, 34 + 2*i);
197 if (program_ptr + 24 > buffer + size) return(0);
198 if (!GET_USHORT(buffer, 34 + 2*i)) continue;
199 if (!GRPFILE_ScanProgram(buffer, size, program_ptr, seqnum,
200 extension, hGroup, lpszGrpFile))
202 GROUP_DeleteGroup(hGroup);
203 return(0);
207 /* FIXME shouldn't be necessary */
208 GROUP_ShowGroupWindow(hGroup);
210 return hGroup;
213 /***********************************************************************
214 * GRPFILE_ScanProgram
217 static HLOCAL GRPFILE_ScanProgram(LPCSTR buffer, INT size,
218 LPCSTR program_ptr, INT seqnum,
219 LPCSTR extension, HLOCAL hGroup,
220 LPCSTR lpszGrpFile)
222 INT icontype;
223 HICON hIcon;
224 LPCSTR lpszName, lpszCmdLine, lpszIconFile, lpszWorkDir;
225 LPCSTR iconinfo_ptr, iconANDbits_ptr, iconXORbits_ptr;
226 INT x, y, nIconIndex, iconANDsize, iconXORsize;
227 INT nHotKey, nCmdShow;
228 CURSORICONINFO iconinfo;
230 x = GET_SHORT(program_ptr, 0);
231 y = GET_SHORT(program_ptr, 2);
232 nIconIndex = GET_USHORT(program_ptr, 4);
234 /* FIXME is this correct ?? */
235 icontype = GET_USHORT(program_ptr, 6);
236 switch (icontype)
238 default:
239 MAIN_MessageBoxIDS_s(IDS_UNKNOWN_FEATURE_s, lpszGrpFile,
240 IDS_WARNING, MB_OK);
241 case 0x048c:
242 iconXORsize = GET_USHORT(program_ptr, 8);
243 iconANDsize = GET_USHORT(program_ptr, 10) / 8;
244 iconinfo_ptr = buffer + GET_USHORT(program_ptr, 12);
245 iconXORbits_ptr = buffer + GET_USHORT(program_ptr, 14);
246 iconANDbits_ptr = buffer + GET_USHORT(program_ptr, 16);
247 iconinfo.ptHotSpot.x = GET_USHORT(iconinfo_ptr, 0);
248 iconinfo.ptHotSpot.y = GET_USHORT(iconinfo_ptr, 2);
249 iconinfo.nWidth = GET_USHORT(iconinfo_ptr, 4);
250 iconinfo.nHeight = GET_USHORT(iconinfo_ptr, 6);
251 iconinfo.nWidthBytes = GET_USHORT(iconinfo_ptr, 8);
252 iconinfo.bPlanes = GET_USHORT(iconinfo_ptr, 10);
253 iconinfo.bBitsPerPixel = GET_USHORT(iconinfo_ptr, 11);
254 break;
255 case 0x000c:
256 iconANDsize = GET_USHORT(program_ptr, 8);
257 iconXORsize = GET_USHORT(program_ptr, 10);
258 iconinfo_ptr = buffer + GET_USHORT(program_ptr, 12);
259 iconANDbits_ptr = buffer + GET_USHORT(program_ptr, 14);
260 iconXORbits_ptr = buffer + GET_USHORT(program_ptr, 16);
261 iconinfo.ptHotSpot.x = GET_USHORT(iconinfo_ptr, 0);
262 iconinfo.ptHotSpot.y = GET_USHORT(iconinfo_ptr, 2);
263 iconinfo.nWidth = GET_USHORT(iconinfo_ptr, 4);
264 iconinfo.nHeight = GET_USHORT(iconinfo_ptr, 6);
265 iconinfo.nWidthBytes = GET_USHORT(iconinfo_ptr, 8) * 8;
266 iconinfo.bPlanes = GET_USHORT(iconinfo_ptr, 10);
267 iconinfo.bBitsPerPixel = GET_USHORT(iconinfo_ptr, 11);
270 if (iconANDbits_ptr + iconANDsize > buffer + size ||
271 iconXORbits_ptr + iconXORsize > buffer + size) return(0);
273 hIcon = CreateCursorIconIndirect(Globals.hInstance, &iconinfo,
274 (LPSTR)iconANDbits_ptr,
275 (LPSTR)iconXORbits_ptr);
277 lpszName = buffer + GET_USHORT(program_ptr, 18);
278 lpszCmdLine = buffer + GET_USHORT(program_ptr, 20);
279 lpszIconFile = buffer + GET_USHORT(program_ptr, 22);
280 if (iconinfo_ptr + 6 > buffer + size ||
281 lpszName > buffer + size ||
282 lpszCmdLine > buffer + size ||
283 lpszIconFile > buffer + size) return(0);
285 /* Scan Extensions */
286 lpszWorkDir = "";
287 nHotKey = 0;
288 nCmdShow = SW_SHOWNORMAL;
289 if (extension)
291 LPCSTR ptr = extension;
292 while (ptr + 6 <= buffer + size)
294 UINT type = GET_USHORT(ptr, 0);
295 UINT number = GET_USHORT(ptr, 2);
296 UINT skip = GET_USHORT(ptr, 4);
298 if (number == seqnum)
300 switch (type)
302 case 0x8000:
303 if (ptr + 10 > buffer + size) return(0);
304 if (ptr[6] != 'P' || ptr[7] != 'M' ||
305 ptr[8] != 'C' || ptr[9] != 'C') return(0);
306 break;
307 case 0x8101:
308 lpszWorkDir = ptr + 6;
309 break;
310 case 0x8102:
311 if (ptr + 8 > buffer + size) return(0);
312 nHotKey = GET_USHORT(ptr, 6);
313 break;
314 case 0x8103:
315 if (ptr + 8 > buffer + size) return(0);
316 nCmdShow = GET_USHORT(ptr, 6);
317 break;
318 default:
319 MAIN_MessageBoxIDS_s(IDS_UNKNOWN_FEATURE_s,
320 lpszGrpFile, IDS_WARNING, MB_OK);
323 if (!skip) break;
324 ptr += skip;
328 return (PROGRAM_AddProgram(hGroup, hIcon, lpszName, x, y,
329 lpszCmdLine, lpszIconFile,
330 nIconIndex, lpszWorkDir,
331 nHotKey, nCmdShow));
334 /***********************************************************************
336 * GRPFILE_WriteGroupFile
339 BOOL GRPFILE_WriteGroupFile(HLOCAL hGroup)
341 CHAR szPath[MAX_PATHNAME_LEN];
342 GROUP *group = LocalLock(hGroup);
343 OFSTRUCT dummy;
344 HFILE file;
345 BOOL ret;
347 GRPFILE_ModifyFileName(szPath, LocalLock(group->hGrpFile),
348 MAX_PATHNAME_LEN,
349 group->bFileNameModified);
351 /* Try not to overwrite original files */
353 /* group->bOverwriteFileOk == TRUE only if a file has the modified format */
354 if (!group->bOverwriteFileOk &&
355 OpenFile(szPath, &dummy, OF_EXIST) != HFILE_ERROR)
357 /* Original file exists, try `.gr' extension */
358 GRPFILE_ModifyFileName(szPath, LocalLock(group->hGrpFile),
359 MAX_PATHNAME_LEN, TRUE);
360 if (OpenFile(szPath, &dummy, OF_EXIST) != HFILE_ERROR)
362 /* File exists. Do not overwrite */
363 MAIN_MessageBoxIDS_s(IDS_FILE_NOT_OVERWRITTEN_s, szPath,
364 IDS_INFO, MB_OK);
365 return FALSE;
367 /* Inform about the modified file name */
368 if (IDCANCEL ==
369 MAIN_MessageBoxIDS_s(IDS_SAVE_GROUP_AS_s, szPath, IDS_INFO,
370 MB_OKCANCEL | MB_ICONINFORMATION))
371 return FALSE;
375 /* Warn about the (possible) incompatibility */
376 CHAR msg[MAX_PATHNAME_LEN + 200];
377 wsprintf(msg,
378 "Group files written by this DRAFT Program Manager "
379 "possibly cannot be read by the Microsoft Program Manager!!\n"
380 "Are you sure to write %s?", szPath);
381 if (IDOK != MessageBox(Globals.hMainWnd, msg, "WARNING",
382 MB_OKCANCEL | MB_DEFBUTTON2)) return FALSE;
385 /* FIXME */
386 if (OpenFile(szPath, &dummy, OF_EXIST) == HFILE_ERROR)
388 CHAR msg[MAX_PATHNAME_LEN + 200];
389 wsprintf(msg, "Cause of a bug you must now touch the file %s\n", szPath);
390 MessageBox(Globals.hMainWnd, msg, "", MB_OK);
393 /* Open file */
394 file = _lopen(szPath, OF_WRITE);
395 if (file != HFILE_ERROR)
397 ret = GRPFILE_DoWriteGroupFile(file, group);
398 _lclose(file);
400 else ret = FALSE;
402 if (!ret)
403 MAIN_MessageBoxIDS_s(IDS_FILE_WRITE_ERROR_s, szPath, IDS_ERROR, MB_OK);
405 return(ret);
408 /***********************************************************************
410 * GRPFILE_CalculateSizes
413 static VOID GRPFILE_CalculateSizes(PROGRAM *program,
414 INT *Progs, INT *Icons)
416 CURSORICONINFO *iconinfo = LocalLock(program->hIcon);
417 INT sizeXor = iconinfo->nHeight * iconinfo->nWidthBytes;
418 INT sizeAnd = iconinfo->nHeight * ((iconinfo->nWidth + 15) / 16 * 2);
420 *Progs += 24;
421 *Progs += lstrlen(LocalLock(program->hName)) + 1;
422 *Progs += lstrlen(LocalLock(program->hCmdLine)) + 1;
423 *Progs += lstrlen(LocalLock(program->hIconFile)) + 1;
425 *Icons += 12; /* IconInfo */
426 *Icons += sizeAnd;
427 *Icons += sizeXor;
430 /***********************************************************************/
431 UINT16 GRPFILE_checksum;
432 BOOL GRPFILE_checksum_half_word;
433 BYTE GRPFILE_checksum_last_byte;
434 /***********************************************************************
436 * GRPFILE_InitChecksum
439 static void GRPFILE_InitChecksum()
441 GRPFILE_checksum = 0;
442 GRPFILE_checksum_half_word = 0;
445 /***********************************************************************
447 * GRPFILE_GetChecksum
450 static UINT16 GRPFILE_GetChecksum()
452 return GRPFILE_checksum;
455 /***********************************************************************
457 * GRPFILE_WriteWithChecksum
459 * Looks crazier than it is:
461 * chksum = 0;
462 * chksum = cksum - 1. word;
463 * chksum = cksum - 2. word;
464 * ...
466 * if (filelen is even)
467 * great I'm finished
468 * else
469 * ignore last byte
472 static UINT GRPFILE_WriteWithChecksum(HFILE file, LPCSTR str, UINT size)
474 UINT i;
475 if (GRPFILE_checksum_half_word) {
476 GRPFILE_checksum -= GRPFILE_checksum_last_byte;
478 for (i=0; i < size; i++) {
479 if (GRPFILE_checksum_half_word) {
480 GRPFILE_checksum -= str[i] << 8;
481 } else {
482 GRPFILE_checksum -= str[i];
484 GRPFILE_checksum_half_word ^= 1;
487 if (GRPFILE_checksum_half_word) {
488 GRPFILE_checksum_last_byte = str[size-1];
489 GRPFILE_checksum += GRPFILE_checksum_last_byte;
492 return _lwrite(file, str, size);
496 /***********************************************************************
498 * GRPFILE_DoWriteGroupFile
501 static BOOL GRPFILE_DoWriteGroupFile(HFILE file, GROUP *group)
503 BYTE buffer[34];
504 HLOCAL hProgram;
505 INT NumProg, Title, Progs, Icons, Extension;
506 INT CurrProg, CurrIcon, nCmdShow, ptr, seqnum;
507 BOOL need_extension;
508 LPCSTR lpszTitle = LocalLock(group->hName);
510 UINT16 checksum;
512 GRPFILE_InitChecksum();
514 /* Calculate offsets */
515 NumProg = 0;
516 Icons = 0;
517 Extension = 0;
518 need_extension = FALSE;
519 hProgram = group->hPrograms;
520 while(hProgram)
522 PROGRAM *program = LocalLock(hProgram);
523 LPCSTR lpszWorkDir = LocalLock(program->hWorkDir);
525 NumProg++;
526 GRPFILE_CalculateSizes(program, &Icons, &Extension);
528 /* Set a flag if an extension is needed */
529 if (lpszWorkDir[0] || program->nHotKey ||
530 program->nCmdShow != SW_SHOWNORMAL) need_extension = TRUE;
532 hProgram = program->hNext;
534 Title = 34 + NumProg * 2;
535 Progs = Title + lstrlen(lpszTitle) + 1;
536 Icons += Progs;
537 Extension += Icons;
539 /* Header */
540 buffer[0] = 'P';
541 buffer[1] = 'M';
542 buffer[2] = 'C';
543 buffer[3] = 'C';
545 PUT_SHORT(buffer, 4, 0); /* Checksum zero for now, written later */
546 PUT_SHORT(buffer, 6, Extension);
547 /* Update group->nCmdShow */
548 if (IsIconic(group->hWnd)) nCmdShow = SW_SHOWMINIMIZED;
549 else if (IsZoomed(group->hWnd)) nCmdShow = SW_SHOWMAXIMIZED;
550 else nCmdShow = SW_SHOWNORMAL;
551 PUT_SHORT(buffer, 8, nCmdShow);
552 PUT_SHORT(buffer, 10, group->x);
553 PUT_SHORT(buffer, 12, group->y);
554 PUT_SHORT(buffer, 14, group->width);
555 PUT_SHORT(buffer, 16, group->height);
556 PUT_SHORT(buffer, 18, group->iconx);
557 PUT_SHORT(buffer, 20, group->icony);
558 PUT_SHORT(buffer, 22, Title);
559 PUT_SHORT(buffer, 24, 0x0020); /* unknown */
560 PUT_SHORT(buffer, 26, 0x0020); /* unknown */
561 PUT_SHORT(buffer, 28, 0x0108); /* unknown */
562 PUT_SHORT(buffer, 30, 0x0000); /* unknown */
563 PUT_SHORT(buffer, 32, NumProg);
565 if (HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 34)) return FALSE;
567 /* Program table */
568 CurrProg = Progs;
569 CurrIcon = Icons;
570 hProgram = group->hPrograms;
571 while(hProgram)
573 PROGRAM *program = LocalLock(hProgram);
575 PUT_SHORT(buffer, 0, CurrProg);
576 if (HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 2))
577 return FALSE;
579 GRPFILE_CalculateSizes(program, &CurrProg, &CurrIcon);
580 hProgram = program->hNext;
583 /* Title */
584 if (HFILE_ERROR == GRPFILE_WriteWithChecksum(file, lpszTitle,
585 lstrlen(lpszTitle) + 1))
586 return FALSE;
588 /* Program entries */
589 CurrProg = Progs;
590 CurrIcon = Icons;
591 hProgram = group->hPrograms;
592 while(hProgram)
594 PROGRAM *program = LocalLock(hProgram);
595 CURSORICONINFO *iconinfo = LocalLock(program->hIcon);
596 LPCSTR Name = LocalLock(program->hName);
597 LPCSTR CmdLine = LocalLock(program->hCmdLine);
598 LPCSTR IconFile = LocalLock(program->hIconFile);
599 INT sizeXor = iconinfo->nHeight * iconinfo->nWidthBytes;
600 INT sizeAnd = iconinfo->nHeight * ((iconinfo->nWidth + 15) / 16 * 2);
602 PUT_SHORT(buffer, 0, program->x);
603 PUT_SHORT(buffer, 2, program->y);
604 PUT_SHORT(buffer, 4, program->nIconIndex);
605 PUT_SHORT(buffer, 6, 0x048c); /* unknown */
606 PUT_SHORT(buffer, 8, sizeXor);
607 PUT_SHORT(buffer, 10, sizeAnd * 8);
608 PUT_SHORT(buffer, 12, CurrIcon);
609 PUT_SHORT(buffer, 14, CurrIcon + 12 + sizeAnd);
610 PUT_SHORT(buffer, 16, CurrIcon + 12);
611 ptr = CurrProg + 24;
612 PUT_SHORT(buffer, 18, ptr);
613 ptr += lstrlen(Name) + 1;
614 PUT_SHORT(buffer, 20, ptr);
615 ptr += lstrlen(CmdLine) + 1;
616 PUT_SHORT(buffer, 22, ptr);
618 if (HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 24) ||
619 HFILE_ERROR == GRPFILE_WriteWithChecksum(file, Name, lstrlen(Name) + 1) ||
620 HFILE_ERROR == GRPFILE_WriteWithChecksum(file, CmdLine, lstrlen(CmdLine) + 1) ||
621 HFILE_ERROR == GRPFILE_WriteWithChecksum(file, IconFile, lstrlen(IconFile) + 1))
622 return FALSE;
624 GRPFILE_CalculateSizes(program, &CurrProg, &CurrIcon);
625 hProgram = program->hNext;
628 /* Icons */
629 hProgram = group->hPrograms;
630 while(hProgram)
632 PROGRAM *program = LocalLock(hProgram);
633 CURSORICONINFO *iconinfo = LocalLock(program->hIcon);
634 LPVOID XorBits, AndBits;
635 INT sizeXor = iconinfo->nHeight * iconinfo->nWidthBytes;
636 INT sizeAnd = iconinfo->nHeight * ((iconinfo->nWidth + 15) / 16 * 2);
637 DumpIcon(LocalLock(program->hIcon), 0, &XorBits, &AndBits);
639 PUT_SHORT(buffer, 0, iconinfo->ptHotSpot.x);
640 PUT_SHORT(buffer, 2, iconinfo->ptHotSpot.y);
641 PUT_SHORT(buffer, 4, iconinfo->nWidth);
642 PUT_SHORT(buffer, 6, iconinfo->nHeight);
643 PUT_SHORT(buffer, 8, iconinfo->nWidthBytes);
644 buffer[10] = iconinfo->bPlanes;
645 buffer[11] = iconinfo->bBitsPerPixel;
647 if (HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 12) ||
648 HFILE_ERROR == GRPFILE_WriteWithChecksum(file, AndBits, sizeAnd) ||
649 HFILE_ERROR == GRPFILE_WriteWithChecksum(file, XorBits, sizeXor)) return FALSE;
651 hProgram = program->hNext;
654 if (need_extension)
656 /* write `PMCC' extension */
657 PUT_SHORT(buffer, 0, 0x8000);
658 PUT_SHORT(buffer, 2, 0xffff);
659 PUT_SHORT(buffer, 4, 0x000a);
660 buffer[6] = 'P', buffer[7] = 'M';
661 buffer[8] = 'C', buffer[9] = 'C';
662 if (HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 10))
663 return FALSE;
665 seqnum = 0;
666 hProgram = group->hPrograms;
667 while(hProgram)
669 PROGRAM *program = LocalLock(hProgram);
670 LPCSTR lpszWorkDir = LocalLock(program->hWorkDir);
672 /* Working directory */
673 if (lpszWorkDir[0])
675 PUT_SHORT(buffer, 0, 0x8101);
676 PUT_SHORT(buffer, 2, seqnum);
677 PUT_SHORT(buffer, 4, 7 + lstrlen(lpszWorkDir));
678 if (HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 6) ||
679 HFILE_ERROR == GRPFILE_WriteWithChecksum(file, lpszWorkDir, lstrlen(lpszWorkDir) + 1))
680 return FALSE;
683 /* Hot key */
684 if (program->nHotKey)
686 PUT_SHORT(buffer, 0, 0x8102);
687 PUT_SHORT(buffer, 2, seqnum);
688 PUT_SHORT(buffer, 4, 8);
689 PUT_SHORT(buffer, 6, program->nHotKey);
690 if (HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 8)) return FALSE;
693 /* Show command */
694 if (program->nCmdShow)
696 PUT_SHORT(buffer, 0, 0x8103);
697 PUT_SHORT(buffer, 2, seqnum);
698 PUT_SHORT(buffer, 4, 8);
699 PUT_SHORT(buffer, 6, program->nCmdShow);
700 if (HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 8)) return FALSE;
703 seqnum++;
704 hProgram = program->hNext;
707 /* Write `End' extension */
708 PUT_SHORT(buffer, 0, 0xffff);
709 PUT_SHORT(buffer, 2, 0xffff);
710 PUT_SHORT(buffer, 4, 0x0000);
711 if (HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 6)) return FALSE;
714 checksum = GRPFILE_GetChecksum();
715 _llseek(file, 4, SEEK_SET);
716 PUT_SHORT(buffer, 0, checksum);
717 _lwrite(file, buffer, 2);
719 return TRUE;
722 /* Local Variables: */
723 /* c-file-style: "GNU" */
724 /* End: */