|
|
/****************************************************************************/ /* */ /* PMGSEG.C - */ /* */ /* Program Manager Group Handling Routines */ /* */ /****************************************************************************/
#include "progman.h"
#include "dde.h"
#include "convgrp.h"
#define WORD_MIN -32767
#define WORD_MAX 32767
#ifndef ORGCODE
#include "fcntl.h"
#include "io.h"
#include "stdio.h"
#include <tchar.h>
#define S_IREAD 0000400 /* read permission, owner */
#define S_IWRITE 0000200 /* write permission, owner */
#endif
BOOL fFirstLoad = FALSE; extern BOOL bHandleProgramGroupsEvent;
#if 0
// DOS apps are no longer set to fullscreen by default in progman
// 5-3-93 johannec (bug 8343)
#ifdef i386
BOOL IsDOSApplication(LPTSTR lpPath); BOOL SetDOSApplicationToFullScreen(LPTSTR lpTitle); #endif
#endif
void NEAR PASCAL RemoveItemFromList(PGROUP pGroup, PITEM pItem) // Removes a PITEM from the list.
{ PITEM *ppItem;
/* Cause it to be repainted later. */ InvalidateIcon(pGroup, pItem);
if (pItem == pGroup->pItems) { /*
* first one in list, must invalidate next one so it paints an active * title bar. */ InvalidateIcon(pGroup,pItem->pNext); }
/* Remove it from the list. */ for (ppItem = &pGroup->pItems;*ppItem != pItem; ppItem = &((*ppItem)->pNext));
*ppItem = pItem->pNext;
/* Lastly free up the memory. */ LocalFree((HANDLE)pItem); }
#ifdef DEBUG
void NEAR PASCAL CheckBeforeReAlloc(HANDLE h) { TCHAR buf[100];
if ((BYTE)GlobalFlags(h)) { wsprintf(buf, TEXT("LockCount before realloc %d\r\n"), (BYTE)GlobalFlags(h)); OutputDebugString(buf); DbgBreakPoint(); } } #else
#define CheckBeforeReAlloc(h)
#endif
#ifdef PARANOID
/*--------------------------------------------------------------------------*/ /* */ /* CheckRange() - */ /* */ /*--------------------------------------------------------------------------*/
void PASCAL CheckRange( LPGROUPDEF lpgd, LPTSTR lp1, WORD *lpw1, WORD cb1, LPTSTR lp2, WORD w2, WORD cb2, LPTSTR lpThing) { WORD w1 = *lpw1; WORD e1, e2;
if (!w1 || (w1 == w2)) { return; }
if (!cb1) { cb1 = (WORD)lstrlen((LPTSTR) PTR(lpgd, *lpw1)); }
e1 = w1 + cb1; e2 = w2 + cb2;
if ((w1 < e2) && (w2 < e1)) { KdPrint(("ERROR: %s overlaps %s in %s!!!!\r\n",lp2,lp1,lpThing)); } }
/*--------------------------------------------------------------------------*/ /* */ /* CheckPointer() - */ /* */ /*--------------------------------------------------------------------------*/
void PASCAL CheckPointer( LPGROUPDEF lpgd, LPTSTR lp, WORD *lpw, WORD cb, WORD limit) { LPITEMDEF lpid; int i;
if (lpw == NULL || !*lpw) { KdPrint(("Warning: %s is NULL\r\n", lp)); DebugBreak(); }
if (!cb) { cb = lstrlen((LPTSTR) PTR(lpgd, *lpw)); }
if (*lpw + cb > limit) { KdPrint(("ERROR: %s runs off end of group\r\n", lp)); return; }
}
/*--------------------------------------------------------------------------*/ /* */ /* VerifyGroup() - */ /* */ /*--------------------------------------------------------------------------*/
void PASCAL VerifyGroup( LPGROUPDEF lpgd) { int i; LPITEMDEF lpid; DWORD limit = lpgd->cbGroup;
KdPrint(("\r\nChecking Group %s\r\n",(LPTSTR) PTR(lpgd, lpgd->pName))); CheckPointer(lpgd, TEXT("Group Name"), &lpgd->pName, 0, limit);
for (i = 0; i < (int)lpgd->cItems; i++) { if (!lpgd->rgiItems[i]) { continue; }
lpid = ITEM(lpgd, i); KdPrint(("Checking item %d at %4.4X (%s):\r\n", i, lpgd->rgiItems[i], (LPTSTR) PTR(lpgd, lpid->pName))); CheckPointer(lpgd, TEXT("Itemdef"), lpgd->rgiItems + i, sizeof(ITEMDEF), limit); CheckPointer(lpgd, TEXT("Item name"), &lpid->pName, 0, limit); CheckPointer(lpgd, TEXT("item command"), &lpid->pCommand, 0, limit); CheckPointer(lpgd, TEXT("item icon path"), &lpid->pIconPath, 0, limit); } } #endif
/*--------------------------------------------------------------------------*/ /* */ /* IsGroupReadOnly() - */ /* */ /*--------------------------------------------------------------------------*/
BOOL FAR PASCAL IsGroupReadOnly(LPTSTR szGroupKey, BOOL bCommonGroup) { HKEY hkey; HKEY hkeyGroups;
if (bCommonGroup) hkeyGroups = hkeyCommonGroups; else if (bUseANSIGroups) hkeyGroups = hkeyAnsiProgramGroups; else hkeyGroups = hkeyProgramGroups;
if (!hkeyGroups) return(FALSE);
if (!RegOpenKeyEx(hkeyGroups, szGroupKey, 0, DELETE | KEY_READ | KEY_WRITE, &hkey)){ RegCloseKey(hkey); return(FALSE); } return(TRUE); }
/*--------------------------------------------------------------------------*/ /* */ /* GroupCheck() - */ /* */ /*--------------------------------------------------------------------------*/
BOOL FAR PASCAL GroupCheck(PGROUP pGroup) { if (!fExiting && IsGroupReadOnly(pGroup->lpKey, pGroup->fCommon)) { pGroup->fRO = TRUE; return FALSE; } pGroup->fRO = FALSE; return TRUE; }
/*--------------------------------------------------------------------------*/ /* */ /* MyDwordAlign() - */ /* */ /*--------------------------------------------------------------------------*/
INT MyDwordAlign(INT wStrLen) { return ((wStrLen + 3) & ~3); }
/*--------------------------------------------------------------------------*/ /* */ /* SizeofGroup() - */ /* */ /*--------------------------------------------------------------------------*/ DWORD PASCAL SizeofGroup(LPGROUPDEF lpgd) { LPPMTAG lptag; DWORD cbSeg; DWORD cb;
cbSeg = (DWORD)GlobalSize(lpgd);
lptag = (LPPMTAG)((LPSTR)lpgd+lpgd->cbGroup);
if ((DWORD)((PCHAR)lptag - (PCHAR)lpgd +MyDwordAlign(sizeof(PMTAG))-MyDwordAlign(sizeof(lptag->rgb))+4) <= cbSeg && lptag->wID == ID_MAGIC && lptag->wItem == (int)0xFFFF && lptag->cb == (WORD)(MyDwordAlign(sizeof(PMTAG))-MyDwordAlign(sizeof(lptag->rgb)) + 4) && *(PLONG)lptag->rgb == PMTAG_MAGIC) { while ((cb = (DWORD)((PCHAR)lptag - (PCHAR)lpgd + MyDwordAlign(sizeof(PMTAG))-MyDwordAlign(sizeof(lptag->rgb)))) <= cbSeg) { if (lptag->wID == ID_LASTTAG) return cb; (LPSTR)lptag += lptag->cb; } } return lpgd->cbGroup; }
/*--------------------------------------------------------------------------*/ /* */ /* LockGroup() - */ /* */ /*--------------------------------------------------------------------------*/
/* Given the handle to the group's window, lock the group segment and return
* a pointer thereto. Reloads the group segment if it is not in memory. */
LPGROUPDEF FAR PASCAL LockGroup(HWND hwndGroup)
{ PGROUP pGroup; LPGROUPDEF lpgd; WORD status; LPTSTR lpszKey; HKEY hKey = NULL; LONG err; DWORD cbMaxValueLen = 0; FILETIME ft; TCHAR szClass[64]; DWORD dummy = 64; DWORD cbSecDesc; HKEY hkeyGroups; BOOL bCommonGroup;
wLockError = 0; // No errors.
/* Find the handle and try to lock it. */ pGroup = (PGROUP)GetWindowLongPtr(hwndGroup, GWLP_PGROUP); lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
/* If we got a non-NULL selector, return the pointer. */ if (pGroup->fLoaded) return(lpgd);
if (lpgd) { GlobalUnlock(pGroup->hGroup); }
NukeIconBitmap(pGroup); // invalidate the bitmap
/* The group has been discarded, must reread the file... */ lpszKey = pGroup->lpKey;
pGroup->fRO = FALSE;
bCommonGroup = pGroup->fCommon; if (bCommonGroup) hkeyGroups = hkeyCommonGroups; else if (bUseANSIGroups) hkeyGroups = hkeyAnsiProgramGroups; else hkeyGroups = hkeyProgramGroups;
if (!hkeyGroups) goto RegError;
/* Try to open the group key. */ if (err = RegOpenKeyEx(hkeyGroups, lpszKey, 0, DELETE | KEY_READ | KEY_WRITE, &hKey)) { /* Try read-only access */ if (err = RegOpenKeyEx(hkeyGroups, lpszKey, 0, KEY_READ, &hKey) || !hKey) { status = IDS_NOGRPFILE; goto LGError1; } if (!bUseANSIGroups) { pGroup->fRO = TRUE; } }
if (!(err = RegQueryInfoKey(hKey, szClass, &dummy, // cbClass
NULL, // Title index
&dummy, // cbSubKeys
&dummy, // cb Max subkey length
&dummy, // max class len
&dummy, // values count
&dummy, // max value name length
&cbMaxValueLen, &cbSecDesc, // cb Security Descriptor
&ft))) { if (!pGroup->ftLastWriteTime.dwLowDateTime && !pGroup->ftLastWriteTime.dwHighDateTime) pGroup->ftLastWriteTime = ft; else if (pGroup->ftLastWriteTime.dwLowDateTime != ft.dwLowDateTime || pGroup->ftLastWriteTime.dwHighDateTime != ft.dwHighDateTime ) { wLockError = LOCK_FILECHANGED; status = IDS_GRPHASCHANGED; if (!fExiting) // Don't reload changed groups on exit.
PostMessage(hwndProgman,WM_RELOADGROUP,(WPARAM)pGroup,0L); goto LGError2; } }
/* Find the size of the file by seeking to the end. */ if (cbMaxValueLen < sizeof(GROUPDEF)) { status = IDS_BADFILE; goto LGError2; }
/* Allocate some memory for the thing. */ CheckBeforeReAlloc(pGroup->hGroup); if (!GlobalReAlloc(pGroup->hGroup, (DWORD)cbMaxValueLen, GMEM_MOVEABLE)) { wLockError = LOCK_LOWMEM; status = IDS_LOWMEM; lpszKey = NULL; goto LGError2; }
pGroup->fLoaded = TRUE; lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
/* Read the whole group data into memory. */ status = IDS_BADFILE; if (err = RegQueryValueEx(hKey, NULL, 0, 0, (LPBYTE)lpgd, &cbMaxValueLen)) { goto LGError3; } //
// If we start out from the ANSI groups, we need the security description
// to copy the entire information to the UNICODE groups
//
if (bUseANSIGroups) { pGroup->pSecDesc = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, cbSecDesc); RegGetKeySecurity(hKey, DACL_SECURITY_INFORMATION, pGroup->pSecDesc, &cbSecDesc); } else { pGroup->pSecDesc = NULL; }
//
// If we loaded an old format ANSI group, then convert it to the
// UNICODE format and save it back in the registry.
//
if (lpgd->dwMagic == GROUP_MAGIC) { HANDLE hUNIGroup;
if (cbMaxValueLen = ConvertToUnicodeGroup((LPGROUPDEF_A)lpgd, &hUNIGroup)) { UnlockGroup(hwndGroup); /* Free the ANSI group. */ GlobalFree(pGroup->hGroup); pGroup->hGroup = hUNIGroup; lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup); } else { goto LGError3; } }
if (lpgd->dwMagic != GROUP_UNICODE) goto LGError3;
if (lpgd->cbGroup > cbMaxValueLen) goto LGError3;
/* Now return the pointer. */ RegCloseKey(hKey);
return(lpgd);
LGError3: GlobalUnlock(pGroup->hGroup); GlobalDiscard(pGroup->hGroup); pGroup->fLoaded = FALSE;
LGError2: RegCloseKey(hKey);
LGError1: if (status != IDS_LOWMEM && status != IDS_GRPHASCHANGED && status != IDS_NOGRPFILE) { MyMessageBox(hwndProgman, IDS_GROUPFILEERR, status, pGroup->lpKey, MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL); if (status == IDS_BADFILE) { //
// stop handling of Program Groups key changes.
//
bHandleProgramGroupsEvent = FALSE;
RegDeleteKey(hkeyGroups, lpszKey);
//
// reset handling of Program Groups key changes.
//
ResetProgramGroupsEvent(bCommonGroup); bHandleProgramGroupsEvent = TRUE; } return(NULL); }
/*
* Special case the group not being found so we can delete it's entry... */ if (status == IDS_NOGRPFILE) { /*
* If no restrictions then we can fixup progman.ini... */ if (!fNoSave && dwEditLevel < 1) { TCHAR szGroup[10];
if (MyMessageBox(hwndProgman,IDS_GROUPFILEERR,IDS_NOGRPFILE2,lpszKey, MB_YESNO | MB_ICONEXCLAMATION | MB_DEFBUTTON1 | MB_SYSTEMMODAL) == IDNO) { wsprintf(szGroup,TEXT("Group%d"),pGroup->wIndex); //
// stop handling of Program Groups key changes.
//
bHandleProgramGroupsEvent = FALSE; RegDeleteKey(hkeyProgramGroups, lpszKey);
//
// reset handling of Program Groups key changes.
//
ResetProgramGroupsEvent(bCommonGroup); bHandleProgramGroupsEvent = TRUE; RegDeleteValue(hkeyPMGroups, szGroup);
if (!fFirstLoad) PostMessage(hwndProgman,WM_UNLOADGROUP,(WPARAM)hwndGroup,0L); } } else { RegError: /*
* Restrictions mean that the user can only OK this error... */ MyMessageBox(hwndProgman, IDS_GROUPFILEERR, IDS_NOGRPFILE, lpszKey, MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL); } }
ShowWindow(hwndGroup, SW_SHOWMINNOACTIVE);
return(NULL); }
/*--------------------------------------------------------------------------*/ /* */ /* UnlockGroup() - */ /* */ /*--------------------------------------------------------------------------*/
void FAR PASCAL UnlockGroup(register HWND hwndGroup)
{ GlobalUnlock(((PGROUP)GetWindowLongPtr(hwndGroup,GWLP_PGROUP))->hGroup); }
/*--------------------------------------------------------------------------*/ /* */ /* LockItem() - */ /* */ /*--------------------------------------------------------------------------*/
LPITEMDEF FAR PASCAL LockItem(PGROUP pGroup, PITEM pItem) { LPGROUPDEF lpgd;
lpgd = LockGroup(pGroup->hwnd);
if (!lpgd) return((LPITEMDEF)NULL);
return ITEM(lpgd,pItem->iItem); }
/*--------------------------------------------------------------------------*/ /* */ /* KeepGroupAround() - */ /* */ /*--------------------------------------------------------------------------*/
/*
* Sets or unsets the discardable flag for the given group file. If setting * to non-discard, forces the group to be in memory. */
HANDLE PASCAL KeepGroupAround(HWND hwndGroup, BOOL fKeep) { PGROUP pGroup;
UNREFERENCED_PARAMETER(fKeep); pGroup = (PGROUP)GetWindowLongPtr(hwndGroup, GWLP_PGROUP); return pGroup->hGroup;
#ifdef ORGCODE
PGROUP pGroup; WORD flag;
pGroup = (PGROUP)GetWindowLongPtr(hwndGroup, GWLP_PGROUP);
if (fKeep) { if (LockGroup(hwndGroup)) { UnlockGroup(hwndGroup); // it is still in memory
} else { return NULL; // failure
}
flag = GMEM_MODIFY | GMEM_MOVEABLE; // make non discardable
} else { flag = GMEM_MODIFY | GMEM_MOVEABLE | GMEM_DISCARDABLE; // discardable
}
return GlobalReAlloc(pGroup->hGroup, 0, flag); #endif
}
/*--------------------------------------------------------------------------*/ /* */ /* SaveGroup() - */ /* */ /*--------------------------------------------------------------------------*/
/*
* Writes out a group file. It must already be in memory or the operation * is meaningless. */ BOOL APIENTRY SaveGroup( HWND hwndGroup, BOOL bDiscard ) { LPGROUPDEF lpgd; HKEY hKey; PGROUP pGroup; WORD status = 0; DWORD cb; LONG err; HKEY hkeyGroups; BOOL bCommonGroup; DWORD dwDisposition;
pGroup = (PGROUP)GetWindowLongPtr(hwndGroup, GWLP_PGROUP);
bCommonGroup = pGroup->fCommon;
if (!bUseANSIGroups && IsGroupReadOnly(pGroup->lpKey, bCommonGroup)) { // Don't produce an error message for RO groups.
return FALSE; }
lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup); if (!lpgd) { return FALSE; }
if (bCommonGroup) hkeyGroups = hkeyCommonGroups; else hkeyGroups = hkeyProgramGroups;
if (!hkeyGroups) { goto Exit1; }
// it may already exist
if (err = RegCreateKeyEx(hkeyGroups, pGroup->lpKey, 0, 0, 0, DELETE | KEY_READ | KEY_WRITE | WRITE_DAC, pSecurityAttributes, &hKey, &dwDisposition)) { //if (err = RegOpenKeyEx(hkeyGroups, pGroup->lpKey, 0,
// KEY_SET_VALUE, &hKey)) {
/*
* We can't open output group key. */ if (err = RegOpenKeyEx(hkeyGroups, pGroup->lpKey, 0, KEY_READ, &hKey)) { status = IDS_NOGRPFILE; } else { // status = IDS_GRPISRO;
RegCloseKey(hKey); } goto Exit1; } else { if (dwDisposition == REG_CREATED_NEW_KEY && bUseANSIGroups) { RegSetKeySecurity(hKey, DACL_SECURITY_INFORMATION, pGroup->pSecDesc); LocalFree(pGroup->pSecDesc); pGroup->pSecDesc = NULL; }
}
//
// stop handling Program Groups key changes for a SAveGroup.
//
bHandleProgramGroupsEvent = FALSE;
cb = SizeofGroup(lpgd); if (err = RegSetValueEx(hKey, NULL, 0, REG_BINARY, (LPBYTE)lpgd, cb)) { status = IDS_CANTWRITEGRP; }
RegFlushKey(hKey); RegCloseKey(hKey);
pGroup->ftLastWriteTime.dwLowDateTime = 0; // update file time stamp if we need to reload
pGroup->ftLastWriteTime.dwHighDateTime = 0;
Exit1: GlobalUnlock(pGroup->hGroup);
if (status && !fExiting) { MyMessageBox(hwndProgman, IDS_GROUPFILEERR, status, pGroup->lpKey, MB_OK | MB_ICONEXCLAMATION);
/*
* Force the group to be reset. */ if (bDiscard) { GlobalDiscard(pGroup->hGroup); pGroup->fLoaded = FALSE; InvalidateRect(pGroup->hwnd, NULL, TRUE); } }
//
// reset handling of Program Groups key changes.
//
ResetProgramGroupsEvent(bCommonGroup); bHandleProgramGroupsEvent = TRUE; return (status == 0); }
/*--------------------------------------------------------------------------*/ /* */ /* AdjustPointers() - */ /* */ /*--------------------------------------------------------------------------*/
/*
* Adjusts pointers in the segment after a section is moved up or down. */ void PASCAL AdjustPointers(LPGROUPDEF lpgd, DWORD iFirst, DWORD di) { WORD i; LPITEMDEF lpid;
if (lpgd->pName >= iFirst) { lpgd->pName += di; }
for (i = 0; i < lpgd->cItems; i++) { if (!lpgd->rgiItems[i]) { continue; }
if (lpgd->rgiItems[i] >= iFirst) { lpgd->rgiItems[i] += di; }
lpid = ITEM(lpgd, i);
if (lpid->pIconRes >= iFirst) lpid->pIconRes += di; if (lpid->pName >= iFirst) lpid->pName += di; if (lpid->pCommand >= iFirst) lpid->pCommand += di; if (lpid->pIconPath >= iFirst) lpid->pIconPath += di; } }
/*--------------------------------------------------------------------------*/ /* */ /* FindFreeItemIndex() - */ /* */ /* Returns the index of a free slot in the item offset array. If necessary,*/ /* moves stuff around. */ /* */ /*--------------------------------------------------------------------------*/
WORD PASCAL FindFreeItemIndex(HWND hwndGroup) { LPGROUPDEF lpgd; PGROUP pGroup; WORD i; LPTSTR lp1; LPTSTR lp2; DWORD cb;
lpgd = LockGroup(hwndGroup); if (!lpgd) { return(0xFFFF); }
for (i = 0; i < lpgd->cItems; i++) { if (!lpgd->rgiItems[i]) { UnlockGroup(hwndGroup); return(i); } }
/*
* Didn't find an empty slot... make some new ones. */ pGroup = (PGROUP)GetWindowLongPtr(hwndGroup, GWLP_PGROUP);
// Current groups+tags size.
cb = SizeofGroup(lpgd);
// Increase space reserved item info.
lpgd->cbGroup += NSLOTS*sizeof(DWORD);
// Increase size of whole group.
cb += NSLOTS*sizeof(DWORD);
UnlockGroup(hwndGroup);
CheckBeforeReAlloc(pGroup->hGroup); if (!GlobalReAlloc(pGroup->hGroup, cb, GMEM_MOVEABLE)) { return 0xFFFF; }
lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
/*
* Copy tags junk (which starts at the end of the rgiItems array) * up a bit to make room for the bigger array.. */ lp1 = (LPTSTR)&(lpgd->rgiItems[lpgd->cItems]); lp2 = (LPTSTR)&(lpgd->rgiItems[lpgd->cItems + NSLOTS]);
/*
* Copy everything down in the segment. */ RtlMoveMemory(lp2, lp1, (WORD)(cb - (DWORD)((LPSTR)lp2 - (LPSTR)lpgd)));
/*
* Zero out the new offsets. */ for (i = (WORD)lpgd->cItems; i < (WORD)(lpgd->cItems + NSLOTS); i++) { lpgd->rgiItems[i] = 0; }
i = lpgd->cItems;
/* Record that we now have more slots */ lpgd->cItems += NSLOTS;
/*
* Fix up all the offsets in the segment. Since the rgiItems array is * part of the group header, all the pointers will change. */ AdjustPointers(lpgd, (WORD)1, NSLOTS * sizeof(DWORD));
GlobalUnlock(pGroup->hGroup);
return i; }
/*--------------------------------------------------------------------------*/ /* */ /* DeleteThing() - */ /* */ /* */ /* Removes a part of the group segment. Updates everything in the segment */ /* but does not realloc. */ /* */ /*--------------------------------------------------------------------------*/
void NEAR PASCAL DeleteThing(LPGROUPDEF lpgd, LPDWORD lpiThing, WORD cbThing) { DWORD dwThingOffset; LPTSTR lp1; LPTSTR lp2; INT cb; WORD cbThingSize;
if (cbThing == 0xFFFF) { return; }
dwThingOffset = *lpiThing;
if (!dwThingOffset) return;
*lpiThing = 0;
lp1 = (LPTSTR) PTR(lpgd, dwThingOffset);
/* If its a string we're removing, the caller can pass 0 as the length
* and have it calculated!!! */ if (!cbThing) { cbThing = (WORD)sizeof(TCHAR)*(1 + lstrlen(lp1)); }
cbThingSize = (WORD)MyDwordAlign((int)cbThing);
lp2 = (LPTSTR)((LPBYTE)lp1 + cbThingSize);
cb = (int)SizeofGroup(lpgd);
RtlMoveMemory(lp1, lp2, (cb - (DWORD)((LPSTR)lp2 - (LPSTR)lpgd)));
lpgd->cbGroup -= cbThingSize;
AdjustPointers(lpgd, dwThingOffset, -cbThingSize);
}
/*--------------------------------------------------------------------------*/ /* */ /* AddThing() - */ /* */ /* in: */ /* hGroup group handle, must not be discardable */ /* lpStuff pointer to data or NULL to init data to zero */ /* cbStuff count of item (may be 0) if lpStuff is a string */ /* */ /* Adds an object to the group segment and returns its offset. Will */ /* reallocate the segment if necessary. */ /* */ /* Handle passed in must not be discardable */ /* */ /* returns: */ /* 0 failure */ /* > 0 offset to thing in the segment */ /* */ /*--------------------------------------------------------------------------*/
DWORD PASCAL AddThing(HANDLE hGroup, LPTSTR lpStuff, DWORD cbStuff) { DWORD cb; LPGROUPDEF lpgd; DWORD offset; LPTSTR lpT; DWORD cbStuffSize; DWORD cbGroupSize; DWORD myOffset;
if (cbStuff == 0xFFFFFFFF) { return 0xFFFFFFFF; }
if (!cbStuff) { cbStuff = sizeof(TCHAR)*(DWORD)(1 + lstrlen(lpStuff)); }
cbStuffSize = MyDwordAlign((int)cbStuff);
lpgd = (LPGROUPDEF)GlobalLock(hGroup); cb = SizeofGroup(lpgd); cbGroupSize = MyDwordAlign((int)cb);
offset = lpgd->cbGroup; myOffset = (DWORD)MyDwordAlign((int)offset);
GlobalUnlock(hGroup);
CheckBeforeReAlloc(hGroup); if (!GlobalReAlloc(hGroup,(DWORD)(cbGroupSize + cbStuffSize), GMEM_MOVEABLE)) return 0;
lpgd = (LPGROUPDEF)GlobalLock(hGroup);
/*
* Slide the tags up */ RtlMoveMemory((LPSTR)lpgd + myOffset + cbStuffSize, (LPSTR)lpgd + myOffset, (cbGroupSize - myOffset)); lpgd->cbGroup += cbStuffSize;
lpT = (LPTSTR)((LPSTR)lpgd + myOffset); if (lpStuff) { RtlMoveMemory(lpT, lpStuff, cbStuff);
} else { /*
* Zero it */ while (cbStuffSize--) { *((LPSTR)lpT)++ = 0; } }
GlobalUnlock(hGroup);
return myOffset; }
/*--------------------------------------------------------------------------*/ /* */ /* FindTag() - */ /* */ /*--------------------------------------------------------------------------*/
LPPMTAG NEAR PASCAL FindTag(LPGROUPDEF lpgd, int item, WORD id) { LPPMTAG lptag; int cbSeg; int cb;
cbSeg = (DWORD)GlobalSize(lpgd);
lptag = (LPPMTAG)((LPSTR)lpgd+lpgd->cbGroup);
if ((PCHAR)lptag - (PCHAR)lpgd + MyDwordAlign(sizeof(PMTAG))-MyDwordAlign(sizeof(lptag->rgb)) + 4 <= cbSeg && lptag->wID == ID_MAGIC && lptag->wItem == (int)0xFFFF && lptag->cb == (WORD)(MyDwordAlign(sizeof(PMTAG))-MyDwordAlign(sizeof(lptag->rgb)) +4) && *(LONG FAR *)lptag->rgb == PMTAG_MAGIC) {
while ((cb = (int)((PCHAR)lptag - (PCHAR)lpgd + MyDwordAlign(sizeof(PMTAG))-MyDwordAlign(sizeof(lptag->rgb)))) <= cbSeg) { if ((item == lptag->wItem) && (id == 0 || id == lptag->wID)) { return lptag; }
if (lptag->wID == ID_LASTTAG) return NULL;
(LPSTR)lptag += lptag->cb; } } return NULL; }
/*--------------------------------------------------------------------------*/ /* */ /* CopyTag() - */ /* */ /*--------------------------------------------------------------------------*/
INT FAR PASCAL CopyTag(LPGROUPDEF lpgd, int item, WORD id, LPTSTR lpbuf, int cb) { LPTSTR lpt; LPPMTAG lptag; WORD cbT;
lptag = FindTag(lpgd,item,id);
if (lptag == NULL) return 0;
if (cb > (int)lptag->cb) cb = lptag->cb;
cbT = (WORD)cb;
lpt = (LPTSTR) lptag->rgb;
while (*lpt && cbT) { *lpbuf++=*lpt++; cbT--; }
if (!(*lpt) && cbT) { *lpbuf = TEXT('\0'); }
return cb; }
/*--------------------------------------------------------------------------*/ /* */ /* DeleteTag() - */ /* */ /* in: */ /* hGroup group handle, can be discardable (alwayws shrink object) */ /* */ /*--------------------------------------------------------------------------*/
VOID FAR PASCAL DeleteTag(HANDLE hGroup, int item, WORD id) { LPPMTAG lptag; LPTSTR lp1, lp2; LPTSTR lpend; LPGROUPDEF lpgd;
lpgd = (LPGROUPDEF) GlobalLock(hGroup);
lptag = FindTag(lpgd,item,id);
if (lptag == NULL) { GlobalUnlock(hGroup); return; }
lp1 = (LPTSTR)lptag;
lp2 = (LPTSTR)((LPSTR)lptag + lptag->cb);
lpend = (LPTSTR)((LPSTR)lpgd + SizeofGroup(lpgd));
while (lp2 < lpend) { *lp1++ = *lp2++; }
/* always reallocing smaller
*/ GlobalUnlock(hGroup); CheckBeforeReAlloc(hGroup); GlobalReAlloc(hGroup, (DWORD)((LPSTR)lp1 - (LPSTR)lpgd), 0);
return; }
/*--------------------------------------------------------------------------*/ /* */ /* AddTag() - */ /* */ /* in: */ /* h group handle, must not be discardable! */ /* */ /* returns: */ /* 0 failure */ /* 1 success */ /*--------------------------------------------------------------------------*/ INT PASCAL AddTag(HANDLE h, int item, WORD id, LPTSTR lpbuf, int cb) { LPPMTAG lptag; WORD fAddFirst; LPGROUPDEF lpgd; int cbNew; int cbMyLen; LPGROUPDEF lpgdOld;
if (!cb && lpbuf) { cb = sizeof(TCHAR)*(lstrlen(lpbuf) + 1); } cbMyLen = MyDwordAlign(cb);
if (!lpbuf) { cb = 0; cbMyLen = 0; }
/*
* Remove the old version of the tag, if any. */ DeleteTag(h, item, id);
lpgd = (LPGROUPDEF)GlobalLock(h);
lptag = FindTag(lpgd, (int)0xFFFF, (WORD)ID_LASTTAG);
if (!lptag) { /*
* In this case, there are no tags at all, and we have to add * the first tag, the interesting tag, and the last tag */ cbNew = 3 * (MyDwordAlign(sizeof(PMTAG)) - MyDwordAlign(sizeof(lptag->rgb))) + 4 + cbMyLen; fAddFirst = TRUE; lptag = (LPPMTAG)((LPSTR)lpgd + lpgd->cbGroup);
} else { /*
* In this case, only the interesting tag needs to be added * but we count in the last because the delta is from lptag */ cbNew = 2 * (MyDwordAlign(sizeof(PMTAG)) - MyDwordAlign(sizeof(lptag->rgb))) + cbMyLen; fAddFirst = FALSE; }
/*
* check for 64K limit */ if ((DWORD_PTR)lptag + cbNew < (DWORD_PTR)lptag) { return 0; }
cbNew += (int)((PCHAR)lptag -(PCHAR)lpgd); lpgdOld = lpgd; GlobalUnlock(h); CheckBeforeReAlloc(h); if (!GlobalReAlloc(h, (DWORD)cbNew, GMEM_MOVEABLE)) { return 0; }
lpgd = (LPGROUPDEF)GlobalLock(h); lptag = (LPPMTAG)((LPSTR)lpgd + ((LPSTR)lptag - (LPSTR)lpgdOld)); if (fAddFirst) { /*
* Add the first tag */ lptag->wID = ID_MAGIC; lptag->wItem = (int)0xFFFF; *(LONG FAR *)lptag->rgb = PMTAG_MAGIC; lptag->cb = (WORD)(MyDwordAlign(sizeof(PMTAG)) - MyDwordAlign(sizeof(lptag->rgb)) + 4); (LPSTR)lptag += lptag->cb; }
/*
* Add the tag */ lptag->wID = id; lptag->wItem = item; lptag->cb = (WORD)(MyDwordAlign(sizeof(PMTAG)) - MyDwordAlign(sizeof(lptag->rgb)) + cbMyLen); if (lpbuf) { RtlMoveMemory(lptag->rgb, lpbuf, (WORD)cb); } (LPSTR)lptag += lptag->cb;
/*
* Add the end tag */ lptag->wID = ID_LASTTAG; lptag->wItem = (int)0xFFFF; lptag->cb = 0;
GlobalUnlock(h);
return 1; }
/*--------------------------------------------------------------------------*/ /* */ /* NukeIconBitmap -- Deletes the icon bitmap if one exists for the group */ /* */ /*--------------------------------------------------------------------------*/
void PASCAL NukeIconBitmap(PGROUP pGroup) { if (pGroup->hbm) { DeleteObject(pGroup->hbm); pGroup->hbm = NULL; } }
/*--------------------------------------------------------------------------*/ /* */ /* GroupFlag() - */ /* */ /*--------------------------------------------------------------------------*/
WORD PASCAL GroupFlag(PGROUP pGroup, PITEM pItem, WORD wFlag) { LPGROUPDEF lpgd; LPPMTAG lptag; WORD wT = 0; int wItem;
if (pItem) { wItem = pItem->iItem; } else { wItem = (int)0xFFFF; }
lpgd = LockGroup(pGroup->hwnd); if (!lpgd) return 0;
lptag = FindTag(lpgd, wItem, wFlag);
if (!lptag) wT = 0; else if (lptag->cb == (WORD)(MyDwordAlign(sizeof(PMTAG))-MyDwordAlign(sizeof(lptag->rgb)))) wT = 1; else if (lptag->cb == (WORD)(MyDwordAlign(sizeof(PMTAG))-MyDwordAlign(sizeof(lptag->rgb)) + 1)) wT = lptag->rgb[0]; else if (lptag->cb == (WORD)(MyDwordAlign(sizeof(PMTAG))-MyDwordAlign(sizeof(lptag->rgb)) + 4)) wT = *(LPWORD)lptag->rgb; UnlockGroup(pGroup->hwnd);
return wT; }
/*--------------------------------------------------------------------------*/ /* */ /* GetGroupTag() - */ /* */ /*--------------------------------------------------------------------------*/
WORD PASCAL GetGroupTag( PGROUP pGroup, PITEM pItem, WORD id, LPTSTR lpT, WORD cb) { WORD wT; LPGROUPDEF lpgd; int wItem;
if (pItem) wItem = pItem->iItem; else wItem = (int)0xFFFF;
lpgd = LockGroup(pGroup->hwnd); if (!lpgd) return 0;
wT = (WORD)CopyTag(lpgd, wItem, id, lpT, cb);
UnlockGroup(pGroup->hwnd); return wT; }
/*--------------------------------------------------------------------------*/ /* */ /* ChangeTagID() - */ /* */ /*--------------------------------------------------------------------------*/
void PASCAL ChangeTagID( LPGROUPDEF lpgd, int iOld, int iNew) { LPPMTAG lptag;
while (lptag = FindTag(lpgd,iOld,0)) { lptag->wItem = iNew; } }
/*--------------------------------------------------------------------------*/ /* */ /* LoadItem() - */ /* */ /* Creates an item window (iconic) within a group window. Assumes that the */ /* group segment is up to date. */ /* */ /*--------------------------------------------------------------------------*/
PITEM PASCAL LoadItem(HWND hwndGroup, WORD iItem, BOOL bActivate) { LPGROUPDEF lpgd; LPITEMDEF lpid; PGROUP pGroup; PITEM pItem; PITEM *ppItem;
lpgd = LockGroup(hwndGroup); if (!lpgd) return NULL;
pItem = (PITEM)LocalAlloc(LPTR, sizeof(ITEM)); if (!pItem) { UnlockGroup(hwndGroup); return NULL; }
pGroup = (PGROUP)GetWindowLongPtr(hwndGroup, GWLP_PGROUP);
NukeIconBitmap(pGroup);
if (bActivate) { InvalidateIcon(pGroup, pGroup->pItems); pItem->pNext = pGroup->pItems; pGroup->pItems = pItem; } else { ppItem = &pGroup->pItems; while (*ppItem) { ppItem = &((*ppItem)->pNext); } pItem->pNext = NULL; *ppItem = pItem; }
lpid = ITEM(lpgd, iItem);
pItem->iItem = iItem; pItem->dwDDEId = 0; SetRectEmpty(&pItem->rcTitle); SetRectEmpty(&pItem->rcIcon);
ComputeIconPosition(pGroup, lpid->pt, &pItem->rcIcon, &pItem->rcTitle, (LPTSTR) PTR(lpgd, lpid->pName));
UnlockGroup(hwndGroup);
InvalidateIcon(pGroup, pItem);
return pItem; }
PITEM FindItemName(LPGROUPDEF lpgd, register PITEM pItem, LPTSTR lpTitle) { LPITEMDEF lpid;
while (pItem) { lpid = ITEM(lpgd, pItem->iItem);
if (!lstrcmp(lpTitle, (LPTSTR) PTR(lpgd, lpid->pName))) return pItem;
pItem = pItem->pNext; }
return NULL; }
/*--------------------------------------------------------------------------*/ /* */ /* CreateNewItem() - */ /* */ /*--------------------------------------------------------------------------*/
/*
* Creates a new item in the file, and adds a window for it. */ PITEM PASCAL CreateNewItem( HWND hwndGroup, LPTSTR lpTitle, LPTSTR lpCommand, LPTSTR lpIconPath, LPTSTR lpDefDir, WORD wHotKey, BOOL fMinimize, WORD wIconId, WORD wIconIndex, HICON hIcon, LPPOINT lppt, DWORD dwFlags) { LPGROUPDEF lpgd; LPITEMDEF lpid; WORD id; DWORD offset; PGROUP pGroup; LPTSTR lpIconRes; WORD cbIconRes; //DWORD dwVer;
WORD wVer; WORD idError = IDS_LOWMEM; PITEM pItem; DWORD cb; TCHAR szCommand[3*MAX_PATH]; TCHAR szExeDir[MAXITEMPATHLEN + 1]; TCHAR szIconExe[MAX_PATH]; TCHAR szTemp[MAXITEMPATHLEN+1]; LPTSTR lp1, lp2, lp3; HANDLE hIconRes; HANDLE hModule; BOOL fWin32App = FALSE; BOOL fUseDefaultIcon = FALSE; BOOL bNoIconPath = TRUE; TCHAR cSeparator;
/*
* Before we do anything, whack the command line and exedir */ lp1 = lpCommand; if (*lpCommand == TEXT('"') && wcschr(lpCommand + 1, TEXT('"'))) { cSeparator = TEXT('"'); //lp1++;
} else { cSeparator = TEXT(' '); } for (lp2=lp3=szExeDir; *lp1 && *lp1 != cSeparator; lp1 = CharNext(lp1)) { *lp2++ = *lp1;
/*
* We know we're looking at the first byte */ if ((*lp1 == TEXT(':')) || (*lp1 == TEXT('\\'))) { lp3 = lp2; } }
*lp2 = 0;
/*
* If the default dir pointer is NULL then we use the directory * component of the command line. Otherwise we do the normal * path whacking stuff to get everything into 3.0 format. */ if (lpDefDir) { LPTSTR lpT;
lpT = lpDefDir; // We have a valid pointer.
lstrcpy(szCommand,lpDefDir); #if 0
/* spaces are allowed in LFN.
*/ RemoveLeadingSpaces(szCommand); #endif
// If a default dir was supplied then go ahead and whack it
// into 3.0 format otherwise leave it blank.
if (*lpDefDir) { LPTSTR lpNextChar;
// locate the character before the NULL
while ( *(lpNextChar = CharNext(lpDefDir)) ) lpDefDir = lpNextChar;
// If there is no '\' seperator, add one.
if (lpDefDir[0] != TEXT('\\')) { lstrcat(szCommand,TEXT("\\")); } }
/*
* Now add the filename itself. this puts the command in the * 3.0 format: defdir\exename */ lstrcat(szCommand, lp3);
/*
* Append the arguments */ lstrcat(szCommand, lp1); lpDefDir = lpT;
} else { /*
* Use the same command line (note def dir is assigned exe dir */ lstrcpy(szCommand, lpCommand); }
/*
* Now truncate exedir so that it does not include the command filename */ *lp3 = 0;
pGroup = (PGROUP)GetWindowLongPtr(hwndGroup, GWLP_PGROUP); lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
if (!GroupCheck(pGroup)) { MyMessageBox(hwndProgman, IDS_GROUPFILEERR, IDS_GROUPRO, (LPTSTR) PTR(lpgd, lpgd->pName), MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL); GlobalUnlock(pGroup->hGroup); return NULL; } GlobalUnlock(pGroup->hGroup);
if (*lpIconPath) { bNoIconPath = FALSE; }
lstrcpy(szIconExe, lpIconPath); if (bNoIconPath && !(dwFlags & CI_NO_ASSOCIATION)) { lstrcpy(szIconExe, lpCommand); } DoEnvironmentSubst(szIconExe, (WORD)CharSizeOf(szIconExe)); StripArgs(szIconExe); if (!bNoIconPath) { TagExtension(szIconExe, sizeof(szIconExe)); }
if (*szIconExe == TEXT('"') && *(szIconExe + lstrlen(szIconExe)-1) == TEXT('"')) { SheRemoveQuotes(szIconExe); }
if (bNoIconPath) { //
// if it's a relative path, extractassociatedicon and LoadLibrary don't
// handle that so find the executable first
//
SetCurrentDirectory(szOriginalDirectory); FindExecutable(szIconExe, lpDefDir, szTemp); if (*szTemp) { lstrcpy(szIconExe, szTemp); TagExtension(szIconExe, sizeof(szIconExe)); if (*szIconExe == TEXT('"') && *(szIconExe + lstrlen(szIconExe)-1) == TEXT('"')) { SheRemoveQuotes(szIconExe); } } else { *szIconExe = 0; // Use a dummy value so no icons will be found
// and progman's item icon will be used instead
// This is to make moricons.dll item icon be the
// right one. -johannec 6/4/93
} //
// reset the current directory to progman's working directory i.e. Windows directory
//
SetCurrentDirectory(szWindowsDirectory);
wIconId = 0; wIconIndex = 0; }
NoIcon:
if (!wIconId) { TCHAR szOldIconExe[MAX_PATH];
lstrcpy(szOldIconExe, szIconExe); hIcon = ExtractAssociatedIconEx(hAppInstance, szIconExe, &wIconIndex, &wIconId); if (lstrcmp(szOldIconExe, szIconExe)) { /* using default icon from Progman.exe */ fUseDefaultIcon = TRUE; } if (hIcon) DestroyIcon(hIcon); }
lpIconRes = NULL; hIconRes = NULL; if (hModule = LoadLibrary(szIconExe)) { fWin32App = TRUE; hIconRes = FindResource(hModule, (LPTSTR) MAKEINTRESOURCE(wIconId), (LPTSTR) MAKEINTRESOURCE(RT_ICON)); if (hIconRes) { //dwVer = 0x00030000; // resource version is windows 3.x
wVer = 3; // resource version is windows 3.x
cbIconRes = (WORD)SizeofResource(hModule, hIconRes); hIconRes = LoadResource(hModule, hIconRes); lpIconRes = LockResource(hIconRes); } if (fUseDefaultIcon) { wIconId = 0; } } else { // Win 3.1 app
if (wVer = ExtractIconResInfo(hAppInstance, szIconExe, wIconIndex, &cbIconRes, &hIconRes)){ lpIconRes = GlobalLock(hIconRes); } }
if (!lpIconRes) { wIconId = 0; wIconIndex = 0;
// ToddB: I see no harm in always setting the current directory to the WinDir
// before jumping back to NoIcon. Seems to be required to fix a Japanese bug.
// The WinDir is the default directory of Progman anyhow, I really don't see
// where it's possible for us to not already be in this directory.
SetCurrentDirectory(szWindowsDirectory);
goto NoIcon; }
if (!KeepGroupAround(hwndGroup, TRUE)) { goto FreeIcon; }
id = FindFreeItemIndex(hwndGroup); if (id == 0xFFFF) { goto FreeIcon; }
if (id >= CITEMSMAX) { // check group size limit
idError = IDS_TOOMANYITEMS; goto FreeIcon; }
offset = AddThing(pGroup->hGroup, (TCHAR)0, (WORD)sizeof(ITEMDEF)); lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
if (!offset) { goto QuitThis; }
lpgd->rgiItems[id] = offset; lpid = ITEM(lpgd, id);
GlobalUnlock(pGroup->hGroup); offset = AddThing(pGroup->hGroup, lpTitle, (WORD)0); lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup); lpid = ITEM(lpgd, id); if (!offset) { goto PuntCreation; }
lpid->pName = offset;
GlobalUnlock(pGroup->hGroup); offset = AddThing(pGroup->hGroup, szCommand,(WORD) 0); lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup); lpid = ITEM(lpgd, id); if (!offset) { goto PuntCreation; } lpid->pCommand = offset;
GlobalUnlock(pGroup->hGroup); CheckEscapes(szIconExe, CharSizeOf(szIconExe)); offset = AddThing(pGroup->hGroup, szIconExe,(WORD) 0); lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup); lpid = ITEM(lpgd, id); if (!offset) goto PuntCreation; lpid->pIconPath = offset;
GlobalUnlock(pGroup->hGroup); offset = AddThing(pGroup->hGroup, lpIconRes, cbIconRes); lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup); lpid = ITEM(lpgd, id); if (!offset) goto PuntCreation; lpid->pIconRes = offset;
if (lppt) { lpid->pt = *lppt; } else { lpid->pt.x = lpid->pt.y = -1; }
lpid->iIcon = wIconId; lpid->wIconIndex = wIconIndex; //lpid->dwIconVer = dwVer;
lpid->wIconVer = wVer; lpid->cbIconRes = cbIconRes;
if (cbIconRes != 0xFFFF) if (fWin32App) { UnlockResource(hIconRes); FreeResource(hIconRes); FreeLibrary(hModule); } else { GlobalUnlock(hIconRes); GlobalFree(hIconRes); } GlobalUnlock(pGroup->hGroup);
if (wHotKey) { AddTag(pGroup->hGroup, (int)id, (WORD)ID_HOTKEY, (LPTSTR)&wHotKey, sizeof(wHotKey)); } if (fMinimize) { AddTag(pGroup->hGroup, (int)id, (WORD)ID_MINIMIZE, NULL, 0); } if (dwFlags & CI_SEPARATE_VDM) { AddTag(pGroup->hGroup, (int)id, (WORD)ID_NEWVDM, NULL, 0); } if (*szExeDir) { AddTag(pGroup->hGroup, (int)id, (WORD)ID_APPLICATIONDIR, szExeDir, 0); }
pItem = LoadItem(hwndGroup, id, dwFlags & CI_ACTIVATE);
lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup); lpid = ITEM(lpgd, id);
if (!pItem) { goto PuntCreation; }
lpid->pt.x = pItem->rcIcon.left; lpid->pt.y = pItem->rcIcon.top;
GlobalUnlock(pGroup->hGroup);
#if 0
// DOS apps are no longer set to fullscreen by default in progman
// 5-3-93 johannec (bug 8343)
#ifdef i386
//
// If this is a new DOS application, set the default to full screen.
// This is only done for x86, since mips doesn't have full screen.
//
lstrcpy(szCommand, lpCommand); DoEnvironmentSubst(szCommand, (WORD)lstrlen(szCommand)); StripArgs(szCommand); TagExtension(szCommand, sizeof(szCommand)); *szTemp = 0; FindExecutable(szCommand, lpDefDir, szTemp);
if ((dwFlags & CI_SET_DOS_FULLSCRN) && *szTemp && IsDOSApplication(szTemp)) { SetDOSApplicationToFullScreen(lpTitle); } #endif
#endif
KeepGroupAround(hwndGroup, FALSE);
// We need to save the current group to disk now
// in case a setup program is doing DDE with us,
// and they reboot the system when finished.
if (!SaveGroup (hwndGroup, FALSE)) { idError = 0; DeleteItem(pGroup, pItem); goto FreeIcon; }
return pItem;
PuntCreation: /*
* Note, must set lpid after each because it may move */ DeleteThing(lpgd, (LPDWORD)&lpid->pName, 0); DeleteThing(lpgd, (LPDWORD)&lpid->pCommand, 0); DeleteThing(lpgd, (LPDWORD)&lpid->pIconPath, 0); DeleteThing(lpgd, (LPDWORD)&lpid->pIconRes, lpid->cbIconRes); DeleteThing(lpgd, (LPDWORD)&lpgd->rgiItems[id], sizeof(ITEMDEF));
QuitThis: cb = SizeofGroup(lpgd); UnlockGroup(pGroup->hwnd);
CheckBeforeReAlloc(pGroup->hGroup); GlobalReAlloc(pGroup->hGroup, cb, GMEM_MOVEABLE);
KeepGroupAround(hwndGroup, FALSE);
FreeIcon: if (cbIconRes != 0xFFFF) if (fWin32App) { UnlockResource(hIconRes); FreeResource(hIconRes); FreeLibrary(hModule); } else { GlobalUnlock(hIconRes); GlobalFree(hIconRes); }
if (idError != 0) MyMessageBox(hwndProgman, IDS_GROUPFILEERR, idError, NULL, MB_OK | MB_ICONEXCLAMATION); // Force re-read of group.
//GlobalDiscard(pGroup->hGroup);
//pGroup->fLoaded = FALSE ;
//LockGroup(pGroup->hwnd);
//UnlockGroup(pGroup->hwnd);
return NULL; }
/*--------------------------------------------------------------------------*/ /* */ /* DeleteItem() - */ /* */ /*--------------------------------------------------------------------------*/
VOID FAR PASCAL DeleteItem(PGROUP pGroup, PITEM pItem) { LPGROUPDEF lpgd; LPITEMDEF lpid; DWORD cb; LPPMTAG lptag;
lpgd = LockGroup(pGroup->hwnd); if (!lpgd) return;
if (!GroupCheck(pGroup)) { MyMessageBox(hwndProgman, IDS_GROUPFILEERR, IDS_GROUPRO, (LPTSTR) PTR(lpgd, lpgd->pName), MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL); InvalidateIcon(pGroup, pItem); return; }
NukeIconBitmap(pGroup);
lpid = ITEM(lpgd,pItem->iItem);
if ( (lpgd->cbGroup != (DWORD)MyDwordAlign((int)lpgd->cbGroup)) || (lpid->pName != (DWORD)MyDwordAlign((int)lpid->pName)) || (lpid->pCommand != (DWORD)MyDwordAlign((int)lpid->pCommand)) || (lpid->pIconPath != (DWORD)MyDwordAlign((int)lpid->pIconPath)) || (lpgd->rgiItems[pItem->iItem] != (DWORD)MyDwordAlign((int)lpgd->rgiItems[pItem->iItem])) ) {
MyMessageBox(hwndProgman, IDS_GROUPFILEERR, IDS_BADFILE, (LPTSTR) PTR(lpgd, lpgd->pName), MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL); return; }
/* note, must set lpid after each because it may move
*/ DeleteThing(lpgd, (LPDWORD)&lpid->pName, 0); DeleteThing(lpgd, (LPDWORD)&lpid->pCommand, 0); DeleteThing(lpgd, (LPDWORD)&lpid->pIconPath, 0); DeleteThing(lpgd, (LPDWORD)&lpid->pIconRes, lpid->cbIconRes); DeleteThing(lpgd, (LPDWORD)&lpgd->rgiItems[pItem->iItem], sizeof(ITEMDEF));
while (lptag = FindTag(lpgd,pItem->iItem,0)) { /* delete all tags associated with this item
*/ UnlockGroup(pGroup->hwnd); DeleteTag(pGroup->hGroup, lptag->wItem, lptag->wID); lpgd = LockGroup(pGroup->hwnd); }
/* Don't need Item anymore so delete it. */ RemoveItemFromList(pGroup, pItem);
cb = SizeofGroup(lpgd);
UnlockGroup(pGroup->hwnd);
CheckBeforeReAlloc(pGroup->hGroup); GlobalReAlloc(pGroup->hGroup, cb, GMEM_MOVEABLE);
if (bAutoArrange && !bAutoArranging) ArrangeItems(pGroup->hwnd); else if (!bAutoArranging) CalcGroupScrolls(pGroup->hwnd);
}
/*--------------------------------------------------------------------------*/ /* */ /* CreateItemIcons() - */ /* */ /* Creates all the item windows... */ /* */ /*--------------------------------------------------------------------------*/
VOID PASCAL CreateItemIcons(HWND hwndGroup) { LPGROUPDEF lpgd; int i;
lpgd = LockGroup(hwndGroup);
if (!lpgd) { return; }
/*
* Create the items in reverse Z-Order. */ for (i = lpgd->cItems - 1; i >= 0; i--) { if (lpgd->rgiItems[i]) { LoadItem(hwndGroup, (WORD)i, TRUE); } }
UnlockGroup(hwndGroup);
// REVIEW This may be not be needed because LoadGroupWindow does a
// SetInternalWindowPos which MIGHT already be generating the messages
// to do this.
if (bAutoArrange && !bAutoArranging) ArrangeItems(hwndGroup); else if (!bAutoArranging) CalcGroupScrolls(hwndGroup); }
/*--------------------------------------------------------------------------*/ /* */ /* CheckIconResolution() - */ /* */ /* Makes sure we have the right icons loaded... reextracts and saves */ /* the file if not. */ /* */ /*--------------------------------------------------------------------------*/
VOID NEAR PASCAL CheckIconResolution(HWND hwndGroup)
{ LPGROUPDEF lpgd; LPITEMDEF lpid; register PGROUP pGroup; HANDLE hGroup; BOOL fGottaDoIt; register HDC hdc; int i; HICON hIcon; WORD cbIconRes; DWORD pIconRes; LPTSTR lpIconRes; WORD wFormat; TCHAR szTemp[MAXITEMPATHLEN]; HANDLE hModule; BOOL fWin32App; //DWORD dwVer;
WORD wVer;
lpgd = LockGroup(hwndGroup); if (!lpgd) return;
hdc = GetDC(hwndGroup);
wFormat = (WORD)GetDeviceCaps(hdc, BITSPIXEL) | (WORD)GetDeviceCaps(hdc, PLANES) * (WORD)256;
ReleaseDC(hwndGroup,hdc);
fGottaDoIt = lpgd->wIconFormat != wFormat || lpgd->cxIcon != (WORD)GetSystemMetrics(SM_CXICON) || lpgd->cyIcon != (WORD)GetSystemMetrics(SM_CYICON);
if (!fGottaDoIt) { goto CleanUpAndLeave; }
pGroup = (PGROUP)GetWindowLongPtr(hwndGroup,GWLP_PGROUP);
NukeIconBitmap(pGroup);
/* Save the new resolution parameters in the group file. */ lpgd->wIconFormat = wFormat; lpgd->cxIcon = (WORD)GetSystemMetrics(SM_CXICON); lpgd->cyIcon = (WORD)GetSystemMetrics(SM_CYICON);
hGroup = pGroup->hGroup;
for (i = 0; i < (int)lpgd->cItems; ++i) { if (!lpgd->rgiItems[i]) continue;
lpid = ITEM(lpgd, i); DeleteThing(lpgd, (LPDWORD)&lpid->pIconRes, lpid->cbIconRes); lpid = ITEM(lpgd, i);
lstrcpy(szTemp, (LPTSTR) PTR(lpgd, lpid->pIconPath)); if (!*szTemp) { /* Get default icon path */ lstrcpy(szTemp, (LPTSTR) PTR(lpgd, lpid->pCommand)); DoEnvironmentSubst(szTemp, (WORD)(MAXITEMPATHLEN+1)); StripArgs(szTemp); } SheRemoveQuotes(szTemp); cbIconRes = 0xFFFF; lpIconRes = NULL; hIcon = NULL;
if (hModule = LoadLibrary(szTemp)) { // if WIN32 app
fWin32App = TRUE; hIcon = (HICON)FindResource(hModule, (LPTSTR) MAKEINTRESOURCE(lpid->iIcon), (LPTSTR) MAKEINTRESOURCE(RT_ICON)); if (hIcon) { //dwVer = 0x00030000;
wVer = 3; cbIconRes = (WORD)SizeofResource(hModule, (HRSRC)hIcon); hIcon = (HICON)LoadResource(hModule, (HRSRC)hIcon); lpIconRes = LockResource(hIcon); } } else { // Win 3.1 app
fWin32App = FALSE; if (wVer = ExtractIconResInfo(hAppInstance, szTemp, lpid->iIcon, &cbIconRes, (LPHANDLE)&hIcon)){ lpIconRes = GlobalLock(hIcon); } }
UnlockGroup(hwndGroup);
pIconRes = AddThing(pGroup->hGroup, lpIconRes, cbIconRes); lpgd = LockGroup(hwndGroup); if (!lpgd) continue;
/* In case the segment got moved... */ lpid = ITEM(lpgd, i);
if (hIcon) if (fWin32App) { UnlockResource(hIcon); FreeResource(hIcon); FreeLibrary(hModule); } else { GlobalUnlock(hIcon); GlobalFree(hIcon); }
lpid->pIconRes = pIconRes; //lpid->dwIconVer = dwVer;
lpid->wIconVer = wVer; lpid->cbIconRes = cbIconRes; }
#ifdef ORGCODE
// Check everythings OK.
if (!pHdr || !pAND || !pXOR) { // FU - delete icon stuff for this item..
// REVIEW UNDONE - warn user about memory problem ?
#ifdef DEBUG
KdPrint(("PM.CIR: Corrupted icon %s \n\r", (LPTSTR) PTR(lpid->pName))); #endif
lpid = ITEM(lpgd, i); DeleteThing(lpgd, (LPDWORD)&lpid->pIconRes, lpid->cbIconRes);
// Mark item as being effed - the header is checked by
// GetItemIcon.
lpid = ITEM(lpgd, i); lpid->pIconRes = NULL; lpid->wIconVer = 0; // This is the important one.
lpid->cbIconRes = 0;
// Warn user when we're through, not right in the middle.
fErrorOnExtract = TRUE; } } #endif
if (!GroupCheck(pGroup)) MyMessageBox(hwndProgman, IDS_GROUPFILEERR, IDS_EEGROUPRO, (LPTSTR) PTR(lpgd, lpgd->pName), MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL);
CleanUpAndLeave: UnlockGroup(hwndGroup);
//REVIEW See above.
KeepGroupAround(hwndGroup, FALSE); return; }
/*--------------------------------------------------------------------------*/ /* */ /* CreateGroupHandle() - */ /* */ /* Creates a discarded handle for use as a group handle... on the first */ /* LockGroup() the file will be loaded. */ /* */ /*--------------------------------------------------------------------------*/
HANDLE NEAR PASCAL CreateGroupHandle(void) { register HANDLE hGroup;
if (hGroup = GlobalAlloc(GMEM_MOVEABLE | GMEM_DISCARDABLE, 1L)) GlobalDiscard(hGroup);
return(hGroup); }
/*--------------------------------------------------------------------------*/ /* */ /* StartupGroup() - */ /* */ /*--------------------------------------------------------------------------*/
VOID FAR PASCAL StartupGroup(HWND hwnd) { PITEM pItemCur, pItemExec; LPGROUPDEF lpgd; INT xLast, yLast; // Coord of icon to exec.
INT xBest, yBest; // Coord of next topmost-leftmost icon.
MSG msg; // Peek a message.
PGROUP pGroup; // The group.
pGroup = (PGROUP)GetWindowLongPtr(hwnd, GWLP_PGROUP);
/*
* Handle Startup group in icon position order - not Z-order. */ lpgd = LockGroup(hwnd); if (!lpgd) return;
/*
* Starts with the top left and works from left to right then * top to bottom. * This is really naff in terms of speed, but groups are usually * small and the time cost is still small compared to that of execing. */ yLast = WORD_MIN; xLast = WORD_MIN; for (;;) { /*
* Init */ xBest = WORD_MAX; yBest = WORD_MAX; pItemExec = NULL; /*
* Find next icon to the right of this one. */ for (pItemCur = pGroup->pItems; pItemCur; pItemCur = pItemCur->pNext) { /*
* Look for Icon to the right of this one. * REVIEW This will ignore icons stacked on top of each other. */ if (pItemCur->rcIcon.top >= yLast && pItemCur->rcIcon.top <= yLast + (cyArrange/2) && pItemCur->rcIcon.left < xBest && pItemCur->rcIcon.left > xLast) { pItemExec = pItemCur; xBest = pItemCur->rcIcon.left; } /*
* Check if it'll be suitable for the next row. */ else if (pItemCur->rcIcon.top > yLast + (cyArrange/2) && pItemCur->rcIcon.top < yBest) { yBest = pItemCur->rcIcon.top; }
}
if (pItemExec) { /*
* Found one on the current row. */
xLast = xBest; /*
* Move this item to the top of the z-order so that any searches * done during DDE will find the last execed item first. * REVIEW This messes with the z-odrder of the startup group. */ BringItemToTop(pGroup, pItemExec, TRUE); /* Start it up. */ ExecItem(pGroup,pItemExec,FALSE, TRUE); /*
* Handle any DDE before doing anything else to stop * the message queue from over-flowing. */ while(PeekMessage(&msg, hwndProgman, 0, 0, PM_REMOVE|PM_NOYIELD)) { TranslateMessage(&msg); DispatchMessage(&msg); }
} else if (yBest != WORD_MAX) { /*
* Nothing left on the current row but there is another row. */ yLast = yBest; xLast = WORD_MIN;
} else { /*
* Nothing left. */ goto Quit; } }
Quit: UnlockGroup(pGroup->hwnd); }
/*---------------------------------------------------------------------------
* Check for null item pointers and item pointers that go out of the group. * REVIEW UNDONE this doesn't check that the pointers point to things * after the end of the items array. */ BOOL NEAR PASCAL ValidItems(LPGROUPDEF lpgd) { INT i; LPITEMDEF lpid; DWORD cbGroup;
if (!lpgd) return FALSE;
cbGroup = lpgd->cbGroup;
for (i = 0; (WORD)i < lpgd->cItems; i++) { if (!lpgd->rgiItems[i]) continue;
lpid = ITEM(lpgd,i); if (!lpid) return FALSE;
if (lpid->pName > cbGroup) return FALSE; if (lpid->pCommand > cbGroup) return FALSE; if (lpid->pIconPath > cbGroup) return FALSE; if ((lpid->cbIconRes != (WORD)-1) && (lpid->pIconRes > cbGroup)) return FALSE;
}
return(TRUE); }
/*--------------------------------------------------------------------------*/ /* */ /* IsGroupAlreadyLoaded() - */ /* */ /* Determines if the user is trying to load a currently loaded group. */ /* */ /*--------------------------------------------------------------------------*/
HWND NEAR PASCAL IsGroupAlreadyLoaded(LPTSTR lpGroupKey, BOOL bCommonGroup) { HWND hwndT; PGROUP pGroup;
for (hwndT=GetWindow(hwndMDIClient, GW_CHILD); hwndT; hwndT=GetWindow(hwndT, GW_HWNDNEXT)) { if (GetWindow(hwndT, GW_OWNER)) continue;
pGroup = (PGROUP)GetWindowLongPtr(hwndT, GWLP_PGROUP); if (!lstrcmpi(lpGroupKey, pGroup->lpKey)) {
if (bCommonGroup) {
if (pGroup->fCommon) return(hwndT);
} else {
if (!pGroup->fCommon) return(hwndT);
} } } return(NULL); }
BOOL NEAR PASCAL IndexUsed(WORD wIndex, BOOL bCommonGroup) { PGROUP pGroup;
for (pGroup = pFirstGroup; pGroup; pGroup = pGroup->pNext) if ((pGroup->wIndex == wIndex) && (pGroup->fCommon == bCommonGroup)) return TRUE;
return FALSE; }
/*--------------------------------------------------------------------------*/ /* */ /* LoadGroupWindow() - */ /* */ /* Creates a group window by sending an MDI create message to the MDI client. */ /* The MDICREATESTRUCT contains a parameter pointer to the name of the group */ /* key. */ /* */ /*--------------------------------------------------------------------------*/ // GroupFile must be ANSI.
HWND PASCAL LoadGroupWindow(LPTSTR lpKey, WORD wIndex, BOOL bCommonGroup) { MDICREATESTRUCT mdics; PGROUP pGroup; TCHAR szGroupClass[64]; LPGROUPDEF lpgd; HWND hwnd; TCHAR szCommonGroupSuffix[MAXKEYLEN]; TCHAR szCommonGroupTitle[2*MAXKEYLEN]; WINDOWPLACEMENT wp;
//
// Check if the group is already loaded. This will prevent duplicate groups.
//
if (hwnd = IsGroupAlreadyLoaded(lpKey, bCommonGroup)) { return(hwnd); }
if (!wIndex) { while (IndexUsed(++wIndex, bCommonGroup)) ; }
if (!LoadString(hAppInstance, IDS_GROUPCLASS, szGroupClass, CharSizeOf(szGroupClass))) { return NULL; }
pGroup = (PGROUP)LocalAlloc(LPTR,sizeof(GROUP)); if (!pGroup) { return NULL; }
pGroup->hGroup = CreateGroupHandle(); pGroup->pItems = NULL; pGroup->hbm = NULL; pGroup->wIndex = wIndex; pGroup->fCommon = bCommonGroup; pGroup->ftLastWriteTime.dwLowDateTime = 0; pGroup->ftLastWriteTime.dwHighDateTime = 0;
pGroup->lpKey = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR)*(lstrlen(lpKey) + 1)); pGroup->fLoaded = FALSE;
if (!pGroup->lpKey) { GoAway: GlobalFree(pGroup->hGroup); LocalFree((HANDLE)pGroup); if (!fLowMemErrYet) { MyMessageBox(hwndProgman, IDS_APPTITLE, IDS_LOWMEMONINIT, lpKey, MB_OK|MB_ICONEXCLAMATION); fLowMemErrYet = TRUE; } return NULL; }
lstrcpy(pGroup->lpKey, lpKey);
mdics.szTitle = TEXT(""); mdics.hOwner = hAppInstance; mdics.szClass = szGroupClass; mdics.style = WS_VSCROLL|WS_HSCROLL; mdics.x = mdics.y = mdics.cx = mdics.cy = CW_USEDEFAULT; mdics.lParam = (LPARAM)pGroup;
/*
* REVIEW HACK - Set the auto arranging flag to stop the group being * loaded by ArrangingIcons doing a LockGroup and then producing * an error if something goes wrong. We're going to do a lock * later on anyway and we don't want two error messages. */ bAutoArranging = TRUE; pGroup->hwnd = (HWND)SendMessage(hwndMDIClient, WM_MDICREATE, 0, (LPARAM)(LPTSTR)&mdics); bAutoArranging = FALSE;
if (!pGroup->hwnd) { LocalFree((HANDLE)pGroup->lpKey); goto GoAway; }
/*
* Note that we're about to load a group for the first time. * NB Stting this tells LockGroup that the caller can handle the errors. */ fFirstLoad = TRUE; lpgd = LockGroup(pGroup->hwnd); /*
* The group has been loaded or at least we tried. */ fFirstLoad = FALSE; if (!lpgd) { LoadFail: /* Loading the group failed somehow... */ SendMessage(hwndMDIClient, WM_MDIDESTROY, (WPARAM)pGroup->hwnd, 0L); //
// stop handling of Program Groups key changes.
//
bHandleProgramGroupsEvent = FALSE; RegDeleteKey(hkeyProgramGroups, pGroup->lpKey);
//
// reset handling of Program Groups key changes.
//
ResetProgramGroupsEvent(bCommonGroup); bHandleProgramGroupsEvent = TRUE;
LocalFree((HANDLE)pGroup->lpKey); GlobalFree(pGroup->hGroup); LocalFree((HANDLE)pGroup); return NULL; }
/*
* test if it is a Windows 3.1 group file format. If so it is not * valid in WIN32. In Windows 3.1 RECT and POINT are WORD instead of LONG. */
if ( (lpgd->rcNormal.left != (INT)(SHORT)lpgd->rcNormal.left) || (lpgd->rcNormal.right != (INT)(SHORT)lpgd->rcNormal.right) || (lpgd->rcNormal.top != (INT)(SHORT)lpgd->rcNormal.top) || (lpgd->rcNormal.bottom != (INT)(SHORT)lpgd->rcNormal.bottom) ){ /* The group is invalid. */ MyMessageBox(hwndProgman, IDS_GROUPFILEERR, IDS_BADFILE, (LPTSTR) PTR(lpgd, lpgd->pName), MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL); UnlockGroup(pGroup->hwnd); goto LoadFail; }
if (!ValidItems(lpgd)) { MyMessageBox(hwndProgman, IDS_GROUPFILEERR, IDS_BADFILE, (LPTSTR) PTR(lpgd, lpgd->pName), MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL); UnlockGroup(pGroup->hwnd); goto LoadFail; }
if (lpgd->nCmdShow) { SetInternalWindowPos(pGroup->hwnd, (UINT)lpgd->nCmdShow, &lpgd->rcNormal, &lpgd->ptMin); }
if (pGroup->fCommon) {
//
// Add the common group suffix to the name of the group e.g. (Common)
// Only do this if the group window is not minimized.
//
wp.length = sizeof(WINDOWPLACEMENT); GetWindowPlacement(pGroup->hwnd, &wp); if ((wp.showCmd == SW_MINIMIZE) || (wp.showCmd == SW_SHOWMINIMIZED) || (wp.showCmd == SW_SHOWMINNOACTIVE) ) { SetWindowText(pGroup->hwnd, (LPTSTR) PTR(lpgd, lpgd->pName)); } else { lstrcpy(szCommonGroupTitle, (LPTSTR) PTR(lpgd, lpgd->pName)); if (LoadString(hAppInstance, IDS_COMMONGRPSUFFIX, szCommonGroupSuffix, CharSizeOf(szCommonGroupSuffix))) { lstrcat(szCommonGroupTitle, szCommonGroupSuffix); } SetWindowText(pGroup->hwnd, szCommonGroupTitle); if (!UserIsAdmin) { pGroup->fRO = TRUE; } } } else { SetWindowText(pGroup->hwnd, (LPTSTR) PTR(lpgd, lpgd->pName)); }
UnlockGroup(pGroup->hwnd);
//CheckIconResolution(pGroup->hwnd);
CreateItemIcons(pGroup->hwnd);
/*
* Link the group. */ pGroup->pNext = NULL; *pLastGroup = pGroup; pLastGroup = &pGroup->pNext; pCurrentGroup = pGroup;
#ifdef NOTINUSER
CalcChildScroll(pGroup->hwnd, SB_BOTH); #endif
GroupCheck(pGroup);
return(pGroup->hwnd); }
/*--------------------------------------------------------------------------*/ /* */ /* UnloadGroupWindow() - */ /* */ /*--------------------------------------------------------------------------*/
void FAR PASCAL UnloadGroupWindow(HWND hwnd) { PGROUP pGroup, *ppGroup; PITEM pItem, pItemNext;
pGroup = (PGROUP)GetWindowLongPtr(hwnd,GWLP_PGROUP);
/* Destroy the window. */ SendMessage(hwndMDIClient,WM_MDIDESTROY,(WPARAM)hwnd,0L);
/* Free the group segment. */ GlobalFree(pGroup->hGroup);
/* Free the local stuff. */ LocalFree((HANDLE)pGroup->lpKey);
/* The cached bitmap if there is one. */ if (pGroup->hbm) { DeleteObject(pGroup->hbm); pGroup->hbm = NULL; }
/* The item data. */ for (pItem = pGroup->pItems; pItem; pItem = pItemNext) { pItemNext = pItem->pNext; LocalFree((HANDLE) pItem); }
/* Remove the group from the linked list. */ for (ppGroup = &pFirstGroup; *ppGroup; ppGroup = &((*ppGroup)->pNext)) { if (*ppGroup == pGroup) { *ppGroup = pGroup->pNext; break; } } if (pLastGroup == &pGroup->pNext) pLastGroup = ppGroup;
/* Lastly, free the group structure itself. */ LocalFree((HANDLE)pGroup); }
/*--------------------------------------------------------------------------*/ /* */ /* RemoveBackslashFromKeyName() - */ /* */ /* replace the invalid characters for a key name by some valid charater. */ /* the same characters that are invalid for a file name are invalid for a */ /* key name. */ /* */ /*--------------------------------------------------------------------------*/
void RemoveBackslashFromKeyName(LPTSTR lpKeyName) { LPTSTR lpt;
for (lpt = lpKeyName; *lpt; lpt++) { if ((*lpt == TEXT('\\')) || (*lpt == TEXT(':')) || (*lpt == TEXT('>')) || (*lpt == TEXT('<')) || (*lpt == TEXT('*')) || (*lpt == TEXT('?')) ){ *lpt = TEXT('.'); } } }
/*--------------------------------------------------------------------------*/ /* */ /* CreateNewGroup() - */ /* */ /* This function creates a new, empty group. */ /* */ /*--------------------------------------------------------------------------*/
HWND PASCAL CreateNewGroup(LPTSTR pGroupName, BOOL bCommonGroup) { HANDLE hT; LPGROUPDEF lpgd; PGROUP pGroup; HDC hdc; int i; int cb; TCHAR szKeyName[MAXKEYLEN+1]; HWND hwnd; DWORD status = 0; WORD cGroups; INT wGroupNameLen; //length of pGroupName DWORD aligned.
HKEY hkeyGroups; HKEY hKey; HWND hwndT; PSECURITY_ATTRIBUTES pSecAttr;
/*
* Check we're not trying to create too many groups. * Count the current number of groups. */ cGroups = 0;
for (hwnd = GetWindow(hwndMDIClient, GW_CHILD); hwnd; hwnd = GetWindow(hwnd, GW_HWNDNEXT)) { if (GetWindow(hwnd, GW_OWNER)) continue; //
// count the common groups seperately from the personal group.
// Both have a maximum of CGROUPSMAX groups.
//
pGroup = (PGROUP)GetWindowLongPtr(hwnd, GWLP_PGROUP); if (bCommonGroup && pGroup->fCommon || !bCommonGroup && !pGroup->fCommon) { cGroups++; } }
// Compare with limit.
if (cGroups >= CGROUPSMAX) { status = bCommonGroup ? IDS_TOOMANYCOMMONGROUPS : IDS_TOOMANYGROUPS; goto Exit; }
if (bCommonGroup) {
hkeyGroups = hkeyCommonGroups; pSecAttr = pAdminSecAttr; if (!hkeyGroups) { if (MyMessageBox(hwndProgman, IDS_COMMONGROUPERR, IDS_NOCOMMONGRPS, pGroupName, MB_OKCANCEL | MB_ICONEXCLAMATION | MB_TASKMODAL) == IDOK) {
hkeyGroups = hkeyProgramGroups; pSecAttr = pSecurityAttributes; bCommonGroup = FALSE;
} else { return(NULL); } }
} else {
hkeyGroups = hkeyProgramGroups; pSecAttr = pSecurityAttributes;
}
if (!hkeyGroups) { status = IDS_NOGRPFILE; goto Exit; }
//
// Replace backslash in the group name because the registry does not
// allow key names with backslash, bckslash is used to separate keys.
//
lstrcpy(szKeyName, pGroupName); RemoveBackslashFromKeyName(szKeyName);
//
// Test for existing key.
//
while (!RegOpenKeyEx(hkeyGroups, szKeyName, 0, KEY_READ, &hKey)) { /* a group with this name already exists */ if (hwndT = IsGroupAlreadyLoaded(szKeyName, bCommonGroup)) { if (lstrlen(szKeyName) < MAXKEYLEN) { lstrcat(szKeyName, TEXT(".")); GlobalUnlock(pGroup->hGroup); RegCloseKey(hKey); continue; } } RegCloseKey(hKey); goto LoadGroupFile; }
wGroupNameLen = MyDwordAlign(sizeof(TCHAR)*(lstrlen(pGroupName) + 1)); cb = sizeof(GROUPDEF) + (NSLOTS * sizeof(DWORD)) + wGroupNameLen;
/*
* In CreateNewGroup before GlobalAlloc. */ hT = GlobalAlloc(GHND, (DWORD)cb); if (!hT) { status = IDS_LOWMEM; goto Exit; }
lpgd = (LPGROUPDEF)GlobalLock(hT);
lpgd->dwMagic = GROUP_UNICODE; lpgd->cbGroup = (DWORD)cb; lpgd->nCmdShow = 0; /* use MDI defaults */ lpgd->pName = sizeof(GROUPDEF) + NSLOTS * sizeof(DWORD); hdc = GetDC(NULL); lpgd->wIconFormat = (WORD)GetDeviceCaps(hdc, BITSPIXEL) + (WORD)256 * (WORD)GetDeviceCaps(hdc, PLANES); ReleaseDC(NULL, hdc); lpgd->cxIcon = (WORD)GetSystemMetrics(SM_CXICON); lpgd->cyIcon = (WORD)GetSystemMetrics(SM_CYICON); lpgd->Reserved1 = (WORD)-1; lpgd->Reserved2 = (DWORD)-1;
lpgd->cItems = NSLOTS;
for (i = 0; i < NSLOTS; i++) { lpgd->rgiItems[i] = 0; }
lstrcpy((LPTSTR)((LPSTR)lpgd + sizeof(GROUPDEF) + NSLOTS * sizeof(DWORD)), pGroupName);
/*
* In CreateNewGroup before SizeofGroup. */ cb = (int)SizeofGroup(lpgd);
//
// stop handling of Program Groups key changes when creating groups.
//
bHandleProgramGroupsEvent = FALSE;
//
// REARCHITECT: pSecurityAttributes might change for Common groups.
//
if (!RegCreateKeyEx(hkeyGroups, szKeyName, 0, 0, 0, DELETE | KEY_READ | KEY_WRITE, pSecAttr, &hKey, NULL)) { if (RegSetValueEx(hKey, NULL, 0, REG_BINARY, (LPBYTE)lpgd, cb)) status = IDS_CANTWRITEGRP; RegCloseKey(hKey); } else status = IDS_NOGRPFILE;
GlobalUnlock(hT); GlobalFree(hT);
Exit: if (status) { MyMessageBox(hwndProgman, IDS_GROUPFILEERR, (WORD)status, pGroupName, MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL); ResetProgramGroupsEvent(bCommonGroup); bHandleProgramGroupsEvent = TRUE; return NULL; }
LoadGroupFile: /*
* The group file now exists on the disk... load it in! */ fLowMemErrYet = FALSE; fErrorOnExtract = FALSE; hwnd = LoadGroupWindow(szKeyName, 0, bCommonGroup);
if (fErrorOnExtract) { // On observed problem with icon extraction has been to do
// with a low memory.
MyMessageBox(hwndProgman, IDS_OOMEXITTITLE, IDS_LOWMEMONEXTRACT, NULL, MB_OK|MB_ICONHAND|MB_SYSTEMMODAL); }
// Save the group section even if SaveSettings is off to stop
// users from themselves.
if (!bCommonGroup) { WriteGroupsSection(); } ResetProgramGroupsEvent(bCommonGroup); bHandleProgramGroupsEvent = TRUE; return hwnd; }
/*--------------------------------------------------------------------------*/ /* */ /* DeleteGroup() - */ /* */ /*--------------------------------------------------------------------------*/
VOID FAR PASCAL DeleteGroup(HWND hwndGroup) { PGROUP pGroup = (PGROUP)GetWindowLongPtr(hwndGroup, GWLP_PGROUP); PGROUP *ppGroup; PITEM pItem; TCHAR szT[10]; BOOL bCommonGroup; HKEY hkeyGroups;
//
// stop handling of Program Groups key changes when deleting groups.
//
bHandleProgramGroupsEvent = FALSE;
bCommonGroup = pGroup->fCommon; if (bCommonGroup) hkeyGroups = hkeyCommonGroups; else hkeyGroups = hkeyProgramGroups;
if (pGroup->fRO || RegDeleteKey(hkeyGroups, pGroup->lpKey) != ERROR_SUCCESS) { MyMessageBox(hwndProgman, IDS_GROUPFILEERR, IDS_ERRORDELETEGROUP, pGroup->lpKey, MB_OK); //
// reset handling of Program Groups key changes.
//
ResetProgramGroupsEvent(bCommonGroup); bHandleProgramGroupsEvent = TRUE; return; // cannot delete the group
}
//
// reset handling of Program Groups key changes.
//
ResetProgramGroupsEvent(bCommonGroup); bHandleProgramGroupsEvent = TRUE;
/* Destroy the window, the global memory block, and the file. */ SendMessage(hwndMDIClient, WM_MDIDESTROY, (WPARAM)hwndGroup, 0L); NukeIconBitmap(pGroup); GlobalFree(pGroup->hGroup);
if (!bCommonGroup) {
//
// Remove the program manager's settings for that personal group.
//
wsprintf(szT,TEXT("Group%d"),pGroup->wIndex); RegDeleteValue(hkeyPMGroups, szT); }
/* Unlink the group structure. */ for (ppGroup=&pFirstGroup; *ppGroup && *ppGroup != pGroup; ppGroup = &(*ppGroup)->pNext) ;
if (*ppGroup) *ppGroup = pGroup->pNext;
if (pLastGroup == &pGroup->pNext) pLastGroup = ppGroup;
/* Destroying the window should activate another one, but if it is the
* last one, nothing will get activated, so to make sure punt the * current group pointer... */ if (pCurrentGroup == pGroup) pCurrentGroup = NULL;
/* Lastly, toss out the group and item structures. */ while (pGroup->pItems) { pItem = pGroup->pItems; pGroup->pItems = pItem->pNext; LocalFree((HANDLE)pItem); } LocalFree((HANDLE)pGroup->lpKey); LocalFree((HANDLE)pGroup);
if (!bCommonGroup) {
//
// Change the program manager's settings for that personal group.
//
WriteGroupsSection(); } }
/*--------------------------------------------------------------------------*/ /* */ /* ChangeGroupTitle() - */ /* */ /* Modifies the name of a program group, on the screen and in the file. */ /* */ /*--------------------------------------------------------------------------*/
VOID FAR PASCAL ChangeGroupTitle(HWND hwndGroup, LPTSTR lpName, BOOL bCommonGroup) { LPGROUPDEF lpgd; PGROUP pGroup; DWORD pName; TCHAR szCommonGroupSuffix[MAXKEYLEN]; TCHAR szCommonGroupTitle[2*MAXKEYLEN]; WINDOWPLACEMENT wp;
if (!hwndGroup) return;
//
// Change the title of the window.
//
if (bCommonGroup) {
//
// Add the common group suffix to the name of the group e.g. (Common),
// do not append the common suffix if the group window is minimized.
//
wp.length = sizeof(WINDOWPLACEMENT); GetWindowPlacement(hwndGroup, &wp); if (wp.showCmd == SW_MINIMIZE || wp.showCmd == SW_SHOWMINIMIZED || wp.showCmd == SW_SHOWMINNOACTIVE) { SetWindowText(hwndGroup, lpName); } else {
lstrcpy(szCommonGroupTitle, lpName); if (LoadString(hAppInstance, IDS_COMMONGRPSUFFIX, szCommonGroupSuffix, CharSizeOf(szCommonGroupSuffix))) { lstrcat(szCommonGroupTitle, szCommonGroupSuffix); } SetWindowText(hwndGroup, szCommonGroupTitle); } } else { SetWindowText(hwndGroup, lpName); }
//
// Remove the old name.
//
lpgd = LockGroup(hwndGroup); if (!lpgd) return;
DeleteThing(lpgd, (LPDWORD)&lpgd->pName, 0); UnlockGroup(hwndGroup);
//
// Insert the new one.
//
pGroup = (PGROUP)GetWindowLongPtr(hwndGroup,GWLP_PGROUP); pName = AddThing(pGroup->hGroup, lpName ,(WORD)0);
//
// Set the new offset...
//
if (lpgd = LockGroup(hwndGroup)) { lpgd->pName = pName; UnlockGroup(hwndGroup); }
}
/*--------------------------------------------------------------------------*/ /* */ /* SetGroupDimensions() - */ /* */ /* Saves the size and position of the group file in the group segment, as */ /* as well as the positions of all the item icons */ /* */ /*--------------------------------------------------------------------------*/
VOID NEAR PASCAL SetGroupDimensions(HWND hwndGroup) { LPGROUPDEF lpgd; LPITEMDEF lpid; PGROUP pGroup; PITEM pItem; WORD i;
lpgd = LockGroup(hwndGroup); if (!lpgd) return;
lpgd->nCmdShow = (WORD)GetInternalWindowPos(hwndGroup, &lpgd->rcNormal, &lpgd->ptMin);
pGroup = (PGROUP)GetWindowLongPtr(hwndGroup,GWLP_PGROUP); NukeIconBitmap(pGroup); // invalidate the bitmap
for (pItem=pGroup->pItems; pItem; pItem=pItem->pNext) { lpid = ITEM(lpgd,pItem->iItem); lpid->pt.x = pItem->rcIcon.left; lpid->pt.y = pItem->rcIcon.top;
/* save offset of ITEMDEF for each item
*/ ChangeTagID(lpgd,pItem->iItem,(int)lpgd->rgiItems[pItem->iItem]); pItem->iItem = (int)lpgd->rgiItems[pItem->iItem]; }
for (i=0, pItem=pGroup->pItems; pItem; pItem=pItem->pNext, i++) { /* write offsets back out in Z order and update the index
*/ ChangeTagID(lpgd,pItem->iItem,(int)i); lpgd->rgiItems[i] = (DWORD)pItem->iItem; pItem->iItem = (int)i; }
/* Clear out remaining pointers to prevent duped item wierdness. */ while (i < lpgd->cItems) lpgd->rgiItems[i++] = 0;
UnlockGroup(hwndGroup); }
/*--------------------------------------------------------------------------*/ /* */ /* WriteGroupsSection() - */ /* */ /*--------------------------------------------------------------------------*/
void PASCAL WriteGroupsSection(VOID) { PGROUP pGroup; HCURSOR hCursor; HWND hwndGroup; LPGROUPDEF lpgd; TCHAR szT[66]; TCHAR szOrd[CGROUPSMAX*8+7]; TCHAR szFmt[] = TEXT("Group%d"); TCHAR szFmtCommonGrp[] = TEXT("GroupC%d"); INT cGroups; TCHAR szGroupKey[MAXKEYLEN]; INT i; RECT rc; POINT ptMin; TCHAR szCGrpInfo[MAXKEYLEN]; INT cbValueName;
hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); ShowCursor(TRUE);
if (!(hwndGroup = GetWindow(hwndMDIClient, GW_CHILD))) { goto WPIExit; }
hwndGroup = GetWindow(hwndGroup, GW_HWNDLAST);
szOrd[0] = 0; cGroups = 0;
//
// Clear user's previous positioning of common groups.
//
if (hkeyPMCommonGroups) { cbValueName = CharSizeOf(szGroupKey); while (!RegEnumValue(hkeyPMCommonGroups, 0, szGroupKey, &cbValueName, 0, 0, 0, 0)) { RegDeleteValue(hkeyPMCommonGroups, szGroupKey); cbValueName = CharSizeOf(szGroupKey); } }
for (; hwndGroup; hwndGroup = GetWindow(hwndGroup, GW_HWNDPREV)) { /*
* Check to make sure we're not out of room for the order string. */ if (cGroups > CGROUPSMAX) { MessageBeep(0); break; }
if (GetWindow(hwndGroup, GW_OWNER)) { continue; }
pGroup = (PGROUP)GetWindowLongPtr(hwndGroup, GWLP_PGROUP);
if (!pGroup->lpKey || !*pGroup->lpKey) { if (pGroup->lpKey) { LocalFree((HANDLE)pGroup->lpKey); }
lpgd = LockGroup(hwndGroup); if (!lpgd) { continue; }
lstrcpy(szGroupKey, (LPTSTR) PTR(lpgd, lpgd->pName)); pGroup->lpKey = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR)*(lstrlen(szGroupKey) + 1)); lstrcpy(pGroup->lpKey, szGroupKey); UnlockGroup(hwndGroup); }
if (pGroup->fCommon) { wsprintf(szT, szFmtCommonGrp, pGroup->wIndex); lstrcat(szOrd, TEXT(" C")); lstrcat(szOrd, szT + CCHCOMMONGROUP); if (hkeyPMCommonGroups) { i = GetInternalWindowPos(hwndGroup, &rc, &ptMin);
if (i==SW_SHOWMINNOACTIVE) i = SW_SHOWNORMAL;
wsprintf(szCGrpInfo, TEXT("%d %d %d %d %d %d %d "), rc.left, rc.top, rc.right, rc.bottom, ptMin.x, ptMin.y, i); lstrcat(szCGrpInfo, pGroup->lpKey); RegSetValueEx(hkeyPMCommonGroups, szT, 0, REG_SZ, (LPBYTE)szCGrpInfo, sizeof(TCHAR)*(lstrlen(szCGrpInfo)+1)); } } else { wsprintf(szT, szFmt, pGroup->wIndex); lstrcat(szOrd, TEXT(" ")); lstrcat(szOrd, szT + CCHGROUP); if (hkeyPMGroups) { RegSetValueEx(hkeyPMGroups, szT, 0, REG_SZ, (LPBYTE)pGroup->lpKey, sizeof(TCHAR)*(lstrlen(pGroup->lpKey)+1)); } }
cGroups++; }
if (hkeyPMSettings) { RegSetValueEx(hkeyPMSettings, szOrder, 0, REG_SZ, (LPBYTE)szOrd, sizeof(TCHAR)*(lstrlen(szOrd) + 1)); }
WPIExit: ShowCursor(FALSE); SetCursor(hCursor); }
/*--------------------------------------------------------------------------*/ /* */ /* SaveGroupsContent() -
/*
/* Save the contents of the all the groups, doesn't save changes in
/* size or position if bSaveGroupSettings is FALSE, only the group items.
/* */ /*--------------------------------------------------------------------------*/
BOOL SaveGroupsContent(BOOL bSaveGroupSettings) { HWND hwndGroup;
hwndGroup = GetWindow(hwndMDIClient, GW_CHILD); if (!hwndGroup) return FALSE;
for (hwndGroup=GetWindow(hwndGroup, GW_HWNDLAST); hwndGroup; hwndGroup=GetWindow(hwndGroup, GW_HWNDPREV)) { if (GetWindow(hwndGroup, GW_OWNER)) continue;
/* Save the latest sizes and positions. */ if (bSaveGroupSettings) { SetGroupDimensions(hwndGroup); if (wLockError == LOCK_LOWMEM && !fLowMemErrYet) { // No more error messages.
fLowMemErrYet = TRUE; wLockError = 0; // Warn user that some settings couldn't be saved.
MyMessageBox(hwndProgman, IDS_OOMEXITTITLE, IDS_LOWMEMONEXIT, NULL, MB_OK | MB_ICONHAND | MB_SYSTEMMODAL); } }
SaveGroup(hwndGroup, TRUE); }
RegFlushKey(HKEY_CURRENT_USER);
return(TRUE); }
/*--------------------------------------------------------------------------*/ /* */ /* WriteINIFile() - */ /* */ /*--------------------------------------------------------------------------*/
void FAR PASCAL WriteINIFile() { register int i; RECT rc; TCHAR szT[40]; HANDLE hCursor;
//
// Don't save if restricted. But force save if we've just converted the
// ansi groups to unicode so we can work from unicode the next time around.
//
if (fNoSave && !bUseANSIGroups) return;
fLowMemErrYet = FALSE;
hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); ShowCursor(TRUE);
i = GetInternalWindowPos(hwndProgman, &rc, NULL);
if (i==SW_SHOWMINNOACTIVE) i = SW_SHOWNORMAL;
wsprintf(szT, TEXT("%d %d %d %d %d"), rc.left, rc.top, rc.right, rc.bottom, i); if (hkeyPMSettings) { RegSetValueEx(hkeyPMSettings, szWindow, 0, REG_SZ, (LPBYTE)szT, sizeof(TCHAR)*(lstrlen(szT)+ 1)); }
if (!bLoadEvil) WriteGroupsSection(); //
// Save all groups content, TRUE means we want the size and position saved
// as well.
//
SaveGroupsContent(TRUE);
ShowCursor(FALSE); SetCursor(hCursor); }
/*--------------------------------------------------------------------------*/ /* */ /* GetItemCommand() - */ /* */ /*--------------------------------------------------------------------------*/
void FAR PASCAL GetItemCommand( PGROUP pGroup, PITEM pItem, LPTSTR lpCommand, LPTSTR lpDir) { BYTE b=0; LPTSTR lp1, lp2, lp3; LPGROUPDEF lpgd; LPITEMDEF lpid; BOOL bNoFirstQuote = TRUE;
if (!GetGroupTag(pGroup,pItem,(WORD)ID_APPLICATIONDIR,lpCommand,MAXITEMPATHLEN)) { // the application directory is not defined
*lpCommand = 0; }
lpgd = LockGroup(pGroup->hwnd); if (!lpgd) { *lpCommand = 0; *lpDir = 0; return; } lpid = ITEM(lpgd,pItem->iItem);
// init working directory
lp3 = lpDir; *lp3 = 0;
// item command
lp1 = (LPTSTR) PTR(lpgd, lpid->pCommand); if (*lp1 == TEXT('"')) { lp2 = lp1; while (lp2 && (lp2 = wcschr(lp2+1, TEXT('"'))) && *(lp2+1) != TEXT('\\')) { //go to next quote
; } if (!lp2) { //
// The directory is not in quotes and since the command path starts
// with a quote, there's no working directory.
//
lp2 = lpDir; *lp2 = 0; } else { if (*(lp2+1) == TEXT('\\')) { //
// the working directory is in quotes
//
*lp3++ = *lp1++; //write first quote
for (; *lp1 && lp1 != lp2; lp1 = CharNext(lp1)) { *lp3++ = *lp1; } if (*lp1 == TEXT('"')) { *lp3++ = *lp1++; //write last quote
lp1++; *lp3 = 0; } } lp2 = lp3 + lstrlen(lp3); } } else { //
// if there's a working directory, it is not in quotes
//
for (lp2 = lp3 = lpDir; *lp1 && *lp1 != TEXT(' ') && *lp1 != TEXT('"'); // the command line might be in quotes
lp1 = CharNext(lp1)) {
*lp3++ = *lp1;
if (*lp1 == TEXT(':') || *lp1 == TEXT('\\')) lp2 = lp3; } *lp3 = 0; }
/* we are assuming the exe dir contains the necessary separator
* add the filename to the command line */ lstrcat(lpCommand,lp2); /* add the arguments to the command line
*/ lstrcat(lpCommand,lp1);
/* truncate the command name from the exe path. note this implies
* that if there is no path, lpDir will be empty */ *lp2 = 0; lp2 = CharPrev(lpDir,lp2); if (*lp2 == TEXT('\\') && *CharPrev(lpDir,lp2) != TEXT(':')) *lp2 = 0;
UnlockGroup(pGroup->hwnd); }
/*--------------------------------------------------------------------------*/ /* */ /* DuplicateItem() - */ /* */ /*--------------------------------------------------------------------------*/
PITEM PASCAL DuplicateItem( PGROUP pGroup, PITEM pItem, PGROUP pGNew, LPPOINT lppt) { WORD wIconId; WORD wIconIndex; LPITEMDEF lpid; LPGROUPDEF lpgd; TCHAR szCommand[MAXITEMPATHLEN + 1]; TCHAR szDefDir[2 * (MAXITEMPATHLEN + 1)]; TCHAR szIconPath[MAXITEMPATHLEN + 1]; TCHAR szName[64]; TCHAR szExpPath[MAXITEMPATHLEN+1]; TCHAR szExpDir[MAXITEMPATHLEN+1]; DWORD dwFlags = CI_ACTIVATE;
lpid = LockItem(pGroup, pItem); if (lpid == 0L) { UnlockGroup(pGroup->hwnd); return NULL; }
lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
lstrcpy(szName, (LPTSTR) PTR(lpgd, lpid->pName)); lstrcpy(szIconPath, (LPTSTR) PTR(lpgd, lpid->pIconPath)); wIconId = lpid->iIcon; wIconIndex = lpid->wIconIndex; GlobalUnlock(pGroup->hGroup); UnlockGroup(pGroup->hwnd);
GetItemCommand(pGroup, pItem, szCommand, szDefDir);
//
// I f there's no icon path, check if we have an executable associated
// with the command path.
//
if (!*szIconPath) { lstrcpy(szExpPath, szCommand); DoEnvironmentSubst(szExpPath, CharSizeOf(szExpPath)); StripArgs(szExpPath); lstrcpy(szExpDir, szDefDir); DoEnvironmentSubst(szExpDir, CharSizeOf(szExpDir)); FindExecutable(szExpPath, szExpDir, szIconPath); if (!*szIconPath) { dwFlags |= CI_NO_ASSOCIATION; } else *szIconPath = 0; } if (GroupFlag(pGroup, pItem, (WORD)ID_NEWVDM)) { dwFlags |= CI_SEPARATE_VDM; }
return CreateNewItem(pGNew->hwnd, szName, szCommand, szIconPath, szDefDir, GroupFlag(pGroup, pItem, (WORD)ID_HOTKEY), GroupFlag(pGroup, pItem, (WORD)ID_MINIMIZE), wIconId, wIconIndex, NULL, lppt, dwFlags); }
|