mlang: Implement DllCanUnloadNow.
[wine/gsoc_dplay.git] / programs / progman / grpfile.c
blob8174308588ed46bb4ed44eb3eb89ec3bde627f77
1 /*
2 * Program Manager
4 * Copyright 1996 Ulrich Schmid
5 * 1997 Peter Schlaile
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #define WIN32_LEAN_AND_MEAN
24 #include "windows.h"
25 #include "wine/winuser16.h"
26 #include "progman.h"
27 #include "mmsystem.h"
29 #define MALLOCHUNK 1000
31 #define GET_USHORT(buffer, i)\
32 (((BYTE)((buffer)[(i)]) + 0x100 * (BYTE)((buffer)[(i)+1])))
33 #define GET_SHORT(buffer, i)\
34 (((BYTE)((buffer)[(i)]) + 0x100 * (signed char)((buffer)[(i)+1])))
35 #define PUT_SHORT(buffer, i, s)\
36 (((buffer)[(i)] = (s) & 0xff, (buffer)[(i)+1] = ((s) >> 8) & 0xff))
38 static BOOL GRPFILE_ReadFileToBuffer(LPCSTR, HLOCAL*, INT*);
39 static HLOCAL GRPFILE_ScanGroup(LPCSTR, INT, LPCSTR, BOOL);
40 static HLOCAL GRPFILE_ScanProgram(LPCSTR, INT, LPCSTR, INT,
41 LPCSTR, HLOCAL,LPCSTR);
42 static BOOL GRPFILE_DoWriteGroupFile(HFILE file, PROGGROUP *group);
44 /***********************************************************************
46 * GRPFILE_ModifyFileName
48 * Change extension `.grp' to `.gr'
51 static VOID GRPFILE_ModifyFileName(LPSTR lpszNewName, LPCSTR lpszOrigName,
52 INT nSize, BOOL bModify)
54 lstrcpyn(lpszNewName, lpszOrigName, nSize);
55 lpszNewName[nSize-1] = '\0';
56 if (!bModify) return;
57 if (!lstrcmpi(lpszNewName + strlen(lpszNewName) - 4, ".grp"))
58 lpszNewName[strlen(lpszNewName) - 1] = '\0';
61 /***********************************************************************
63 * GRPFILE_ReadGroupFile
66 HLOCAL GRPFILE_ReadGroupFile(LPCSTR lpszPath)
68 CHAR szPath_gr[MAX_PATHNAME_LEN];
69 BOOL bFileNameModified = FALSE;
70 OFSTRUCT dummy;
71 HLOCAL hBuffer, hGroup;
72 INT size;
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)
78 lpszPath = szPath_gr;
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);
86 return(0);
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);
95 LocalFree(hBuffer);
97 return(hGroup);
100 /***********************************************************************
102 * GRPFILE_ReadFileToBuffer
105 static BOOL GRPFILE_ReadFileToBuffer(LPCSTR path, HLOCAL *phBuffer,
106 INT *piSize)
108 UINT len, size;
109 LPSTR buffer;
110 HLOCAL hBuffer, hNewBuffer;
111 HFILE file;
113 file=_lopen(path, OF_READ);
114 if (file == HFILE_ERROR) return FALSE;
116 size = 0;
117 hBuffer = LocalAlloc(LMEM_FIXED, size + MALLOCHUNK + 1);
118 if (!hBuffer) return FALSE;
119 buffer = LocalLock(hBuffer);
121 while ((len = _lread(file, buffer + size, MALLOCHUNK))
122 == MALLOCHUNK)
124 size += len;
125 hNewBuffer = LocalReAlloc(hBuffer, size + MALLOCHUNK + 1,
126 LMEM_FIXED);
127 if (!hNewBuffer)
129 LocalFree(hBuffer);
130 return FALSE;
132 hBuffer = hNewBuffer;
133 buffer = LocalLock(hBuffer);
136 _lclose(file);
138 if (len == (UINT)HFILE_ERROR)
140 LocalFree(hBuffer);
141 return FALSE;
144 size += len;
145 buffer[size] = 0;
147 *phBuffer = hBuffer;
148 *piSize = size;
149 return TRUE;
152 /***********************************************************************
153 * GRPFILE_ScanGroup
156 static HLOCAL GRPFILE_ScanGroup(LPCSTR buffer, INT size,
157 LPCSTR lpszGrpFile,
158 BOOL bModifiedFileName)
160 HLOCAL hGroup;
161 INT i, seqnum;
162 LPCSTR extension;
163 LPCSTR lpszName;
164 INT x, y, width, height, iconx, icony, nCmdShow;
165 INT number_of_programs;
166 BOOL bOverwriteFileOk;
168 if (buffer[0] != 'P' || buffer[1] != 'M') return(0);
169 if (buffer[2] == 'C' && buffer[3] == 'C')
170 /* original with checksum */
171 bOverwriteFileOk = FALSE;
172 else if (buffer[2] == 'X' && buffer[3] == 'X')
173 /* modified without checksum */
174 bOverwriteFileOk = TRUE;
175 else return(0);
177 /* checksum = GET_USHORT(buffer, 4) (ignored) */
179 extension = buffer + GET_USHORT(buffer, 6);
180 if (extension == buffer + size) extension = 0;
181 else if (extension + 6 > buffer + size) return(0);
183 nCmdShow = GET_USHORT(buffer, 8);
184 x = GET_SHORT(buffer, 10);
185 y = GET_SHORT(buffer, 12);
186 width = GET_USHORT(buffer, 14);
187 height = GET_USHORT(buffer, 16);
188 iconx = GET_SHORT(buffer, 18);
189 icony = GET_SHORT(buffer, 20);
190 lpszName = buffer + GET_USHORT(buffer, 22);
191 if (lpszName >= buffer + size) return(0);
193 /* unknown bytes 24 - 31 ignored */
195 Unknown bytes should be:
196 wLogPixelsX = GET_SHORT(buffer, 24);
197 wLogPixelsY = GET_SHORT(buffer, 26);
198 byBitsPerPixel = byte at 28;
199 byPlanes = byte at 29;
200 wReserved = GET_SHORT(buffer, 30);
203 hGroup = GROUP_AddGroup(lpszName, lpszGrpFile, nCmdShow, x, y,
204 width, height, iconx, icony,
205 bModifiedFileName, bOverwriteFileOk,
206 TRUE);
207 if (!hGroup) return(0);
209 number_of_programs = GET_USHORT(buffer, 32);
210 if (2 * number_of_programs + 34 > size) return(0);
211 for (i=0, seqnum=0; i < number_of_programs; i++, seqnum++)
213 LPCSTR program_ptr = buffer + GET_USHORT(buffer, 34 + 2*i);
214 if (program_ptr + 24 > buffer + size) return(0);
215 if (!GET_USHORT(buffer, 34 + 2*i)) continue;
216 if (!GRPFILE_ScanProgram(buffer, size, program_ptr, seqnum,
217 extension, hGroup, lpszGrpFile))
219 GROUP_DeleteGroup(hGroup);
220 return(0);
224 /* FIXME shouldn't be necessary */
225 GROUP_ShowGroupWindow(hGroup);
227 return hGroup;
230 /***********************************************************************
231 * GRPFILE_ScanProgram
234 static HLOCAL GRPFILE_ScanProgram(LPCSTR buffer, INT size,
235 LPCSTR program_ptr, INT seqnum,
236 LPCSTR extension, HLOCAL hGroup,
237 LPCSTR lpszGrpFile)
239 INT icontype;
240 HICON hIcon;
241 LPCSTR lpszName, lpszCmdLine, lpszIconFile, lpszWorkDir;
242 LPCSTR iconinfo_ptr, iconANDbits_ptr, iconXORbits_ptr;
243 INT x, y, nIconIndex, iconANDsize, iconXORsize;
244 INT nHotKey, nCmdShow;
245 CURSORICONINFO iconinfo;
247 x = GET_SHORT(program_ptr, 0);
248 y = GET_SHORT(program_ptr, 2);
249 nIconIndex = GET_USHORT(program_ptr, 4);
251 /* FIXME is this correct ?? */
252 icontype = GET_USHORT(program_ptr, 6);
253 switch (icontype)
255 default:
256 MAIN_MessageBoxIDS_s(IDS_UNKNOWN_FEATURE_s, lpszGrpFile,
257 IDS_WARNING, MB_OK);
258 case 0x048c:
259 iconXORsize = GET_USHORT(program_ptr, 8);
260 iconANDsize = GET_USHORT(program_ptr, 10) / 8;
261 iconinfo_ptr = buffer + GET_USHORT(program_ptr, 12);
262 iconXORbits_ptr = buffer + GET_USHORT(program_ptr, 14);
263 iconANDbits_ptr = buffer + GET_USHORT(program_ptr, 16);
264 iconinfo.ptHotSpot.x = GET_USHORT(iconinfo_ptr, 0);
265 iconinfo.ptHotSpot.y = GET_USHORT(iconinfo_ptr, 2);
266 iconinfo.nWidth = GET_USHORT(iconinfo_ptr, 4);
267 iconinfo.nHeight = GET_USHORT(iconinfo_ptr, 6);
268 iconinfo.nWidthBytes = GET_USHORT(iconinfo_ptr, 8);
269 iconinfo.bPlanes = GET_USHORT(iconinfo_ptr, 10);
270 iconinfo.bBitsPerPixel = GET_USHORT(iconinfo_ptr, 11);
271 break;
272 case 0x000c:
273 iconANDsize = GET_USHORT(program_ptr, 8);
274 iconXORsize = GET_USHORT(program_ptr, 10);
275 iconinfo_ptr = buffer + GET_USHORT(program_ptr, 12);
276 iconANDbits_ptr = buffer + GET_USHORT(program_ptr, 14);
277 iconXORbits_ptr = buffer + GET_USHORT(program_ptr, 16);
278 iconinfo.ptHotSpot.x = GET_USHORT(iconinfo_ptr, 0);
279 iconinfo.ptHotSpot.y = GET_USHORT(iconinfo_ptr, 2);
280 iconinfo.nWidth = GET_USHORT(iconinfo_ptr, 4);
281 iconinfo.nHeight = GET_USHORT(iconinfo_ptr, 6);
282 iconinfo.nWidthBytes = GET_USHORT(iconinfo_ptr, 8) * 8;
283 iconinfo.bPlanes = GET_USHORT(iconinfo_ptr, 10);
284 iconinfo.bBitsPerPixel = GET_USHORT(iconinfo_ptr, 11);
287 if (iconANDbits_ptr + iconANDsize > buffer + size ||
288 iconXORbits_ptr + iconXORsize > buffer + size) return(0);
290 hIcon = CreateIcon( Globals.hInstance, iconinfo.nWidth, iconinfo.nHeight,
291 iconinfo.bPlanes, iconinfo.bBitsPerPixel,
292 iconANDbits_ptr, iconXORbits_ptr );
294 lpszName = buffer + GET_USHORT(program_ptr, 18);
295 lpszCmdLine = buffer + GET_USHORT(program_ptr, 20);
296 lpszIconFile = buffer + GET_USHORT(program_ptr, 22);
297 if (iconinfo_ptr + 6 > buffer + size ||
298 lpszName > buffer + size ||
299 lpszCmdLine > buffer + size ||
300 lpszIconFile > buffer + size) return(0);
302 /* Scan Extensions */
303 lpszWorkDir = "";
304 nHotKey = 0;
305 nCmdShow = SW_SHOWNORMAL;
306 if (extension)
308 LPCSTR ptr = extension;
309 while (ptr + 6 <= buffer + size)
311 UINT type = GET_USHORT(ptr, 0);
312 UINT number = GET_USHORT(ptr, 2);
313 UINT skip = GET_USHORT(ptr, 4);
315 if (number == seqnum)
317 switch (type)
319 case 0x8000:
320 if (ptr + 10 > buffer + size) return(0);
321 if (ptr[6] != 'P' || ptr[7] != 'M' ||
322 ptr[8] != 'C' || ptr[9] != 'C') return(0);
323 break;
324 case 0x8101:
325 lpszWorkDir = ptr + 6;
326 break;
327 case 0x8102:
328 if (ptr + 8 > buffer + size) return(0);
329 nHotKey = GET_USHORT(ptr, 6);
330 break;
331 case 0x8103:
332 if (ptr + 8 > buffer + size) return(0);
333 nCmdShow = GET_USHORT(ptr, 6);
334 break;
335 default:
336 MAIN_MessageBoxIDS_s(IDS_UNKNOWN_FEATURE_s,
337 lpszGrpFile, IDS_WARNING, MB_OK);
340 if (!skip) break;
341 ptr += skip;
345 return (PROGRAM_AddProgram(hGroup, hIcon, lpszName, x, y,
346 lpszCmdLine, lpszIconFile,
347 nIconIndex, lpszWorkDir,
348 nHotKey, nCmdShow));
351 /***********************************************************************
353 * GRPFILE_WriteGroupFile
356 BOOL GRPFILE_WriteGroupFile(HLOCAL hGroup)
358 CHAR szPath[MAX_PATHNAME_LEN];
359 PROGGROUP *group = LocalLock(hGroup);
360 OFSTRUCT dummy;
361 HFILE file;
362 BOOL ret;
364 GRPFILE_ModifyFileName(szPath, LocalLock(group->hGrpFile),
365 MAX_PATHNAME_LEN,
366 group->bFileNameModified);
368 /* Try not to overwrite original files */
370 /* group->bOverwriteFileOk == TRUE only if a file has the modified format */
371 if (!group->bOverwriteFileOk &&
372 OpenFile(szPath, &dummy, OF_EXIST) != HFILE_ERROR)
374 /* Original file exists, try `.gr' extension */
375 GRPFILE_ModifyFileName(szPath, LocalLock(group->hGrpFile),
376 MAX_PATHNAME_LEN, TRUE);
377 if (OpenFile(szPath, &dummy, OF_EXIST) != HFILE_ERROR)
379 /* File exists. Do not overwrite */
380 MAIN_MessageBoxIDS_s(IDS_FILE_NOT_OVERWRITTEN_s, szPath,
381 IDS_INFO, MB_OK);
382 return FALSE;
384 /* Inform about the modified file name */
385 if (IDCANCEL ==
386 MAIN_MessageBoxIDS_s(IDS_SAVE_GROUP_AS_s, szPath, IDS_INFO,
387 MB_OKCANCEL | MB_ICONINFORMATION))
388 return FALSE;
392 /* Warn about the (possible) incompatibility */
393 CHAR msg[MAX_PATHNAME_LEN + 200];
394 wsprintf(msg,
395 "Group files written by this DRAFT Program Manager "
396 "possibly cannot be read by the Microsoft Program Manager!!\n"
397 "Are you sure to write %s?", szPath);
398 if (IDOK != MessageBox(Globals.hMainWnd, msg, "WARNING",
399 MB_OKCANCEL | MB_DEFBUTTON2)) return FALSE;
402 /* FIXME */
403 if (OpenFile(szPath, &dummy, OF_EXIST) == HFILE_ERROR)
405 CHAR msg[MAX_PATHNAME_LEN + 200];
406 wsprintf(msg, "Cause of a bug you must now touch the file %s\n", szPath);
407 MessageBox(Globals.hMainWnd, msg, "", MB_OK);
410 /* Open file */
411 file = _lopen(szPath, OF_WRITE);
412 if (file != HFILE_ERROR)
414 ret = GRPFILE_DoWriteGroupFile(file, group);
415 _lclose(file);
417 else ret = FALSE;
419 if (!ret)
420 MAIN_MessageBoxIDS_s(IDS_FILE_WRITE_ERROR_s, szPath, IDS_ERROR, MB_OK);
422 return(ret);
425 /***********************************************************************
427 * GRPFILE_CalculateSizes
430 static VOID GRPFILE_CalculateSizes(PROGRAM *program,
431 INT *Progs, INT *Icons)
433 CURSORICONINFO *iconinfo = LocalLock(program->hIcon);
434 INT sizeXor = iconinfo->nHeight * iconinfo->nWidthBytes;
435 INT sizeAnd = iconinfo->nHeight * ((iconinfo->nWidth + 15) / 16 * 2);
437 *Progs += 24;
438 *Progs += lstrlen(LocalLock(program->hName)) + 1;
439 *Progs += lstrlen(LocalLock(program->hCmdLine)) + 1;
440 *Progs += lstrlen(LocalLock(program->hIconFile)) + 1;
442 *Icons += 12; /* IconInfo */
443 *Icons += sizeAnd;
444 *Icons += sizeXor;
447 /***********************************************************************/
448 UINT16 GRPFILE_checksum;
449 BOOL GRPFILE_checksum_half_word;
450 BYTE GRPFILE_checksum_last_byte;
451 /***********************************************************************
453 * GRPFILE_InitChecksum
456 static void GRPFILE_InitChecksum(void)
458 GRPFILE_checksum = 0;
459 GRPFILE_checksum_half_word = 0;
462 /***********************************************************************
464 * GRPFILE_GetChecksum
467 static UINT16 GRPFILE_GetChecksum(void)
469 return GRPFILE_checksum;
472 /***********************************************************************
474 * GRPFILE_WriteWithChecksum
476 * Looks crazier than it is:
478 * chksum = 0;
479 * chksum = cksum - 1. word;
480 * chksum = cksum - 2. word;
481 * ...
483 * if (filelen is even)
484 * great I'm finished
485 * else
486 * ignore last byte
489 static UINT GRPFILE_WriteWithChecksum(HFILE file, LPCSTR str, UINT size)
491 UINT i;
492 if (GRPFILE_checksum_half_word) {
493 GRPFILE_checksum -= GRPFILE_checksum_last_byte;
495 for (i=0; i < size; i++) {
496 if (GRPFILE_checksum_half_word) {
497 GRPFILE_checksum -= str[i] << 8;
498 } else {
499 GRPFILE_checksum -= str[i];
501 GRPFILE_checksum_half_word ^= 1;
504 if (GRPFILE_checksum_half_word) {
505 GRPFILE_checksum_last_byte = str[size-1];
506 GRPFILE_checksum += GRPFILE_checksum_last_byte;
509 return _lwrite(file, str, size);
513 /***********************************************************************
515 * GRPFILE_DoWriteGroupFile
518 static BOOL GRPFILE_DoWriteGroupFile(HFILE file, PROGGROUP *group)
520 CHAR buffer[34];
521 HLOCAL hProgram;
522 INT NumProg, Title, Progs, Icons, Extension;
523 INT CurrProg, CurrIcon, nCmdShow, ptr, seqnum;
524 BOOL need_extension;
525 LPCSTR lpszTitle = LocalLock(group->hName);
527 UINT16 checksum;
529 GRPFILE_InitChecksum();
531 /* Calculate offsets */
532 NumProg = 0;
533 Icons = 0;
534 Extension = 0;
535 need_extension = FALSE;
536 hProgram = group->hPrograms;
537 while(hProgram)
539 PROGRAM *program = LocalLock(hProgram);
540 LPCSTR lpszWorkDir = LocalLock(program->hWorkDir);
542 NumProg++;
543 GRPFILE_CalculateSizes(program, &Icons, &Extension);
545 /* Set a flag if an extension is needed */
546 if (lpszWorkDir[0] || program->nHotKey ||
547 program->nCmdShow != SW_SHOWNORMAL) need_extension = TRUE;
549 hProgram = program->hNext;
551 Title = 34 + NumProg * 2;
552 Progs = Title + lstrlen(lpszTitle) + 1;
553 Icons += Progs;
554 Extension += Icons;
556 /* Header */
557 buffer[0] = 'P';
558 buffer[1] = 'M';
559 buffer[2] = 'C';
560 buffer[3] = 'C';
562 PUT_SHORT(buffer, 4, 0); /* Checksum zero for now, written later */
563 PUT_SHORT(buffer, 6, Extension);
564 /* Update group->nCmdShow */
565 if (IsIconic(group->hWnd)) nCmdShow = SW_SHOWMINIMIZED;
566 else if (IsZoomed(group->hWnd)) nCmdShow = SW_SHOWMAXIMIZED;
567 else nCmdShow = SW_SHOWNORMAL;
568 PUT_SHORT(buffer, 8, nCmdShow);
569 PUT_SHORT(buffer, 10, group->x);
570 PUT_SHORT(buffer, 12, group->y);
571 PUT_SHORT(buffer, 14, group->width);
572 PUT_SHORT(buffer, 16, group->height);
573 PUT_SHORT(buffer, 18, group->iconx);
574 PUT_SHORT(buffer, 20, group->icony);
575 PUT_SHORT(buffer, 22, Title);
576 PUT_SHORT(buffer, 24, 0x0020); /* unknown */
577 PUT_SHORT(buffer, 26, 0x0020); /* unknown */
578 PUT_SHORT(buffer, 28, 0x0108); /* unknown */
579 PUT_SHORT(buffer, 30, 0x0000); /* unknown */
580 PUT_SHORT(buffer, 32, NumProg);
582 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 34)) return FALSE;
584 /* Program table */
585 CurrProg = Progs;
586 CurrIcon = Icons;
587 hProgram = group->hPrograms;
588 while(hProgram)
590 PROGRAM *program = LocalLock(hProgram);
592 PUT_SHORT(buffer, 0, CurrProg);
593 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 2))
594 return FALSE;
596 GRPFILE_CalculateSizes(program, &CurrProg, &CurrIcon);
597 hProgram = program->hNext;
600 /* Title */
601 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, lpszTitle,
602 lstrlen(lpszTitle) + 1))
603 return FALSE;
605 /* Program entries */
606 CurrProg = Progs;
607 CurrIcon = Icons;
608 hProgram = group->hPrograms;
609 while(hProgram)
611 PROGRAM *program = LocalLock(hProgram);
612 CURSORICONINFO *iconinfo = LocalLock(program->hIcon);
613 LPCSTR Name = LocalLock(program->hName);
614 LPCSTR CmdLine = LocalLock(program->hCmdLine);
615 LPCSTR IconFile = LocalLock(program->hIconFile);
616 INT sizeXor = iconinfo->nHeight * iconinfo->nWidthBytes;
617 INT sizeAnd = iconinfo->nHeight * ((iconinfo->nWidth + 15) / 16 * 2);
619 PUT_SHORT(buffer, 0, program->x);
620 PUT_SHORT(buffer, 2, program->y);
621 PUT_SHORT(buffer, 4, program->nIconIndex);
622 PUT_SHORT(buffer, 6, 0x048c); /* unknown */
623 PUT_SHORT(buffer, 8, sizeXor);
624 PUT_SHORT(buffer, 10, sizeAnd * 8);
625 PUT_SHORT(buffer, 12, CurrIcon);
626 PUT_SHORT(buffer, 14, CurrIcon + 12 + sizeAnd);
627 PUT_SHORT(buffer, 16, CurrIcon + 12);
628 ptr = CurrProg + 24;
629 PUT_SHORT(buffer, 18, ptr);
630 ptr += lstrlen(Name) + 1;
631 PUT_SHORT(buffer, 20, ptr);
632 ptr += lstrlen(CmdLine) + 1;
633 PUT_SHORT(buffer, 22, ptr);
635 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 24) ||
636 (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, Name, lstrlen(Name) + 1) ||
637 (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, CmdLine, lstrlen(CmdLine) + 1) ||
638 (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, IconFile, lstrlen(IconFile) + 1))
639 return FALSE;
641 GRPFILE_CalculateSizes(program, &CurrProg, &CurrIcon);
642 hProgram = program->hNext;
645 /* Icons */
646 #if 0 /* FIXME: this is broken anyway */
647 hProgram = group->hPrograms;
648 while(hProgram)
650 PROGRAM *program = LocalLock(hProgram);
651 CURSORICONINFO *iconinfo = LocalLock(program->hIcon);
652 LPVOID XorBits, AndBits;
653 INT sizeXor = iconinfo->nHeight * iconinfo->nWidthBytes;
654 INT sizeAnd = iconinfo->nHeight * ((iconinfo->nWidth + 15) / 16 * 2);
655 /* DumpIcon16(LocalLock(program->hIcon), 0, &XorBits, &AndBits);*/
657 PUT_SHORT(buffer, 0, iconinfo->ptHotSpot.x);
658 PUT_SHORT(buffer, 2, iconinfo->ptHotSpot.y);
659 PUT_SHORT(buffer, 4, iconinfo->nWidth);
660 PUT_SHORT(buffer, 6, iconinfo->nHeight);
661 PUT_SHORT(buffer, 8, iconinfo->nWidthBytes);
662 buffer[10] = iconinfo->bPlanes;
663 buffer[11] = iconinfo->bBitsPerPixel;
665 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 12) ||
666 (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, AndBits, sizeAnd) ||
667 (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, XorBits, sizeXor)) return FALSE;
669 hProgram = program->hNext;
671 #endif
673 if (need_extension)
675 /* write `PMCC' extension */
676 PUT_SHORT(buffer, 0, 0x8000);
677 PUT_SHORT(buffer, 2, 0xffff);
678 PUT_SHORT(buffer, 4, 0x000a);
679 buffer[6] = 'P', buffer[7] = 'M';
680 buffer[8] = 'C', buffer[9] = 'C';
681 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 10))
682 return FALSE;
684 seqnum = 0;
685 hProgram = group->hPrograms;
686 while(hProgram)
688 PROGRAM *program = LocalLock(hProgram);
689 LPCSTR lpszWorkDir = LocalLock(program->hWorkDir);
691 /* Working directory */
692 if (lpszWorkDir[0])
694 PUT_SHORT(buffer, 0, 0x8101);
695 PUT_SHORT(buffer, 2, seqnum);
696 PUT_SHORT(buffer, 4, 7 + lstrlen(lpszWorkDir));
697 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 6) ||
698 (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, lpszWorkDir, lstrlen(lpszWorkDir) + 1))
699 return FALSE;
702 /* Hot key */
703 if (program->nHotKey)
705 PUT_SHORT(buffer, 0, 0x8102);
706 PUT_SHORT(buffer, 2, seqnum);
707 PUT_SHORT(buffer, 4, 8);
708 PUT_SHORT(buffer, 6, program->nHotKey);
709 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 8)) return FALSE;
712 /* Show command */
713 if (program->nCmdShow)
715 PUT_SHORT(buffer, 0, 0x8103);
716 PUT_SHORT(buffer, 2, seqnum);
717 PUT_SHORT(buffer, 4, 8);
718 PUT_SHORT(buffer, 6, program->nCmdShow);
719 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 8)) return FALSE;
722 seqnum++;
723 hProgram = program->hNext;
726 /* Write `End' extension */
727 PUT_SHORT(buffer, 0, 0xffff);
728 PUT_SHORT(buffer, 2, 0xffff);
729 PUT_SHORT(buffer, 4, 0x0000);
730 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 6)) return FALSE;
733 checksum = GRPFILE_GetChecksum();
734 _llseek(file, 4, SEEK_SET);
735 PUT_SHORT(buffer, 0, checksum);
736 _lwrite(file, buffer, 2);
738 return TRUE;
741 /* Local Variables: */
742 /* c-file-style: "GNU" */
743 /* End: */