| /* | |
| * Program Manager | |
| * | |
| * Copyright 1996 Ulrich Schmid | |
| * 1997 Peter Schlaile | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| */ | |
| #include "windows.h" | |
| #include "wine/winuser16.h" | |
| #include "progman.h" | |
| #include "mmsystem.h" | |
| #define MALLOCHUNK 1000 | |
| #define GET_USHORT(buffer, i)\ | |
| (((BYTE)((buffer)[(i)]) + 0x100 * (BYTE)((buffer)[(i)+1]))) | |
| #define GET_SHORT(buffer, i)\ | |
| (((BYTE)((buffer)[(i)]) + 0x100 * (signed char)((buffer)[(i)+1]))) | |
| #define PUT_SHORT(buffer, i, s)\ | |
| (((buffer)[(i)] = (s) & 0xff, (buffer)[(i)+1] = ((s) >> 8) & 0xff)) | |
| static BOOL GRPFILE_ReadFileToBuffer(LPCSTR, HLOCAL*, INT*); | |
| static HLOCAL GRPFILE_ScanGroup(LPCSTR, INT, LPCSTR, BOOL); | |
| static HLOCAL GRPFILE_ScanProgram(LPCSTR, INT, LPCSTR, INT, | |
| LPCSTR, HLOCAL,LPCSTR); | |
| static BOOL GRPFILE_DoWriteGroupFile(HFILE file, PROGGROUP *group); | |
| /*********************************************************************** | |
| * | |
| * GRPFILE_ModifyFileName | |
| * | |
| * Change extension `.grp' to `.gr' | |
| */ | |
| static VOID GRPFILE_ModifyFileName(LPSTR lpszNewName, LPCSTR lpszOrigName, | |
| INT nSize, BOOL bModify) | |
| { | |
| lstrcpyn(lpszNewName, lpszOrigName, nSize); | |
| lpszNewName[nSize-1] = '\0'; | |
| if (!bModify) return; | |
| if (!lstrcmpi(lpszNewName + strlen(lpszNewName) - 4, ".grp")) | |
| lpszNewName[strlen(lpszNewName) - 1] = '\0'; | |
| } | |
| /*********************************************************************** | |
| * | |
| * GRPFILE_ReadGroupFile | |
| */ | |
| HLOCAL GRPFILE_ReadGroupFile(LPCSTR lpszPath) | |
| { | |
| CHAR szPath_gr[MAX_PATHNAME_LEN]; | |
| BOOL bFileNameModified = FALSE; | |
| OFSTRUCT dummy; | |
| HLOCAL hBuffer, hGroup; | |
| INT size; | |
| /* if `.gr' file exists use that */ | |
| GRPFILE_ModifyFileName(szPath_gr, lpszPath, MAX_PATHNAME_LEN, TRUE); | |
| if (OpenFile(szPath_gr, &dummy, OF_EXIST) != HFILE_ERROR) | |
| { | |
| lpszPath = szPath_gr; | |
| bFileNameModified = TRUE; | |
| } | |
| /* Read the whole file into a buffer */ | |
| if (!GRPFILE_ReadFileToBuffer(lpszPath, &hBuffer, &size)) | |
| { | |
| MAIN_MessageBoxIDS_s(IDS_GRPFILE_READ_ERROR_s, lpszPath, IDS_ERROR, MB_YESNO); | |
| return(0); | |
| } | |
| /* Interpret buffer */ | |
| hGroup = GRPFILE_ScanGroup(LocalLock(hBuffer), size, | |
| lpszPath, bFileNameModified); | |
| if (!hGroup) | |
| MAIN_MessageBoxIDS_s(IDS_GRPFILE_READ_ERROR_s, lpszPath, IDS_ERROR, MB_YESNO); | |
| LocalFree(hBuffer); | |
| return(hGroup); | |
| } | |
| /*********************************************************************** | |
| * | |
| * GRPFILE_ReadFileToBuffer | |
| */ | |
| static BOOL GRPFILE_ReadFileToBuffer(LPCSTR path, HLOCAL *phBuffer, | |
| INT *piSize) | |
| { | |
| UINT len, size; | |
| LPSTR buffer; | |
| HLOCAL hBuffer, hNewBuffer; | |
| HFILE file; | |
| file=_lopen(path, OF_READ); | |
| if (file == HFILE_ERROR) return FALSE; | |
| size = 0; | |
| hBuffer = LocalAlloc(LMEM_FIXED, size + MALLOCHUNK + 1); | |
| if (!hBuffer) return FALSE; | |
| buffer = LocalLock(hBuffer); | |
| while ((len = _lread(file, buffer + size, MALLOCHUNK)) | |
| == MALLOCHUNK) | |
| { | |
| size += len; | |
| hNewBuffer = LocalReAlloc(hBuffer, size + MALLOCHUNK + 1, | |
| LMEM_FIXED); | |
| if (!hNewBuffer) | |
| { | |
| LocalFree(hBuffer); | |
| return FALSE; | |
| } | |
| hBuffer = hNewBuffer; | |
| buffer = LocalLock(hBuffer); | |
| } | |
| _lclose(file); | |
| if (len == (UINT)HFILE_ERROR) | |
| { | |
| LocalFree(hBuffer); | |
| return FALSE; | |
| } | |
| size += len; | |
| buffer[size] = 0; | |
| *phBuffer = hBuffer; | |
| *piSize = size; | |
| return TRUE; | |
| } | |
| /*********************************************************************** | |
| * GRPFILE_ScanGroup | |
| */ | |
| static HLOCAL GRPFILE_ScanGroup(LPCSTR buffer, INT size, | |
| LPCSTR lpszGrpFile, | |
| BOOL bModifiedFileName) | |
| { | |
| HLOCAL hGroup; | |
| INT i, seqnum; | |
| LPCSTR extension; | |
| LPCSTR lpszName; | |
| INT x, y, width, height, iconx, icony, nCmdShow; | |
| INT number_of_programs; | |
| BOOL bOverwriteFileOk; | |
| if (buffer[0] != 'P' || buffer[1] != 'M') return(0); | |
| if (buffer[2] == 'C' && buffer[3] == 'C') | |
| /* original with checksum */ | |
| bOverwriteFileOk = FALSE; | |
| else if (buffer[2] == 'X' && buffer[3] == 'X') | |
| /* modified without checksum */ | |
| bOverwriteFileOk = TRUE; | |
| else return(0); | |
| /* checksum = GET_USHORT(buffer, 4) (ignored) */ | |
| extension = buffer + GET_USHORT(buffer, 6); | |
| if (extension == buffer + size) extension = 0; | |
| else if (extension + 6 > buffer + size) return(0); | |
| nCmdShow = GET_USHORT(buffer, 8); | |
| x = GET_SHORT(buffer, 10); | |
| y = GET_SHORT(buffer, 12); | |
| width = GET_USHORT(buffer, 14); | |
| height = GET_USHORT(buffer, 16); | |
| iconx = GET_SHORT(buffer, 18); | |
| icony = GET_SHORT(buffer, 20); | |
| lpszName = buffer + GET_USHORT(buffer, 22); | |
| if (lpszName >= buffer + size) return(0); | |
| /* unknown bytes 24 - 31 ignored */ | |
| /* | |
| Unknown bytes should be: | |
| wLogPixelsX = GET_SHORT(buffer, 24); | |
| wLogPixelsY = GET_SHORT(buffer, 26); | |
| byBitsPerPixel = byte at 28; | |
| byPlanes = byte at 29; | |
| wReserved = GET_SHORT(buffer, 30); | |
| */ | |
| hGroup = GROUP_AddGroup(lpszName, lpszGrpFile, nCmdShow, x, y, | |
| width, height, iconx, icony, | |
| bModifiedFileName, bOverwriteFileOk, | |
| TRUE); | |
| if (!hGroup) return(0); | |
| number_of_programs = GET_USHORT(buffer, 32); | |
| if (2 * number_of_programs + 34 > size) return(0); | |
| for (i=0, seqnum=0; i < number_of_programs; i++, seqnum++) | |
| { | |
| LPCSTR program_ptr = buffer + GET_USHORT(buffer, 34 + 2*i); | |
| if (program_ptr + 24 > buffer + size) return(0); | |
| if (!GET_USHORT(buffer, 34 + 2*i)) continue; | |
| if (!GRPFILE_ScanProgram(buffer, size, program_ptr, seqnum, | |
| extension, hGroup, lpszGrpFile)) | |
| { | |
| GROUP_DeleteGroup(hGroup); | |
| return(0); | |
| } | |
| } | |
| /* FIXME shouldn't be necessary */ | |
| GROUP_ShowGroupWindow(hGroup); | |
| return hGroup; | |
| } | |
| /*********************************************************************** | |
| * GRPFILE_ScanProgram | |
| */ | |
| static HLOCAL GRPFILE_ScanProgram(LPCSTR buffer, INT size, | |
| LPCSTR program_ptr, INT seqnum, | |
| LPCSTR extension, HLOCAL hGroup, | |
| LPCSTR lpszGrpFile) | |
| { | |
| INT icontype; | |
| HICON hIcon; | |
| LPCSTR lpszName, lpszCmdLine, lpszIconFile, lpszWorkDir; | |
| LPCSTR iconinfo_ptr, iconANDbits_ptr, iconXORbits_ptr; | |
| INT x, y, nIconIndex, iconANDsize, iconXORsize; | |
| INT nHotKey, nCmdShow; | |
| CURSORICONINFO iconinfo; | |
| x = GET_SHORT(program_ptr, 0); | |
| y = GET_SHORT(program_ptr, 2); | |
| nIconIndex = GET_USHORT(program_ptr, 4); | |
| /* FIXME is this correct ?? */ | |
| icontype = GET_USHORT(program_ptr, 6); | |
| switch (icontype) | |
| { | |
| default: | |
| MAIN_MessageBoxIDS_s(IDS_UNKNOWN_FEATURE_s, lpszGrpFile, | |
| IDS_WARNING, MB_OK); | |
| case 0x048c: | |
| iconXORsize = GET_USHORT(program_ptr, 8); | |
| iconANDsize = GET_USHORT(program_ptr, 10) / 8; | |
| iconinfo_ptr = buffer + GET_USHORT(program_ptr, 12); | |
| iconXORbits_ptr = buffer + GET_USHORT(program_ptr, 14); | |
| iconANDbits_ptr = buffer + GET_USHORT(program_ptr, 16); | |
| iconinfo.ptHotSpot.x = GET_USHORT(iconinfo_ptr, 0); | |
| iconinfo.ptHotSpot.y = GET_USHORT(iconinfo_ptr, 2); | |
| iconinfo.nWidth = GET_USHORT(iconinfo_ptr, 4); | |
| iconinfo.nHeight = GET_USHORT(iconinfo_ptr, 6); | |
| iconinfo.nWidthBytes = GET_USHORT(iconinfo_ptr, 8); | |
| iconinfo.bPlanes = GET_USHORT(iconinfo_ptr, 10); | |
| iconinfo.bBitsPerPixel = GET_USHORT(iconinfo_ptr, 11); | |
| break; | |
| case 0x000c: | |
| iconANDsize = GET_USHORT(program_ptr, 8); | |
| iconXORsize = GET_USHORT(program_ptr, 10); | |
| iconinfo_ptr = buffer + GET_USHORT(program_ptr, 12); | |
| iconANDbits_ptr = buffer + GET_USHORT(program_ptr, 14); | |
| iconXORbits_ptr = buffer + GET_USHORT(program_ptr, 16); | |
| iconinfo.ptHotSpot.x = GET_USHORT(iconinfo_ptr, 0); | |
| iconinfo.ptHotSpot.y = GET_USHORT(iconinfo_ptr, 2); | |
| iconinfo.nWidth = GET_USHORT(iconinfo_ptr, 4); | |
| iconinfo.nHeight = GET_USHORT(iconinfo_ptr, 6); | |
| iconinfo.nWidthBytes = GET_USHORT(iconinfo_ptr, 8) * 8; | |
| iconinfo.bPlanes = GET_USHORT(iconinfo_ptr, 10); | |
| iconinfo.bBitsPerPixel = GET_USHORT(iconinfo_ptr, 11); | |
| } | |
| if (iconANDbits_ptr + iconANDsize > buffer + size || | |
| iconXORbits_ptr + iconXORsize > buffer + size) return(0); | |
| hIcon = CreateIcon( Globals.hInstance, iconinfo.nWidth, iconinfo.nHeight, | |
| iconinfo.bPlanes, iconinfo.bBitsPerPixel, | |
| iconANDbits_ptr, iconXORbits_ptr ); | |
| lpszName = buffer + GET_USHORT(program_ptr, 18); | |
| lpszCmdLine = buffer + GET_USHORT(program_ptr, 20); | |
| lpszIconFile = buffer + GET_USHORT(program_ptr, 22); | |
| if (iconinfo_ptr + 6 > buffer + size || | |
| lpszName > buffer + size || | |
| lpszCmdLine > buffer + size || | |
| lpszIconFile > buffer + size) return(0); | |
| /* Scan Extensions */ | |
| lpszWorkDir = ""; | |
| nHotKey = 0; | |
| nCmdShow = SW_SHOWNORMAL; | |
| if (extension) | |
| { | |
| LPCSTR ptr = extension; | |
| while (ptr + 6 <= buffer + size) | |
| { | |
| UINT type = GET_USHORT(ptr, 0); | |
| UINT number = GET_USHORT(ptr, 2); | |
| UINT skip = GET_USHORT(ptr, 4); | |
| if (number == seqnum) | |
| { | |
| switch (type) | |
| { | |
| case 0x8000: | |
| if (ptr + 10 > buffer + size) return(0); | |
| if (ptr[6] != 'P' || ptr[7] != 'M' || | |
| ptr[8] != 'C' || ptr[9] != 'C') return(0); | |
| break; | |
| case 0x8101: | |
| lpszWorkDir = ptr + 6; | |
| break; | |
| case 0x8102: | |
| if (ptr + 8 > buffer + size) return(0); | |
| nHotKey = GET_USHORT(ptr, 6); | |
| break; | |
| case 0x8103: | |
| if (ptr + 8 > buffer + size) return(0); | |
| nCmdShow = GET_USHORT(ptr, 6); | |
| break; | |
| default: | |
| MAIN_MessageBoxIDS_s(IDS_UNKNOWN_FEATURE_s, | |
| lpszGrpFile, IDS_WARNING, MB_OK); | |
| } | |
| } | |
| if (!skip) break; | |
| ptr += skip; | |
| } | |
| } | |
| return (PROGRAM_AddProgram(hGroup, hIcon, lpszName, x, y, | |
| lpszCmdLine, lpszIconFile, | |
| nIconIndex, lpszWorkDir, | |
| nHotKey, nCmdShow)); | |
| } | |
| /*********************************************************************** | |
| * | |
| * GRPFILE_WriteGroupFile | |
| */ | |
| BOOL GRPFILE_WriteGroupFile(HLOCAL hGroup) | |
| { | |
| CHAR szPath[MAX_PATHNAME_LEN]; | |
| PROGGROUP *group = LocalLock(hGroup); | |
| OFSTRUCT dummy; | |
| HFILE file; | |
| BOOL ret; | |
| GRPFILE_ModifyFileName(szPath, LocalLock(group->hGrpFile), | |
| MAX_PATHNAME_LEN, | |
| group->bFileNameModified); | |
| /* Try not to overwrite original files */ | |
| /* group->bOverwriteFileOk == TRUE only if a file has the modified format */ | |
| if (!group->bOverwriteFileOk && | |
| OpenFile(szPath, &dummy, OF_EXIST) != HFILE_ERROR) | |
| { | |
| /* Original file exists, try `.gr' extension */ | |
| GRPFILE_ModifyFileName(szPath, LocalLock(group->hGrpFile), | |
| MAX_PATHNAME_LEN, TRUE); | |
| if (OpenFile(szPath, &dummy, OF_EXIST) != HFILE_ERROR) | |
| { | |
| /* File exists. Do not overwrite */ | |
| MAIN_MessageBoxIDS_s(IDS_FILE_NOT_OVERWRITTEN_s, szPath, | |
| IDS_INFO, MB_OK); | |
| return FALSE; | |
| } | |
| /* Inform about the modified file name */ | |
| if (IDCANCEL == | |
| MAIN_MessageBoxIDS_s(IDS_SAVE_GROUP_AS_s, szPath, IDS_INFO, | |
| MB_OKCANCEL | MB_ICONINFORMATION)) | |
| return FALSE; | |
| } | |
| { | |
| /* Warn about the (possible) incompatibility */ | |
| CHAR msg[MAX_PATHNAME_LEN + 200]; | |
| wsprintf(msg, | |
| "Group files written by this DRAFT Program Manager " | |
| "possibly cannot be read by the Microsoft Program Manager!!\n" | |
| "Are you sure to write %s?", szPath); | |
| if (IDOK != MessageBox(Globals.hMainWnd, msg, "WARNING", | |
| MB_OKCANCEL | MB_DEFBUTTON2)) return FALSE; | |
| } | |
| /* FIXME */ | |
| if (OpenFile(szPath, &dummy, OF_EXIST) == HFILE_ERROR) | |
| { | |
| CHAR msg[MAX_PATHNAME_LEN + 200]; | |
| wsprintf(msg, "Cause of a bug you must now touch the file %s\n", szPath); | |
| MessageBox(Globals.hMainWnd, msg, "", MB_OK); | |
| } | |
| /* Open file */ | |
| file = _lopen(szPath, OF_WRITE); | |
| if (file != HFILE_ERROR) | |
| { | |
| ret = GRPFILE_DoWriteGroupFile(file, group); | |
| _lclose(file); | |
| } | |
| else ret = FALSE; | |
| if (!ret) | |
| MAIN_MessageBoxIDS_s(IDS_FILE_WRITE_ERROR_s, szPath, IDS_ERROR, MB_OK); | |
| return(ret); | |
| } | |
| /*********************************************************************** | |
| * | |
| * GRPFILE_CalculateSizes | |
| */ | |
| static VOID GRPFILE_CalculateSizes(PROGRAM *program, | |
| INT *Progs, INT *Icons) | |
| { | |
| CURSORICONINFO *iconinfo = LocalLock(program->hIcon); | |
| INT sizeXor = iconinfo->nHeight * iconinfo->nWidthBytes; | |
| INT sizeAnd = iconinfo->nHeight * ((iconinfo->nWidth + 15) / 16 * 2); | |
| *Progs += 24; | |
| *Progs += lstrlen(LocalLock(program->hName)) + 1; | |
| *Progs += lstrlen(LocalLock(program->hCmdLine)) + 1; | |
| *Progs += lstrlen(LocalLock(program->hIconFile)) + 1; | |
| *Icons += 12; /* IconInfo */ | |
| *Icons += sizeAnd; | |
| *Icons += sizeXor; | |
| } | |
| /***********************************************************************/ | |
| UINT16 GRPFILE_checksum; | |
| BOOL GRPFILE_checksum_half_word; | |
| BYTE GRPFILE_checksum_last_byte; | |
| /*********************************************************************** | |
| * | |
| * GRPFILE_InitChecksum | |
| */ | |
| static void GRPFILE_InitChecksum() | |
| { | |
| GRPFILE_checksum = 0; | |
| GRPFILE_checksum_half_word = 0; | |
| } | |
| /*********************************************************************** | |
| * | |
| * GRPFILE_GetChecksum | |
| */ | |
| static UINT16 GRPFILE_GetChecksum() | |
| { | |
| return GRPFILE_checksum; | |
| } | |
| /*********************************************************************** | |
| * | |
| * GRPFILE_WriteWithChecksum | |
| * | |
| * Looks crazier than it is: | |
| * | |
| * chksum = 0; | |
| * chksum = cksum - 1. word; | |
| * chksum = cksum - 2. word; | |
| * ... | |
| * | |
| * if (filelen is even) | |
| * great I'm finished | |
| * else | |
| * ignore last byte | |
| */ | |
| static UINT GRPFILE_WriteWithChecksum(HFILE file, LPCSTR str, UINT size) | |
| { | |
| UINT i; | |
| if (GRPFILE_checksum_half_word) { | |
| GRPFILE_checksum -= GRPFILE_checksum_last_byte; | |
| } | |
| for (i=0; i < size; i++) { | |
| if (GRPFILE_checksum_half_word) { | |
| GRPFILE_checksum -= str[i] << 8; | |
| } else { | |
| GRPFILE_checksum -= str[i]; | |
| } | |
| GRPFILE_checksum_half_word ^= 1; | |
| } | |
| if (GRPFILE_checksum_half_word) { | |
| GRPFILE_checksum_last_byte = str[size-1]; | |
| GRPFILE_checksum += GRPFILE_checksum_last_byte; | |
| } | |
| return _lwrite(file, str, size); | |
| } | |
| /*********************************************************************** | |
| * | |
| * GRPFILE_DoWriteGroupFile | |
| */ | |
| static BOOL GRPFILE_DoWriteGroupFile(HFILE file, PROGGROUP *group) | |
| { | |
| BYTE buffer[34]; | |
| HLOCAL hProgram; | |
| INT NumProg, Title, Progs, Icons, Extension; | |
| INT CurrProg, CurrIcon, nCmdShow, ptr, seqnum; | |
| BOOL need_extension; | |
| LPCSTR lpszTitle = LocalLock(group->hName); | |
| UINT16 checksum; | |
| GRPFILE_InitChecksum(); | |
| /* Calculate offsets */ | |
| NumProg = 0; | |
| Icons = 0; | |
| Extension = 0; | |
| need_extension = FALSE; | |
| hProgram = group->hPrograms; | |
| while(hProgram) | |
| { | |
| PROGRAM *program = LocalLock(hProgram); | |
| LPCSTR lpszWorkDir = LocalLock(program->hWorkDir); | |
| NumProg++; | |
| GRPFILE_CalculateSizes(program, &Icons, &Extension); | |
| /* Set a flag if an extension is needed */ | |
| if (lpszWorkDir[0] || program->nHotKey || | |
| program->nCmdShow != SW_SHOWNORMAL) need_extension = TRUE; | |
| hProgram = program->hNext; | |
| } | |
| Title = 34 + NumProg * 2; | |
| Progs = Title + lstrlen(lpszTitle) + 1; | |
| Icons += Progs; | |
| Extension += Icons; | |
| /* Header */ | |
| buffer[0] = 'P'; | |
| buffer[1] = 'M'; | |
| buffer[2] = 'C'; | |
| buffer[3] = 'C'; | |
| PUT_SHORT(buffer, 4, 0); /* Checksum zero for now, written later */ | |
| PUT_SHORT(buffer, 6, Extension); | |
| /* Update group->nCmdShow */ | |
| if (IsIconic(group->hWnd)) nCmdShow = SW_SHOWMINIMIZED; | |
| else if (IsZoomed(group->hWnd)) nCmdShow = SW_SHOWMAXIMIZED; | |
| else nCmdShow = SW_SHOWNORMAL; | |
| PUT_SHORT(buffer, 8, nCmdShow); | |
| PUT_SHORT(buffer, 10, group->x); | |
| PUT_SHORT(buffer, 12, group->y); | |
| PUT_SHORT(buffer, 14, group->width); | |
| PUT_SHORT(buffer, 16, group->height); | |
| PUT_SHORT(buffer, 18, group->iconx); | |
| PUT_SHORT(buffer, 20, group->icony); | |
| PUT_SHORT(buffer, 22, Title); | |
| PUT_SHORT(buffer, 24, 0x0020); /* unknown */ | |
| PUT_SHORT(buffer, 26, 0x0020); /* unknown */ | |
| PUT_SHORT(buffer, 28, 0x0108); /* unknown */ | |
| PUT_SHORT(buffer, 30, 0x0000); /* unknown */ | |
| PUT_SHORT(buffer, 32, NumProg); | |
| if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 34)) return FALSE; | |
| /* Program table */ | |
| CurrProg = Progs; | |
| CurrIcon = Icons; | |
| hProgram = group->hPrograms; | |
| while(hProgram) | |
| { | |
| PROGRAM *program = LocalLock(hProgram); | |
| PUT_SHORT(buffer, 0, CurrProg); | |
| if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 2)) | |
| return FALSE; | |
| GRPFILE_CalculateSizes(program, &CurrProg, &CurrIcon); | |
| hProgram = program->hNext; | |
| } | |
| /* Title */ | |
| if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, lpszTitle, | |
| lstrlen(lpszTitle) + 1)) | |
| return FALSE; | |
| /* Program entries */ | |
| CurrProg = Progs; | |
| CurrIcon = Icons; | |
| hProgram = group->hPrograms; | |
| while(hProgram) | |
| { | |
| PROGRAM *program = LocalLock(hProgram); | |
| CURSORICONINFO *iconinfo = LocalLock(program->hIcon); | |
| LPCSTR Name = LocalLock(program->hName); | |
| LPCSTR CmdLine = LocalLock(program->hCmdLine); | |
| LPCSTR IconFile = LocalLock(program->hIconFile); | |
| INT sizeXor = iconinfo->nHeight * iconinfo->nWidthBytes; | |
| INT sizeAnd = iconinfo->nHeight * ((iconinfo->nWidth + 15) / 16 * 2); | |
| PUT_SHORT(buffer, 0, program->x); | |
| PUT_SHORT(buffer, 2, program->y); | |
| PUT_SHORT(buffer, 4, program->nIconIndex); | |
| PUT_SHORT(buffer, 6, 0x048c); /* unknown */ | |
| PUT_SHORT(buffer, 8, sizeXor); | |
| PUT_SHORT(buffer, 10, sizeAnd * 8); | |
| PUT_SHORT(buffer, 12, CurrIcon); | |
| PUT_SHORT(buffer, 14, CurrIcon + 12 + sizeAnd); | |
| PUT_SHORT(buffer, 16, CurrIcon + 12); | |
| ptr = CurrProg + 24; | |
| PUT_SHORT(buffer, 18, ptr); | |
| ptr += lstrlen(Name) + 1; | |
| PUT_SHORT(buffer, 20, ptr); | |
| ptr += lstrlen(CmdLine) + 1; | |
| PUT_SHORT(buffer, 22, ptr); | |
| if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 24) || | |
| (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, Name, lstrlen(Name) + 1) || | |
| (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, CmdLine, lstrlen(CmdLine) + 1) || | |
| (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, IconFile, lstrlen(IconFile) + 1)) | |
| return FALSE; | |
| GRPFILE_CalculateSizes(program, &CurrProg, &CurrIcon); | |
| hProgram = program->hNext; | |
| } | |
| /* Icons */ | |
| #if 0 /* FIXME: this is broken anyway */ | |
| hProgram = group->hPrograms; | |
| while(hProgram) | |
| { | |
| PROGRAM *program = LocalLock(hProgram); | |
| CURSORICONINFO *iconinfo = LocalLock(program->hIcon); | |
| LPVOID XorBits, AndBits; | |
| INT sizeXor = iconinfo->nHeight * iconinfo->nWidthBytes; | |
| INT sizeAnd = iconinfo->nHeight * ((iconinfo->nWidth + 15) / 16 * 2); | |
| /* DumpIcon16(LocalLock(program->hIcon), 0, &XorBits, &AndBits);*/ | |
| PUT_SHORT(buffer, 0, iconinfo->ptHotSpot.x); | |
| PUT_SHORT(buffer, 2, iconinfo->ptHotSpot.y); | |
| PUT_SHORT(buffer, 4, iconinfo->nWidth); | |
| PUT_SHORT(buffer, 6, iconinfo->nHeight); | |
| PUT_SHORT(buffer, 8, iconinfo->nWidthBytes); | |
| buffer[10] = iconinfo->bPlanes; | |
| buffer[11] = iconinfo->bBitsPerPixel; | |
| if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 12) || | |
| (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, AndBits, sizeAnd) || | |
| (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, XorBits, sizeXor)) return FALSE; | |
| hProgram = program->hNext; | |
| } | |
| #endif | |
| if (need_extension) | |
| { | |
| /* write `PMCC' extension */ | |
| PUT_SHORT(buffer, 0, 0x8000); | |
| PUT_SHORT(buffer, 2, 0xffff); | |
| PUT_SHORT(buffer, 4, 0x000a); | |
| buffer[6] = 'P', buffer[7] = 'M'; | |
| buffer[8] = 'C', buffer[9] = 'C'; | |
| if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 10)) | |
| return FALSE; | |
| seqnum = 0; | |
| hProgram = group->hPrograms; | |
| while(hProgram) | |
| { | |
| PROGRAM *program = LocalLock(hProgram); | |
| LPCSTR lpszWorkDir = LocalLock(program->hWorkDir); | |
| /* Working directory */ | |
| if (lpszWorkDir[0]) | |
| { | |
| PUT_SHORT(buffer, 0, 0x8101); | |
| PUT_SHORT(buffer, 2, seqnum); | |
| PUT_SHORT(buffer, 4, 7 + lstrlen(lpszWorkDir)); | |
| if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 6) || | |
| (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, lpszWorkDir, lstrlen(lpszWorkDir) + 1)) | |
| return FALSE; | |
| } | |
| /* Hot key */ | |
| if (program->nHotKey) | |
| { | |
| PUT_SHORT(buffer, 0, 0x8102); | |
| PUT_SHORT(buffer, 2, seqnum); | |
| PUT_SHORT(buffer, 4, 8); | |
| PUT_SHORT(buffer, 6, program->nHotKey); | |
| if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 8)) return FALSE; | |
| } | |
| /* Show command */ | |
| if (program->nCmdShow) | |
| { | |
| PUT_SHORT(buffer, 0, 0x8103); | |
| PUT_SHORT(buffer, 2, seqnum); | |
| PUT_SHORT(buffer, 4, 8); | |
| PUT_SHORT(buffer, 6, program->nCmdShow); | |
| if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 8)) return FALSE; | |
| } | |
| seqnum++; | |
| hProgram = program->hNext; | |
| } | |
| /* Write `End' extension */ | |
| PUT_SHORT(buffer, 0, 0xffff); | |
| PUT_SHORT(buffer, 2, 0xffff); | |
| PUT_SHORT(buffer, 4, 0x0000); | |
| if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 6)) return FALSE; | |
| } | |
| checksum = GRPFILE_GetChecksum(); | |
| _llseek(file, 4, SEEK_SET); | |
| PUT_SHORT(buffer, 0, checksum); | |
| _lwrite(file, buffer, 2); | |
| return TRUE; | |
| } | |
| /* Local Variables: */ | |
| /* c-file-style: "GNU" */ | |
| /* End: */ |