Added configuration on per application basis.
[wine/hacks.git] / programs / progman / grpfile.c
blob88c2d857e22ef1b11fec32010906282ed929f7f7
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 #include "windows.h"
23 #include "wine/winuser16.h"
24 #include "progman.h"
25 #include "mmsystem.h"
27 #define MALLOCHUNK 1000
29 #define GET_USHORT(buffer, i)\
30 (((BYTE)((buffer)[(i)]) + 0x100 * (BYTE)((buffer)[(i)+1])))
31 #define GET_SHORT(buffer, i)\
32 (((BYTE)((buffer)[(i)]) + 0x100 * (signed char)((buffer)[(i)+1])))
33 #define PUT_SHORT(buffer, i, s)\
34 (((buffer)[(i)] = (s) & 0xff, (buffer)[(i)+1] = ((s) >> 8) & 0xff))
36 static BOOL GRPFILE_ReadFileToBuffer(LPCSTR, HLOCAL*, INT*);
37 static HLOCAL GRPFILE_ScanGroup(LPCSTR, INT, LPCSTR, BOOL);
38 static HLOCAL GRPFILE_ScanProgram(LPCSTR, INT, LPCSTR, INT,
39 LPCSTR, HLOCAL,LPCSTR);
40 static BOOL GRPFILE_DoWriteGroupFile(HFILE file, PROGGROUP *group);
42 /***********************************************************************
44 * GRPFILE_ModifyFileName
46 * Change extension `.grp' to `.gr'
49 static VOID GRPFILE_ModifyFileName(LPSTR lpszNewName, LPCSTR lpszOrigName,
50 INT nSize, BOOL bModify)
52 lstrcpyn(lpszNewName, lpszOrigName, nSize);
53 lpszNewName[nSize-1] = '\0';
54 if (!bModify) return;
55 if (!lstrcmpi(lpszNewName + strlen(lpszNewName) - 4, ".grp"))
56 lpszNewName[strlen(lpszNewName) - 1] = '\0';
59 /***********************************************************************
61 * GRPFILE_ReadGroupFile
64 HLOCAL GRPFILE_ReadGroupFile(LPCSTR lpszPath)
66 CHAR szPath_gr[MAX_PATHNAME_LEN];
67 BOOL bFileNameModified = FALSE;
68 OFSTRUCT dummy;
69 HLOCAL hBuffer, hGroup;
70 INT size;
72 /* if `.gr' file exists use that */
73 GRPFILE_ModifyFileName(szPath_gr, lpszPath, MAX_PATHNAME_LEN, TRUE);
74 if (OpenFile(szPath_gr, &dummy, OF_EXIST) != HFILE_ERROR)
76 lpszPath = szPath_gr;
77 bFileNameModified = TRUE;
80 /* Read the whole file into a buffer */
81 if (!GRPFILE_ReadFileToBuffer(lpszPath, &hBuffer, &size))
83 MAIN_MessageBoxIDS_s(IDS_GRPFILE_READ_ERROR_s, lpszPath, IDS_ERROR, MB_YESNO);
84 return(0);
87 /* Interpret buffer */
88 hGroup = GRPFILE_ScanGroup(LocalLock(hBuffer), size,
89 lpszPath, bFileNameModified);
90 if (!hGroup)
91 MAIN_MessageBoxIDS_s(IDS_GRPFILE_READ_ERROR_s, lpszPath, IDS_ERROR, MB_YESNO);
93 LocalFree(hBuffer);
95 return(hGroup);
98 /***********************************************************************
100 * GRPFILE_ReadFileToBuffer
103 static BOOL GRPFILE_ReadFileToBuffer(LPCSTR path, HLOCAL *phBuffer,
104 INT *piSize)
106 UINT len, size;
107 LPSTR buffer;
108 HLOCAL hBuffer, hNewBuffer;
109 HFILE file;
111 file=_lopen(path, OF_READ);
112 if (file == HFILE_ERROR) return FALSE;
114 size = 0;
115 hBuffer = LocalAlloc(LMEM_FIXED, size + MALLOCHUNK + 1);
116 if (!hBuffer) return FALSE;
117 buffer = LocalLock(hBuffer);
119 while ((len = _lread(file, buffer + size, MALLOCHUNK))
120 == MALLOCHUNK)
122 size += len;
123 hNewBuffer = LocalReAlloc(hBuffer, size + MALLOCHUNK + 1,
124 LMEM_FIXED);
125 if (!hNewBuffer)
127 LocalFree(hBuffer);
128 return FALSE;
130 hBuffer = hNewBuffer;
131 buffer = LocalLock(hBuffer);
134 _lclose(file);
136 if (len == (UINT)HFILE_ERROR)
138 LocalFree(hBuffer);
139 return FALSE;
142 size += len;
143 buffer[size] = 0;
145 *phBuffer = hBuffer;
146 *piSize = size;
147 return TRUE;
150 /***********************************************************************
151 * GRPFILE_ScanGroup
154 static HLOCAL GRPFILE_ScanGroup(LPCSTR buffer, INT size,
155 LPCSTR lpszGrpFile,
156 BOOL bModifiedFileName)
158 HLOCAL hGroup;
159 INT i, seqnum;
160 LPCSTR extension;
161 LPCSTR lpszName;
162 INT x, y, width, height, iconx, icony, nCmdShow;
163 INT number_of_programs;
164 BOOL bOverwriteFileOk;
166 if (buffer[0] != 'P' || buffer[1] != 'M') return(0);
167 if (buffer[2] == 'C' && buffer[3] == 'C')
168 /* original with checksum */
169 bOverwriteFileOk = FALSE;
170 else if (buffer[2] == 'X' && buffer[3] == 'X')
171 /* modified without checksum */
172 bOverwriteFileOk = TRUE;
173 else return(0);
175 /* checksum = GET_USHORT(buffer, 4) (ignored) */
177 extension = buffer + GET_USHORT(buffer, 6);
178 if (extension == buffer + size) extension = 0;
179 else if (extension + 6 > buffer + size) return(0);
181 nCmdShow = GET_USHORT(buffer, 8);
182 x = GET_SHORT(buffer, 10);
183 y = GET_SHORT(buffer, 12);
184 width = GET_USHORT(buffer, 14);
185 height = GET_USHORT(buffer, 16);
186 iconx = GET_SHORT(buffer, 18);
187 icony = GET_SHORT(buffer, 20);
188 lpszName = buffer + GET_USHORT(buffer, 22);
189 if (lpszName >= buffer + size) return(0);
191 /* unknown bytes 24 - 31 ignored */
193 Unknown bytes should be:
194 wLogPixelsX = GET_SHORT(buffer, 24);
195 wLogPixelsY = GET_SHORT(buffer, 26);
196 byBitsPerPixel = byte at 28;
197 byPlanes = byte at 29;
198 wReserved = GET_SHORT(buffer, 30);
201 hGroup = GROUP_AddGroup(lpszName, lpszGrpFile, nCmdShow, x, y,
202 width, height, iconx, icony,
203 bModifiedFileName, bOverwriteFileOk,
204 TRUE);
205 if (!hGroup) return(0);
207 number_of_programs = GET_USHORT(buffer, 32);
208 if (2 * number_of_programs + 34 > size) return(0);
209 for (i=0, seqnum=0; i < number_of_programs; i++, seqnum++)
211 LPCSTR program_ptr = buffer + GET_USHORT(buffer, 34 + 2*i);
212 if (program_ptr + 24 > buffer + size) return(0);
213 if (!GET_USHORT(buffer, 34 + 2*i)) continue;
214 if (!GRPFILE_ScanProgram(buffer, size, program_ptr, seqnum,
215 extension, hGroup, lpszGrpFile))
217 GROUP_DeleteGroup(hGroup);
218 return(0);
222 /* FIXME shouldn't be necessary */
223 GROUP_ShowGroupWindow(hGroup);
225 return hGroup;
228 /***********************************************************************
229 * GRPFILE_ScanProgram
232 static HLOCAL GRPFILE_ScanProgram(LPCSTR buffer, INT size,
233 LPCSTR program_ptr, INT seqnum,
234 LPCSTR extension, HLOCAL hGroup,
235 LPCSTR lpszGrpFile)
237 INT icontype;
238 HICON hIcon;
239 LPCSTR lpszName, lpszCmdLine, lpszIconFile, lpszWorkDir;
240 LPCSTR iconinfo_ptr, iconANDbits_ptr, iconXORbits_ptr;
241 INT x, y, nIconIndex, iconANDsize, iconXORsize;
242 INT nHotKey, nCmdShow;
243 CURSORICONINFO iconinfo;
245 x = GET_SHORT(program_ptr, 0);
246 y = GET_SHORT(program_ptr, 2);
247 nIconIndex = GET_USHORT(program_ptr, 4);
249 /* FIXME is this correct ?? */
250 icontype = GET_USHORT(program_ptr, 6);
251 switch (icontype)
253 default:
254 MAIN_MessageBoxIDS_s(IDS_UNKNOWN_FEATURE_s, lpszGrpFile,
255 IDS_WARNING, MB_OK);
256 case 0x048c:
257 iconXORsize = GET_USHORT(program_ptr, 8);
258 iconANDsize = GET_USHORT(program_ptr, 10) / 8;
259 iconinfo_ptr = buffer + GET_USHORT(program_ptr, 12);
260 iconXORbits_ptr = buffer + GET_USHORT(program_ptr, 14);
261 iconANDbits_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);
267 iconinfo.bPlanes = GET_USHORT(iconinfo_ptr, 10);
268 iconinfo.bBitsPerPixel = GET_USHORT(iconinfo_ptr, 11);
269 break;
270 case 0x000c:
271 iconANDsize = GET_USHORT(program_ptr, 8);
272 iconXORsize = GET_USHORT(program_ptr, 10);
273 iconinfo_ptr = buffer + GET_USHORT(program_ptr, 12);
274 iconANDbits_ptr = buffer + GET_USHORT(program_ptr, 14);
275 iconXORbits_ptr = buffer + GET_USHORT(program_ptr, 16);
276 iconinfo.ptHotSpot.x = GET_USHORT(iconinfo_ptr, 0);
277 iconinfo.ptHotSpot.y = GET_USHORT(iconinfo_ptr, 2);
278 iconinfo.nWidth = GET_USHORT(iconinfo_ptr, 4);
279 iconinfo.nHeight = GET_USHORT(iconinfo_ptr, 6);
280 iconinfo.nWidthBytes = GET_USHORT(iconinfo_ptr, 8) * 8;
281 iconinfo.bPlanes = GET_USHORT(iconinfo_ptr, 10);
282 iconinfo.bBitsPerPixel = GET_USHORT(iconinfo_ptr, 11);
285 if (iconANDbits_ptr + iconANDsize > buffer + size ||
286 iconXORbits_ptr + iconXORsize > buffer + size) return(0);
288 hIcon = CreateIcon( Globals.hInstance, iconinfo.nWidth, iconinfo.nHeight,
289 iconinfo.bPlanes, iconinfo.bBitsPerPixel,
290 iconANDbits_ptr, iconXORbits_ptr );
292 lpszName = buffer + GET_USHORT(program_ptr, 18);
293 lpszCmdLine = buffer + GET_USHORT(program_ptr, 20);
294 lpszIconFile = buffer + GET_USHORT(program_ptr, 22);
295 if (iconinfo_ptr + 6 > buffer + size ||
296 lpszName > buffer + size ||
297 lpszCmdLine > buffer + size ||
298 lpszIconFile > buffer + size) return(0);
300 /* Scan Extensions */
301 lpszWorkDir = "";
302 nHotKey = 0;
303 nCmdShow = SW_SHOWNORMAL;
304 if (extension)
306 LPCSTR ptr = extension;
307 while (ptr + 6 <= buffer + size)
309 UINT type = GET_USHORT(ptr, 0);
310 UINT number = GET_USHORT(ptr, 2);
311 UINT skip = GET_USHORT(ptr, 4);
313 if (number == seqnum)
315 switch (type)
317 case 0x8000:
318 if (ptr + 10 > buffer + size) return(0);
319 if (ptr[6] != 'P' || ptr[7] != 'M' ||
320 ptr[8] != 'C' || ptr[9] != 'C') return(0);
321 break;
322 case 0x8101:
323 lpszWorkDir = ptr + 6;
324 break;
325 case 0x8102:
326 if (ptr + 8 > buffer + size) return(0);
327 nHotKey = GET_USHORT(ptr, 6);
328 break;
329 case 0x8103:
330 if (ptr + 8 > buffer + size) return(0);
331 nCmdShow = GET_USHORT(ptr, 6);
332 break;
333 default:
334 MAIN_MessageBoxIDS_s(IDS_UNKNOWN_FEATURE_s,
335 lpszGrpFile, IDS_WARNING, MB_OK);
338 if (!skip) break;
339 ptr += skip;
343 return (PROGRAM_AddProgram(hGroup, hIcon, lpszName, x, y,
344 lpszCmdLine, lpszIconFile,
345 nIconIndex, lpszWorkDir,
346 nHotKey, nCmdShow));
349 /***********************************************************************
351 * GRPFILE_WriteGroupFile
354 BOOL GRPFILE_WriteGroupFile(HLOCAL hGroup)
356 CHAR szPath[MAX_PATHNAME_LEN];
357 PROGGROUP *group = LocalLock(hGroup);
358 OFSTRUCT dummy;
359 HFILE file;
360 BOOL ret;
362 GRPFILE_ModifyFileName(szPath, LocalLock(group->hGrpFile),
363 MAX_PATHNAME_LEN,
364 group->bFileNameModified);
366 /* Try not to overwrite original files */
368 /* group->bOverwriteFileOk == TRUE only if a file has the modified format */
369 if (!group->bOverwriteFileOk &&
370 OpenFile(szPath, &dummy, OF_EXIST) != HFILE_ERROR)
372 /* Original file exists, try `.gr' extension */
373 GRPFILE_ModifyFileName(szPath, LocalLock(group->hGrpFile),
374 MAX_PATHNAME_LEN, TRUE);
375 if (OpenFile(szPath, &dummy, OF_EXIST) != HFILE_ERROR)
377 /* File exists. Do not overwrite */
378 MAIN_MessageBoxIDS_s(IDS_FILE_NOT_OVERWRITTEN_s, szPath,
379 IDS_INFO, MB_OK);
380 return FALSE;
382 /* Inform about the modified file name */
383 if (IDCANCEL ==
384 MAIN_MessageBoxIDS_s(IDS_SAVE_GROUP_AS_s, szPath, IDS_INFO,
385 MB_OKCANCEL | MB_ICONINFORMATION))
386 return FALSE;
390 /* Warn about the (possible) incompatibility */
391 CHAR msg[MAX_PATHNAME_LEN + 200];
392 wsprintf(msg,
393 "Group files written by this DRAFT Program Manager "
394 "possibly cannot be read by the Microsoft Program Manager!!\n"
395 "Are you sure to write %s?", szPath);
396 if (IDOK != MessageBox(Globals.hMainWnd, msg, "WARNING",
397 MB_OKCANCEL | MB_DEFBUTTON2)) return FALSE;
400 /* FIXME */
401 if (OpenFile(szPath, &dummy, OF_EXIST) == HFILE_ERROR)
403 CHAR msg[MAX_PATHNAME_LEN + 200];
404 wsprintf(msg, "Cause of a bug you must now touch the file %s\n", szPath);
405 MessageBox(Globals.hMainWnd, msg, "", MB_OK);
408 /* Open file */
409 file = _lopen(szPath, OF_WRITE);
410 if (file != HFILE_ERROR)
412 ret = GRPFILE_DoWriteGroupFile(file, group);
413 _lclose(file);
415 else ret = FALSE;
417 if (!ret)
418 MAIN_MessageBoxIDS_s(IDS_FILE_WRITE_ERROR_s, szPath, IDS_ERROR, MB_OK);
420 return(ret);
423 /***********************************************************************
425 * GRPFILE_CalculateSizes
428 static VOID GRPFILE_CalculateSizes(PROGRAM *program,
429 INT *Progs, INT *Icons)
431 CURSORICONINFO *iconinfo = LocalLock(program->hIcon);
432 INT sizeXor = iconinfo->nHeight * iconinfo->nWidthBytes;
433 INT sizeAnd = iconinfo->nHeight * ((iconinfo->nWidth + 15) / 16 * 2);
435 *Progs += 24;
436 *Progs += lstrlen(LocalLock(program->hName)) + 1;
437 *Progs += lstrlen(LocalLock(program->hCmdLine)) + 1;
438 *Progs += lstrlen(LocalLock(program->hIconFile)) + 1;
440 *Icons += 12; /* IconInfo */
441 *Icons += sizeAnd;
442 *Icons += sizeXor;
445 /***********************************************************************/
446 UINT16 GRPFILE_checksum;
447 BOOL GRPFILE_checksum_half_word;
448 BYTE GRPFILE_checksum_last_byte;
449 /***********************************************************************
451 * GRPFILE_InitChecksum
454 static void GRPFILE_InitChecksum()
456 GRPFILE_checksum = 0;
457 GRPFILE_checksum_half_word = 0;
460 /***********************************************************************
462 * GRPFILE_GetChecksum
465 static UINT16 GRPFILE_GetChecksum()
467 return GRPFILE_checksum;
470 /***********************************************************************
472 * GRPFILE_WriteWithChecksum
474 * Looks crazier than it is:
476 * chksum = 0;
477 * chksum = cksum - 1. word;
478 * chksum = cksum - 2. word;
479 * ...
481 * if (filelen is even)
482 * great I'm finished
483 * else
484 * ignore last byte
487 static UINT GRPFILE_WriteWithChecksum(HFILE file, LPCSTR str, UINT size)
489 UINT i;
490 if (GRPFILE_checksum_half_word) {
491 GRPFILE_checksum -= GRPFILE_checksum_last_byte;
493 for (i=0; i < size; i++) {
494 if (GRPFILE_checksum_half_word) {
495 GRPFILE_checksum -= str[i] << 8;
496 } else {
497 GRPFILE_checksum -= str[i];
499 GRPFILE_checksum_half_word ^= 1;
502 if (GRPFILE_checksum_half_word) {
503 GRPFILE_checksum_last_byte = str[size-1];
504 GRPFILE_checksum += GRPFILE_checksum_last_byte;
507 return _lwrite(file, str, size);
511 /***********************************************************************
513 * GRPFILE_DoWriteGroupFile
516 static BOOL GRPFILE_DoWriteGroupFile(HFILE file, PROGGROUP *group)
518 BYTE buffer[34];
519 HLOCAL hProgram;
520 INT NumProg, Title, Progs, Icons, Extension;
521 INT CurrProg, CurrIcon, nCmdShow, ptr, seqnum;
522 BOOL need_extension;
523 LPCSTR lpszTitle = LocalLock(group->hName);
525 UINT16 checksum;
527 GRPFILE_InitChecksum();
529 /* Calculate offsets */
530 NumProg = 0;
531 Icons = 0;
532 Extension = 0;
533 need_extension = FALSE;
534 hProgram = group->hPrograms;
535 while(hProgram)
537 PROGRAM *program = LocalLock(hProgram);
538 LPCSTR lpszWorkDir = LocalLock(program->hWorkDir);
540 NumProg++;
541 GRPFILE_CalculateSizes(program, &Icons, &Extension);
543 /* Set a flag if an extension is needed */
544 if (lpszWorkDir[0] || program->nHotKey ||
545 program->nCmdShow != SW_SHOWNORMAL) need_extension = TRUE;
547 hProgram = program->hNext;
549 Title = 34 + NumProg * 2;
550 Progs = Title + lstrlen(lpszTitle) + 1;
551 Icons += Progs;
552 Extension += Icons;
554 /* Header */
555 buffer[0] = 'P';
556 buffer[1] = 'M';
557 buffer[2] = 'C';
558 buffer[3] = 'C';
560 PUT_SHORT(buffer, 4, 0); /* Checksum zero for now, written later */
561 PUT_SHORT(buffer, 6, Extension);
562 /* Update group->nCmdShow */
563 if (IsIconic(group->hWnd)) nCmdShow = SW_SHOWMINIMIZED;
564 else if (IsZoomed(group->hWnd)) nCmdShow = SW_SHOWMAXIMIZED;
565 else nCmdShow = SW_SHOWNORMAL;
566 PUT_SHORT(buffer, 8, nCmdShow);
567 PUT_SHORT(buffer, 10, group->x);
568 PUT_SHORT(buffer, 12, group->y);
569 PUT_SHORT(buffer, 14, group->width);
570 PUT_SHORT(buffer, 16, group->height);
571 PUT_SHORT(buffer, 18, group->iconx);
572 PUT_SHORT(buffer, 20, group->icony);
573 PUT_SHORT(buffer, 22, Title);
574 PUT_SHORT(buffer, 24, 0x0020); /* unknown */
575 PUT_SHORT(buffer, 26, 0x0020); /* unknown */
576 PUT_SHORT(buffer, 28, 0x0108); /* unknown */
577 PUT_SHORT(buffer, 30, 0x0000); /* unknown */
578 PUT_SHORT(buffer, 32, NumProg);
580 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 34)) return FALSE;
582 /* Program table */
583 CurrProg = Progs;
584 CurrIcon = Icons;
585 hProgram = group->hPrograms;
586 while(hProgram)
588 PROGRAM *program = LocalLock(hProgram);
590 PUT_SHORT(buffer, 0, CurrProg);
591 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 2))
592 return FALSE;
594 GRPFILE_CalculateSizes(program, &CurrProg, &CurrIcon);
595 hProgram = program->hNext;
598 /* Title */
599 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, lpszTitle,
600 lstrlen(lpszTitle) + 1))
601 return FALSE;
603 /* Program entries */
604 CurrProg = Progs;
605 CurrIcon = Icons;
606 hProgram = group->hPrograms;
607 while(hProgram)
609 PROGRAM *program = LocalLock(hProgram);
610 CURSORICONINFO *iconinfo = LocalLock(program->hIcon);
611 LPCSTR Name = LocalLock(program->hName);
612 LPCSTR CmdLine = LocalLock(program->hCmdLine);
613 LPCSTR IconFile = LocalLock(program->hIconFile);
614 INT sizeXor = iconinfo->nHeight * iconinfo->nWidthBytes;
615 INT sizeAnd = iconinfo->nHeight * ((iconinfo->nWidth + 15) / 16 * 2);
617 PUT_SHORT(buffer, 0, program->x);
618 PUT_SHORT(buffer, 2, program->y);
619 PUT_SHORT(buffer, 4, program->nIconIndex);
620 PUT_SHORT(buffer, 6, 0x048c); /* unknown */
621 PUT_SHORT(buffer, 8, sizeXor);
622 PUT_SHORT(buffer, 10, sizeAnd * 8);
623 PUT_SHORT(buffer, 12, CurrIcon);
624 PUT_SHORT(buffer, 14, CurrIcon + 12 + sizeAnd);
625 PUT_SHORT(buffer, 16, CurrIcon + 12);
626 ptr = CurrProg + 24;
627 PUT_SHORT(buffer, 18, ptr);
628 ptr += lstrlen(Name) + 1;
629 PUT_SHORT(buffer, 20, ptr);
630 ptr += lstrlen(CmdLine) + 1;
631 PUT_SHORT(buffer, 22, ptr);
633 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 24) ||
634 (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, Name, lstrlen(Name) + 1) ||
635 (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, CmdLine, lstrlen(CmdLine) + 1) ||
636 (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, IconFile, lstrlen(IconFile) + 1))
637 return FALSE;
639 GRPFILE_CalculateSizes(program, &CurrProg, &CurrIcon);
640 hProgram = program->hNext;
643 /* Icons */
644 hProgram = group->hPrograms;
645 while(hProgram)
647 PROGRAM *program = LocalLock(hProgram);
648 CURSORICONINFO *iconinfo = LocalLock(program->hIcon);
649 LPVOID XorBits, AndBits;
650 INT sizeXor = iconinfo->nHeight * iconinfo->nWidthBytes;
651 INT sizeAnd = iconinfo->nHeight * ((iconinfo->nWidth + 15) / 16 * 2);
652 /* FIXME: this is broken anyway */
653 /* DumpIcon16(LocalLock(program->hIcon), 0, &XorBits, &AndBits);*/
655 PUT_SHORT(buffer, 0, iconinfo->ptHotSpot.x);
656 PUT_SHORT(buffer, 2, iconinfo->ptHotSpot.y);
657 PUT_SHORT(buffer, 4, iconinfo->nWidth);
658 PUT_SHORT(buffer, 6, iconinfo->nHeight);
659 PUT_SHORT(buffer, 8, iconinfo->nWidthBytes);
660 buffer[10] = iconinfo->bPlanes;
661 buffer[11] = iconinfo->bBitsPerPixel;
663 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 12) ||
664 (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, AndBits, sizeAnd) ||
665 (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, XorBits, sizeXor)) return FALSE;
667 hProgram = program->hNext;
670 if (need_extension)
672 /* write `PMCC' extension */
673 PUT_SHORT(buffer, 0, 0x8000);
674 PUT_SHORT(buffer, 2, 0xffff);
675 PUT_SHORT(buffer, 4, 0x000a);
676 buffer[6] = 'P', buffer[7] = 'M';
677 buffer[8] = 'C', buffer[9] = 'C';
678 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 10))
679 return FALSE;
681 seqnum = 0;
682 hProgram = group->hPrograms;
683 while(hProgram)
685 PROGRAM *program = LocalLock(hProgram);
686 LPCSTR lpszWorkDir = LocalLock(program->hWorkDir);
688 /* Working directory */
689 if (lpszWorkDir[0])
691 PUT_SHORT(buffer, 0, 0x8101);
692 PUT_SHORT(buffer, 2, seqnum);
693 PUT_SHORT(buffer, 4, 7 + lstrlen(lpszWorkDir));
694 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 6) ||
695 (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, lpszWorkDir, lstrlen(lpszWorkDir) + 1))
696 return FALSE;
699 /* Hot key */
700 if (program->nHotKey)
702 PUT_SHORT(buffer, 0, 0x8102);
703 PUT_SHORT(buffer, 2, seqnum);
704 PUT_SHORT(buffer, 4, 8);
705 PUT_SHORT(buffer, 6, program->nHotKey);
706 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 8)) return FALSE;
709 /* Show command */
710 if (program->nCmdShow)
712 PUT_SHORT(buffer, 0, 0x8103);
713 PUT_SHORT(buffer, 2, seqnum);
714 PUT_SHORT(buffer, 4, 8);
715 PUT_SHORT(buffer, 6, program->nCmdShow);
716 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 8)) return FALSE;
719 seqnum++;
720 hProgram = program->hNext;
723 /* Write `End' extension */
724 PUT_SHORT(buffer, 0, 0xffff);
725 PUT_SHORT(buffer, 2, 0xffff);
726 PUT_SHORT(buffer, 4, 0x0000);
727 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 6)) return FALSE;
730 checksum = GRPFILE_GetChecksum();
731 _llseek(file, 4, SEEK_SET);
732 PUT_SHORT(buffer, 0, checksum);
733 _lwrite(file, buffer, 2);
735 return TRUE;
738 /* Local Variables: */
739 /* c-file-style: "GNU" */
740 /* End: */