Pass the correct hFile to PE_CreateModule.
[wine/multimedia.git] / programs / progman / grpfile.c
blob61d74b47f07b27aa059340cd3b07a699f149ede9
1 /*
2 * Program Manager
4 * Copyright 1996 Ulrich Schmid
5 * 1997 Peter Schlaile
6 */
8 #include "windows.h"
9 #include "wine/winuser16.h"
10 #include "progman.h"
11 #include "mmsystem.h"
13 #define MALLOCHUNK 1000
15 #define GET_USHORT(buffer, i)\
16 (((BYTE)((buffer)[(i)]) + 0x100 * (BYTE)((buffer)[(i)+1])))
17 #define GET_SHORT(buffer, i)\
18 (((BYTE)((buffer)[(i)]) + 0x100 * (signed char)((buffer)[(i)+1])))
19 #define PUT_SHORT(buffer, i, s)\
20 (((buffer)[(i)] = (s) & 0xff, (buffer)[(i)+1] = ((s) >> 8) & 0xff))
22 static BOOL GRPFILE_ReadFileToBuffer(LPCSTR, HLOCAL*, INT*);
23 static HLOCAL GRPFILE_ScanGroup(LPCSTR, INT, LPCSTR, BOOL);
24 static HLOCAL GRPFILE_ScanProgram(LPCSTR, INT, LPCSTR, INT,
25 LPCSTR, HLOCAL,LPCSTR);
26 static BOOL GRPFILE_DoWriteGroupFile(HFILE file, PROGGROUP *group);
28 /***********************************************************************
30 * GRPFILE_ModifyFileName
32 * Change extension `.grp' to `.gr'
35 static VOID GRPFILE_ModifyFileName(LPSTR lpszNewName, LPCSTR lpszOrigName,
36 INT nSize, BOOL bModify)
38 lstrcpyn(lpszNewName, lpszOrigName, nSize);
39 lpszNewName[nSize-1] = '\0';
40 if (!bModify) return;
41 if (!lstrcmpi(lpszNewName + strlen(lpszNewName) - 4, ".grp"))
42 lpszNewName[strlen(lpszNewName) - 1] = '\0';
45 /***********************************************************************
47 * GRPFILE_ReadGroupFile
50 HLOCAL GRPFILE_ReadGroupFile(LPCSTR lpszPath)
52 CHAR szPath_gr[MAX_PATHNAME_LEN];
53 BOOL bFileNameModified = FALSE;
54 OFSTRUCT dummy;
55 HLOCAL hBuffer, hGroup;
56 INT size;
58 /* if `.gr' file exists use that */
59 GRPFILE_ModifyFileName(szPath_gr, lpszPath, MAX_PATHNAME_LEN, TRUE);
60 if (OpenFile(szPath_gr, &dummy, OF_EXIST) != HFILE_ERROR)
62 lpszPath = szPath_gr;
63 bFileNameModified = TRUE;
66 /* Read the whole file into a buffer */
67 if (!GRPFILE_ReadFileToBuffer(lpszPath, &hBuffer, &size))
69 MAIN_MessageBoxIDS_s(IDS_GRPFILE_READ_ERROR_s, lpszPath, IDS_ERROR, MB_YESNO);
70 return(0);
73 /* Interpret buffer */
74 hGroup = GRPFILE_ScanGroup(LocalLock(hBuffer), size,
75 lpszPath, bFileNameModified);
76 if (!hGroup)
77 MAIN_MessageBoxIDS_s(IDS_GRPFILE_READ_ERROR_s, lpszPath, IDS_ERROR, MB_YESNO);
79 LocalFree(hBuffer);
81 return(hGroup);
84 /***********************************************************************
86 * GRPFILE_ReadFileToBuffer
89 static BOOL GRPFILE_ReadFileToBuffer(LPCSTR path, HLOCAL *phBuffer,
90 INT *piSize)
92 UINT len, size;
93 LPSTR buffer;
94 HLOCAL hBuffer, hNewBuffer;
95 HFILE file;
97 file=_lopen(path, OF_READ);
98 if (file == HFILE_ERROR) return FALSE;
100 size = 0;
101 hBuffer = LocalAlloc(LMEM_FIXED, size + MALLOCHUNK + 1);
102 if (!hBuffer) return FALSE;
103 buffer = LocalLock(hBuffer);
105 while ((len = _lread(file, buffer + size, MALLOCHUNK))
106 == MALLOCHUNK)
108 size += len;
109 hNewBuffer = LocalReAlloc(hBuffer, size + MALLOCHUNK + 1,
110 LMEM_FIXED);
111 if (!hNewBuffer)
113 LocalFree(hBuffer);
114 return FALSE;
116 hBuffer = hNewBuffer;
117 buffer = LocalLock(hBuffer);
120 _lclose(file);
122 if (len == (UINT)HFILE_ERROR)
124 LocalFree(hBuffer);
125 return FALSE;
128 size += len;
129 buffer[size] = 0;
131 *phBuffer = hBuffer;
132 *piSize = size;
133 return TRUE;
136 /***********************************************************************
137 * GRPFILE_ScanGroup
140 static HLOCAL GRPFILE_ScanGroup(LPCSTR buffer, INT size,
141 LPCSTR lpszGrpFile,
142 BOOL bModifiedFileName)
144 HLOCAL hGroup;
145 INT i, seqnum;
146 LPCSTR extension;
147 LPCSTR lpszName;
148 INT x, y, width, height, iconx, icony, nCmdShow;
149 INT number_of_programs;
150 BOOL bOverwriteFileOk;
152 if (buffer[0] != 'P' || buffer[1] != 'M') return(0);
153 if (buffer[2] == 'C' && buffer[3] == 'C')
154 /* original with checksum */
155 bOverwriteFileOk = FALSE;
156 else if (buffer[2] == 'X' && buffer[3] == 'X')
157 /* modified without checksum */
158 bOverwriteFileOk = TRUE;
159 else return(0);
161 /* checksum = GET_USHORT(buffer, 4) (ignored) */
163 extension = buffer + GET_USHORT(buffer, 6);
164 if (extension == buffer + size) extension = 0;
165 else if (extension + 6 > buffer + size) return(0);
167 nCmdShow = GET_USHORT(buffer, 8);
168 x = GET_SHORT(buffer, 10);
169 y = GET_SHORT(buffer, 12);
170 width = GET_USHORT(buffer, 14);
171 height = GET_USHORT(buffer, 16);
172 iconx = GET_SHORT(buffer, 18);
173 icony = GET_SHORT(buffer, 20);
174 lpszName = buffer + GET_USHORT(buffer, 22);
175 if (lpszName >= buffer + size) return(0);
177 /* unknown bytes 24 - 31 ignored */
179 Unknown bytes should be:
180 wLogPixelsX = GET_SHORT(buffer, 24);
181 wLogPixelsY = GET_SHORT(buffer, 26);
182 byBitsPerPixel = byte at 28;
183 byPlanes = byte at 29;
184 wReserved = GET_SHORT(buffer, 30);
187 hGroup = GROUP_AddGroup(lpszName, lpszGrpFile, nCmdShow, x, y,
188 width, height, iconx, icony,
189 bModifiedFileName, bOverwriteFileOk,
190 TRUE);
191 if (!hGroup) return(0);
193 number_of_programs = GET_USHORT(buffer, 32);
194 if (2 * number_of_programs + 34 > size) return(0);
195 for (i=0, seqnum=0; i < number_of_programs; i++, seqnum++)
197 LPCSTR program_ptr = buffer + GET_USHORT(buffer, 34 + 2*i);
198 if (program_ptr + 24 > buffer + size) return(0);
199 if (!GET_USHORT(buffer, 34 + 2*i)) continue;
200 if (!GRPFILE_ScanProgram(buffer, size, program_ptr, seqnum,
201 extension, hGroup, lpszGrpFile))
203 GROUP_DeleteGroup(hGroup);
204 return(0);
208 /* FIXME shouldn't be necessary */
209 GROUP_ShowGroupWindow(hGroup);
211 return hGroup;
214 /***********************************************************************
215 * GRPFILE_ScanProgram
218 static HLOCAL GRPFILE_ScanProgram(LPCSTR buffer, INT size,
219 LPCSTR program_ptr, INT seqnum,
220 LPCSTR extension, HLOCAL hGroup,
221 LPCSTR lpszGrpFile)
223 INT icontype;
224 HICON hIcon;
225 LPCSTR lpszName, lpszCmdLine, lpszIconFile, lpszWorkDir;
226 LPCSTR iconinfo_ptr, iconANDbits_ptr, iconXORbits_ptr;
227 INT x, y, nIconIndex, iconANDsize, iconXORsize;
228 INT nHotKey, nCmdShow;
229 CURSORICONINFO iconinfo;
231 x = GET_SHORT(program_ptr, 0);
232 y = GET_SHORT(program_ptr, 2);
233 nIconIndex = GET_USHORT(program_ptr, 4);
235 /* FIXME is this correct ?? */
236 icontype = GET_USHORT(program_ptr, 6);
237 switch (icontype)
239 default:
240 MAIN_MessageBoxIDS_s(IDS_UNKNOWN_FEATURE_s, lpszGrpFile,
241 IDS_WARNING, MB_OK);
242 case 0x048c:
243 iconXORsize = GET_USHORT(program_ptr, 8);
244 iconANDsize = GET_USHORT(program_ptr, 10) / 8;
245 iconinfo_ptr = buffer + GET_USHORT(program_ptr, 12);
246 iconXORbits_ptr = buffer + GET_USHORT(program_ptr, 14);
247 iconANDbits_ptr = buffer + GET_USHORT(program_ptr, 16);
248 iconinfo.ptHotSpot.x = GET_USHORT(iconinfo_ptr, 0);
249 iconinfo.ptHotSpot.y = GET_USHORT(iconinfo_ptr, 2);
250 iconinfo.nWidth = GET_USHORT(iconinfo_ptr, 4);
251 iconinfo.nHeight = GET_USHORT(iconinfo_ptr, 6);
252 iconinfo.nWidthBytes = GET_USHORT(iconinfo_ptr, 8);
253 iconinfo.bPlanes = GET_USHORT(iconinfo_ptr, 10);
254 iconinfo.bBitsPerPixel = GET_USHORT(iconinfo_ptr, 11);
255 break;
256 case 0x000c:
257 iconANDsize = GET_USHORT(program_ptr, 8);
258 iconXORsize = GET_USHORT(program_ptr, 10);
259 iconinfo_ptr = buffer + GET_USHORT(program_ptr, 12);
260 iconANDbits_ptr = buffer + GET_USHORT(program_ptr, 14);
261 iconXORbits_ptr = buffer + GET_USHORT(program_ptr, 16);
262 iconinfo.ptHotSpot.x = GET_USHORT(iconinfo_ptr, 0);
263 iconinfo.ptHotSpot.y = GET_USHORT(iconinfo_ptr, 2);
264 iconinfo.nWidth = GET_USHORT(iconinfo_ptr, 4);
265 iconinfo.nHeight = GET_USHORT(iconinfo_ptr, 6);
266 iconinfo.nWidthBytes = GET_USHORT(iconinfo_ptr, 8) * 8;
267 iconinfo.bPlanes = GET_USHORT(iconinfo_ptr, 10);
268 iconinfo.bBitsPerPixel = GET_USHORT(iconinfo_ptr, 11);
271 if (iconANDbits_ptr + iconANDsize > buffer + size ||
272 iconXORbits_ptr + iconXORsize > buffer + size) return(0);
274 hIcon = CreateCursorIconIndirect16(Globals.hInstance, &iconinfo,
275 (LPSTR)iconANDbits_ptr,
276 (LPSTR)iconXORbits_ptr);
278 lpszName = buffer + GET_USHORT(program_ptr, 18);
279 lpszCmdLine = buffer + GET_USHORT(program_ptr, 20);
280 lpszIconFile = buffer + GET_USHORT(program_ptr, 22);
281 if (iconinfo_ptr + 6 > buffer + size ||
282 lpszName > buffer + size ||
283 lpszCmdLine > buffer + size ||
284 lpszIconFile > buffer + size) return(0);
286 /* Scan Extensions */
287 lpszWorkDir = "";
288 nHotKey = 0;
289 nCmdShow = SW_SHOWNORMAL;
290 if (extension)
292 LPCSTR ptr = extension;
293 while (ptr + 6 <= buffer + size)
295 UINT type = GET_USHORT(ptr, 0);
296 UINT number = GET_USHORT(ptr, 2);
297 UINT skip = GET_USHORT(ptr, 4);
299 if (number == seqnum)
301 switch (type)
303 case 0x8000:
304 if (ptr + 10 > buffer + size) return(0);
305 if (ptr[6] != 'P' || ptr[7] != 'M' ||
306 ptr[8] != 'C' || ptr[9] != 'C') return(0);
307 break;
308 case 0x8101:
309 lpszWorkDir = ptr + 6;
310 break;
311 case 0x8102:
312 if (ptr + 8 > buffer + size) return(0);
313 nHotKey = GET_USHORT(ptr, 6);
314 break;
315 case 0x8103:
316 if (ptr + 8 > buffer + size) return(0);
317 nCmdShow = GET_USHORT(ptr, 6);
318 break;
319 default:
320 MAIN_MessageBoxIDS_s(IDS_UNKNOWN_FEATURE_s,
321 lpszGrpFile, IDS_WARNING, MB_OK);
324 if (!skip) break;
325 ptr += skip;
329 return (PROGRAM_AddProgram(hGroup, hIcon, lpszName, x, y,
330 lpszCmdLine, lpszIconFile,
331 nIconIndex, lpszWorkDir,
332 nHotKey, nCmdShow));
335 /***********************************************************************
337 * GRPFILE_WriteGroupFile
340 BOOL GRPFILE_WriteGroupFile(HLOCAL hGroup)
342 CHAR szPath[MAX_PATHNAME_LEN];
343 PROGGROUP *group = LocalLock(hGroup);
344 OFSTRUCT dummy;
345 HFILE file;
346 BOOL ret;
348 GRPFILE_ModifyFileName(szPath, LocalLock(group->hGrpFile),
349 MAX_PATHNAME_LEN,
350 group->bFileNameModified);
352 /* Try not to overwrite original files */
354 /* group->bOverwriteFileOk == TRUE only if a file has the modified format */
355 if (!group->bOverwriteFileOk &&
356 OpenFile(szPath, &dummy, OF_EXIST) != HFILE_ERROR)
358 /* Original file exists, try `.gr' extension */
359 GRPFILE_ModifyFileName(szPath, LocalLock(group->hGrpFile),
360 MAX_PATHNAME_LEN, TRUE);
361 if (OpenFile(szPath, &dummy, OF_EXIST) != HFILE_ERROR)
363 /* File exists. Do not overwrite */
364 MAIN_MessageBoxIDS_s(IDS_FILE_NOT_OVERWRITTEN_s, szPath,
365 IDS_INFO, MB_OK);
366 return FALSE;
368 /* Inform about the modified file name */
369 if (IDCANCEL ==
370 MAIN_MessageBoxIDS_s(IDS_SAVE_GROUP_AS_s, szPath, IDS_INFO,
371 MB_OKCANCEL | MB_ICONINFORMATION))
372 return FALSE;
376 /* Warn about the (possible) incompatibility */
377 CHAR msg[MAX_PATHNAME_LEN + 200];
378 wsprintf(msg,
379 "Group files written by this DRAFT Program Manager "
380 "possibly cannot be read by the Microsoft Program Manager!!\n"
381 "Are you sure to write %s?", szPath);
382 if (IDOK != MessageBox(Globals.hMainWnd, msg, "WARNING",
383 MB_OKCANCEL | MB_DEFBUTTON2)) return FALSE;
386 /* FIXME */
387 if (OpenFile(szPath, &dummy, OF_EXIST) == HFILE_ERROR)
389 CHAR msg[MAX_PATHNAME_LEN + 200];
390 wsprintf(msg, "Cause of a bug you must now touch the file %s\n", szPath);
391 MessageBox(Globals.hMainWnd, msg, "", MB_OK);
394 /* Open file */
395 file = _lopen(szPath, OF_WRITE);
396 if (file != HFILE_ERROR)
398 ret = GRPFILE_DoWriteGroupFile(file, group);
399 _lclose(file);
401 else ret = FALSE;
403 if (!ret)
404 MAIN_MessageBoxIDS_s(IDS_FILE_WRITE_ERROR_s, szPath, IDS_ERROR, MB_OK);
406 return(ret);
409 /***********************************************************************
411 * GRPFILE_CalculateSizes
414 static VOID GRPFILE_CalculateSizes(PROGRAM *program,
415 INT *Progs, INT *Icons)
417 CURSORICONINFO *iconinfo = LocalLock(program->hIcon);
418 INT sizeXor = iconinfo->nHeight * iconinfo->nWidthBytes;
419 INT sizeAnd = iconinfo->nHeight * ((iconinfo->nWidth + 15) / 16 * 2);
421 *Progs += 24;
422 *Progs += lstrlen(LocalLock(program->hName)) + 1;
423 *Progs += lstrlen(LocalLock(program->hCmdLine)) + 1;
424 *Progs += lstrlen(LocalLock(program->hIconFile)) + 1;
426 *Icons += 12; /* IconInfo */
427 *Icons += sizeAnd;
428 *Icons += sizeXor;
431 /***********************************************************************/
432 UINT16 GRPFILE_checksum;
433 BOOL GRPFILE_checksum_half_word;
434 BYTE GRPFILE_checksum_last_byte;
435 /***********************************************************************
437 * GRPFILE_InitChecksum
440 static void GRPFILE_InitChecksum()
442 GRPFILE_checksum = 0;
443 GRPFILE_checksum_half_word = 0;
446 /***********************************************************************
448 * GRPFILE_GetChecksum
451 static UINT16 GRPFILE_GetChecksum()
453 return GRPFILE_checksum;
456 /***********************************************************************
458 * GRPFILE_WriteWithChecksum
460 * Looks crazier than it is:
462 * chksum = 0;
463 * chksum = cksum - 1. word;
464 * chksum = cksum - 2. word;
465 * ...
467 * if (filelen is even)
468 * great I'm finished
469 * else
470 * ignore last byte
473 static UINT GRPFILE_WriteWithChecksum(HFILE file, LPCSTR str, UINT size)
475 UINT i;
476 if (GRPFILE_checksum_half_word) {
477 GRPFILE_checksum -= GRPFILE_checksum_last_byte;
479 for (i=0; i < size; i++) {
480 if (GRPFILE_checksum_half_word) {
481 GRPFILE_checksum -= str[i] << 8;
482 } else {
483 GRPFILE_checksum -= str[i];
485 GRPFILE_checksum_half_word ^= 1;
488 if (GRPFILE_checksum_half_word) {
489 GRPFILE_checksum_last_byte = str[size-1];
490 GRPFILE_checksum += GRPFILE_checksum_last_byte;
493 return _lwrite(file, str, size);
497 /***********************************************************************
499 * GRPFILE_DoWriteGroupFile
502 static BOOL GRPFILE_DoWriteGroupFile(HFILE file, PROGGROUP *group)
504 BYTE buffer[34];
505 HLOCAL hProgram;
506 INT NumProg, Title, Progs, Icons, Extension;
507 INT CurrProg, CurrIcon, nCmdShow, ptr, seqnum;
508 BOOL need_extension;
509 LPCSTR lpszTitle = LocalLock(group->hName);
511 UINT16 checksum;
513 GRPFILE_InitChecksum();
515 /* Calculate offsets */
516 NumProg = 0;
517 Icons = 0;
518 Extension = 0;
519 need_extension = FALSE;
520 hProgram = group->hPrograms;
521 while(hProgram)
523 PROGRAM *program = LocalLock(hProgram);
524 LPCSTR lpszWorkDir = LocalLock(program->hWorkDir);
526 NumProg++;
527 GRPFILE_CalculateSizes(program, &Icons, &Extension);
529 /* Set a flag if an extension is needed */
530 if (lpszWorkDir[0] || program->nHotKey ||
531 program->nCmdShow != SW_SHOWNORMAL) need_extension = TRUE;
533 hProgram = program->hNext;
535 Title = 34 + NumProg * 2;
536 Progs = Title + lstrlen(lpszTitle) + 1;
537 Icons += Progs;
538 Extension += Icons;
540 /* Header */
541 buffer[0] = 'P';
542 buffer[1] = 'M';
543 buffer[2] = 'C';
544 buffer[3] = 'C';
546 PUT_SHORT(buffer, 4, 0); /* Checksum zero for now, written later */
547 PUT_SHORT(buffer, 6, Extension);
548 /* Update group->nCmdShow */
549 if (IsIconic(group->hWnd)) nCmdShow = SW_SHOWMINIMIZED;
550 else if (IsZoomed(group->hWnd)) nCmdShow = SW_SHOWMAXIMIZED;
551 else nCmdShow = SW_SHOWNORMAL;
552 PUT_SHORT(buffer, 8, nCmdShow);
553 PUT_SHORT(buffer, 10, group->x);
554 PUT_SHORT(buffer, 12, group->y);
555 PUT_SHORT(buffer, 14, group->width);
556 PUT_SHORT(buffer, 16, group->height);
557 PUT_SHORT(buffer, 18, group->iconx);
558 PUT_SHORT(buffer, 20, group->icony);
559 PUT_SHORT(buffer, 22, Title);
560 PUT_SHORT(buffer, 24, 0x0020); /* unknown */
561 PUT_SHORT(buffer, 26, 0x0020); /* unknown */
562 PUT_SHORT(buffer, 28, 0x0108); /* unknown */
563 PUT_SHORT(buffer, 30, 0x0000); /* unknown */
564 PUT_SHORT(buffer, 32, NumProg);
566 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 34)) return FALSE;
568 /* Program table */
569 CurrProg = Progs;
570 CurrIcon = Icons;
571 hProgram = group->hPrograms;
572 while(hProgram)
574 PROGRAM *program = LocalLock(hProgram);
576 PUT_SHORT(buffer, 0, CurrProg);
577 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 2))
578 return FALSE;
580 GRPFILE_CalculateSizes(program, &CurrProg, &CurrIcon);
581 hProgram = program->hNext;
584 /* Title */
585 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, lpszTitle,
586 lstrlen(lpszTitle) + 1))
587 return FALSE;
589 /* Program entries */
590 CurrProg = Progs;
591 CurrIcon = Icons;
592 hProgram = group->hPrograms;
593 while(hProgram)
595 PROGRAM *program = LocalLock(hProgram);
596 CURSORICONINFO *iconinfo = LocalLock(program->hIcon);
597 LPCSTR Name = LocalLock(program->hName);
598 LPCSTR CmdLine = LocalLock(program->hCmdLine);
599 LPCSTR IconFile = LocalLock(program->hIconFile);
600 INT sizeXor = iconinfo->nHeight * iconinfo->nWidthBytes;
601 INT sizeAnd = iconinfo->nHeight * ((iconinfo->nWidth + 15) / 16 * 2);
603 PUT_SHORT(buffer, 0, program->x);
604 PUT_SHORT(buffer, 2, program->y);
605 PUT_SHORT(buffer, 4, program->nIconIndex);
606 PUT_SHORT(buffer, 6, 0x048c); /* unknown */
607 PUT_SHORT(buffer, 8, sizeXor);
608 PUT_SHORT(buffer, 10, sizeAnd * 8);
609 PUT_SHORT(buffer, 12, CurrIcon);
610 PUT_SHORT(buffer, 14, CurrIcon + 12 + sizeAnd);
611 PUT_SHORT(buffer, 16, CurrIcon + 12);
612 ptr = CurrProg + 24;
613 PUT_SHORT(buffer, 18, ptr);
614 ptr += lstrlen(Name) + 1;
615 PUT_SHORT(buffer, 20, ptr);
616 ptr += lstrlen(CmdLine) + 1;
617 PUT_SHORT(buffer, 22, ptr);
619 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 24) ||
620 (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, Name, lstrlen(Name) + 1) ||
621 (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, CmdLine, lstrlen(CmdLine) + 1) ||
622 (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, IconFile, lstrlen(IconFile) + 1))
623 return FALSE;
625 GRPFILE_CalculateSizes(program, &CurrProg, &CurrIcon);
626 hProgram = program->hNext;
629 /* Icons */
630 hProgram = group->hPrograms;
631 while(hProgram)
633 PROGRAM *program = LocalLock(hProgram);
634 CURSORICONINFO *iconinfo = LocalLock(program->hIcon);
635 LPVOID XorBits, AndBits;
636 INT sizeXor = iconinfo->nHeight * iconinfo->nWidthBytes;
637 INT sizeAnd = iconinfo->nHeight * ((iconinfo->nWidth + 15) / 16 * 2);
638 DumpIcon16(LocalLock(program->hIcon), 0, &XorBits, &AndBits);
640 PUT_SHORT(buffer, 0, iconinfo->ptHotSpot.x);
641 PUT_SHORT(buffer, 2, iconinfo->ptHotSpot.y);
642 PUT_SHORT(buffer, 4, iconinfo->nWidth);
643 PUT_SHORT(buffer, 6, iconinfo->nHeight);
644 PUT_SHORT(buffer, 8, iconinfo->nWidthBytes);
645 buffer[10] = iconinfo->bPlanes;
646 buffer[11] = iconinfo->bBitsPerPixel;
648 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 12) ||
649 (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, AndBits, sizeAnd) ||
650 (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, XorBits, sizeXor)) return FALSE;
652 hProgram = program->hNext;
655 if (need_extension)
657 /* write `PMCC' extension */
658 PUT_SHORT(buffer, 0, 0x8000);
659 PUT_SHORT(buffer, 2, 0xffff);
660 PUT_SHORT(buffer, 4, 0x000a);
661 buffer[6] = 'P', buffer[7] = 'M';
662 buffer[8] = 'C', buffer[9] = 'C';
663 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 10))
664 return FALSE;
666 seqnum = 0;
667 hProgram = group->hPrograms;
668 while(hProgram)
670 PROGRAM *program = LocalLock(hProgram);
671 LPCSTR lpszWorkDir = LocalLock(program->hWorkDir);
673 /* Working directory */
674 if (lpszWorkDir[0])
676 PUT_SHORT(buffer, 0, 0x8101);
677 PUT_SHORT(buffer, 2, seqnum);
678 PUT_SHORT(buffer, 4, 7 + lstrlen(lpszWorkDir));
679 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 6) ||
680 (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, lpszWorkDir, lstrlen(lpszWorkDir) + 1))
681 return FALSE;
684 /* Hot key */
685 if (program->nHotKey)
687 PUT_SHORT(buffer, 0, 0x8102);
688 PUT_SHORT(buffer, 2, seqnum);
689 PUT_SHORT(buffer, 4, 8);
690 PUT_SHORT(buffer, 6, program->nHotKey);
691 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 8)) return FALSE;
694 /* Show command */
695 if (program->nCmdShow)
697 PUT_SHORT(buffer, 0, 0x8103);
698 PUT_SHORT(buffer, 2, seqnum);
699 PUT_SHORT(buffer, 4, 8);
700 PUT_SHORT(buffer, 6, program->nCmdShow);
701 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 8)) return FALSE;
704 seqnum++;
705 hProgram = program->hNext;
708 /* Write `End' extension */
709 PUT_SHORT(buffer, 0, 0xffff);
710 PUT_SHORT(buffer, 2, 0xffff);
711 PUT_SHORT(buffer, 4, 0x0000);
712 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 6)) return FALSE;
715 checksum = GRPFILE_GetChecksum();
716 _llseek(file, 4, SEEK_SET);
717 PUT_SHORT(buffer, 0, checksum);
718 _lwrite(file, buffer, 2);
720 return TRUE;
723 /* Local Variables: */
724 /* c-file-style: "GNU" */
725 /* End: */