/****************************** Module Header ******************************\ * Module Name: DMGDB.C * * DDE manager data handling routines * * Created: 12/14/88 Sanford Staab * * Copyright (c) 1988, 1989 Microsoft Corporation \***************************************************************************/ #include "ddemlp.h" /***************************** Private Function ****************************\ * PAPPINFO GetCurrentAppInfo() * * DESCRIPTION: * This routine uses the pid of the current thread to locate the information * pertaining to that thread. If not found, 0 is returned. * * This call fails if the DLL is in a callback state to prevent recursion. * if fChkCallback is set. * * History: 1/1/89 Created sanfords \***************************************************************************/ PAPPINFO GetCurrentAppInfo( PAPPINFO paiStart) { register PAPPINFO pai; HANDLE hTaskCurrent; SEMENTER(); if (pAppInfoList == NULL) { SEMLEAVE(); return(0); } pai = paiStart ? paiStart->next : pAppInfoList; hTaskCurrent = GetCurrentTask(); while (pai) { if (pai->hTask == hTaskCurrent) { SEMLEAVE(); return(pai); } pai = pai->next; } SEMLEAVE(); return(0); } /***************************** Private Function ****************************\ * void UnlinkAppInfo(pai) * PAPPINFO pai; * * DESCRIPTION: * unlinks an pai safely. Does nothing if not linked. * * History: 1/1/89 Created sanfords \***************************************************************************/ void UnlinkAppInfo(pai) PAPPINFO pai; { PAPPINFO paiT; AssertF(pai != NULL, "UnlinkAppInfo - NULL input"); SEMENTER(); if (pai == pAppInfoList) { pAppInfoList = pai->next; SEMLEAVE(); return; } paiT = pAppInfoList; while (paiT && paiT->next != pai) paiT = paiT->next; if (paiT) paiT->next = pai->next; SEMLEAVE(); return; } /***************************** Private Functions ***************************\ * General List management functions. * * History: * Created 12/15/88 sanfords \***************************************************************************/ PLST CreateLst(hheap, cbItem) HANDLE hheap; WORD cbItem; { PLST pLst; SEMENTER(); if (!(pLst = (PLST)FarAllocMem(hheap, sizeof(LST)))) { SEMLEAVE(); return(NULL); } pLst->hheap = hheap; pLst->cbItem = cbItem; pLst->pItemFirst = (PLITEM)NULL; SEMLEAVE(); return(pLst); } void DestroyLst(pLst) PLST pLst; { if (pLst == NULL) return; SEMENTER(); while (pLst->pItemFirst) RemoveLstItem(pLst, pLst->pItemFirst); FarFreeMem((LPSTR)pLst); SEMLEAVE(); } void DestroyAdvLst(pLst) PLST pLst; { if (pLst == NULL) return; SEMENTER(); while (pLst->pItemFirst) { FreeHsz(((PADVLI)(pLst->pItemFirst))->aItem); RemoveLstItem(pLst, pLst->pItemFirst); } FarFreeMem((LPSTR)pLst); SEMLEAVE(); } PLITEM FindLstItem(pLst, npfnCmp, piSearch) PLST pLst; NPFNCMP npfnCmp; PLITEM piSearch; { PLITEM pi; if (pLst == NULL) return(NULL); SEMENTER(); pi = pLst->pItemFirst; while (pi) { if ((*npfnCmp)((LPBYTE)pi + sizeof(LITEM), (LPBYTE)piSearch + sizeof(LITEM))) { SEMLEAVE(); return(pi); } pi = pi->next; } SEMLEAVE(); return(pi); } /* * Comparison functions for FindLstItem() and FindPileItem() */ BOOL CmpDWORD(pb1, pb2) LPBYTE pb1; LPBYTE pb2; { return(*(LPDWORD)pb1 == *(LPDWORD)pb2); } BOOL CmpWORD(pb1, pb2) LPBYTE pb1; LPBYTE pb2; { return(*(LPWORD)pb1 == *(LPWORD)pb2); } BOOL CmpHIWORD(pb1, pb2) LPBYTE pb1; LPBYTE pb2; { return(*(LPWORD)(pb1 + 2) == *(LPWORD)(pb2 + 2)); } /***************************** Private Function ****************************\ * This routine creates a new list item for pLst and links it in according * to the ILST_ constant in afCmd. Returns a pointer to the new item * or NULL on failure. * * Note: This MUST be in the semaphore for use since the new list item * is filled with garbage on return yet is linked in. * * * History: * Created 9/12/89 Sanfords \***************************************************************************/ PLITEM NewLstItem(pLst, afCmd) PLST pLst; WORD afCmd; { PLITEM pi, piT; if (pLst == NULL) return(NULL); SEMCHECKIN(); pi = (PLITEM)FarAllocMem(pLst->hheap, pLst->cbItem + sizeof(LITEM)); if (pi == NULL) { AssertF(FALSE, "NewLstItem - memory failure"); return(NULL); } if (afCmd & ILST_NOLINK) return(pi); if (((piT = pLst->pItemFirst) == NULL) || (afCmd & ILST_FIRST)) { pi->next = piT; pLst->pItemFirst = pi; } else { /* ILST_LAST assumed */ while (piT->next != NULL) piT = piT->next; piT->next = pi; pi->next = NULL; } return(pi); } /***************************** Private Function ****************************\ * This routine unlinks and frees pi from pLst. If pi cannot be located * within pLst, it is freed anyway. * * History: * Created 9/12/89 Sanfords \***************************************************************************/ BOOL RemoveLstItem(pLst, pi) PLST pLst; PLITEM pi; { PLITEM piT; if (pLst == NULL || pi == NULL) return(FALSE); SEMCHECKIN(); if ((piT = pLst->pItemFirst) != NULL) { if (pi == piT) { pLst->pItemFirst = pi->next; } else { while (piT->next != pi && piT->next != NULL) piT = piT->next; if (piT->next != NULL) piT->next = pi->next; /* unlink */ } } else { AssertF(FALSE, "Improper list item removal"); return(FALSE); } FarFreeMem((LPSTR)pi); return(TRUE); } /* * ------------- Specific list routines ------------- */ /***************************** Private Function ****************************\ * hwnd-hsz list functions * * History: 1/20/89 Created sanfords \***************************************************************************/ void AddHwndHszList( ATOM a, HWND hwnd, PLST pLst) { PHWNDHSZLI phhi; AssertF(pLst->cbItem == sizeof(HWNDHSZLI), "AddHwndHszList - Bad item size"); SEMENTER(); if (!a || (BOOL)HwndFromHsz(a, pLst)) { SEMLEAVE(); return; } phhi = (PHWNDHSZLI)NewLstItem(pLst, ILST_FIRST); phhi->hwnd = hwnd; phhi->a = a; IncHszCount(a); // structure copy SEMLEAVE(); } void DestroyHwndHszList(pLst) PLST pLst; { if (pLst == NULL) return; AssertF(pLst->cbItem == sizeof(HWNDHSZLI), "DestroyHwndHszList - Bad item size"); SEMENTER(); while (pLst->pItemFirst) { FreeHsz(((PHWNDHSZLI)pLst->pItemFirst)->a); RemoveLstItem(pLst, pLst->pItemFirst); } FarFreeMem((LPSTR)pLst); SEMLEAVE(); } HWND HwndFromHsz( ATOM a, PLST pLst) { HWNDHSZLI hhli; PHWNDHSZLI phhli; hhli.a = a; if (!(phhli = (PHWNDHSZLI)FindLstItem(pLst, CmpWORD, (PLITEM)&hhli))) return(NULL); return(phhli->hwnd); } /***************************** Private Function ****************************\ * DESCRIPTION: * Advise list helper functions. * * History: 1/20/89 Created sanfords \***************************************************************************/ /* * This will match an exact hsz/fmt pair with a 0 format or 0 item or 0 hwnd * being wild. */ BOOL CmpAdv( LPBYTE pb1, // entry being compared LPBYTE pb2) // search for { PADVLI pali1 = (PADVLI)(pb1 - sizeof(LITEM)); PADVLI pali2 = (PADVLI)(pb2 - sizeof(LITEM)); if (pali2->aTopic == 0 || pali1->aTopic == pali2->aTopic) { if (pali2->hwnd == 0 || pali1->hwnd == pali2->hwnd) { if (pali2->aItem == 0 || pali1->aItem == pali2->aItem ) { if (pali2->wFmt == 0 || pali1->wFmt == pali2->wFmt) { return(TRUE); } } } } return(FALSE); } WORD CountAdvReqLeft( PADVLI pali) { ADVLI aliKey; register WORD cLoops = 0; SEMENTER(); aliKey = *pali; aliKey.hwnd = 0; // all hwnds pali = (PADVLI)aliKey.next; while (pali) { if (CmpAdv(((LPBYTE)pali) + sizeof(LITEM), ((LPBYTE)&aliKey) + sizeof(LITEM))) { cLoops++; } pali = (PADVLI)pali->next; } SEMLEAVE(); return(cLoops); } BOOL AddAdvList( PLST pLst, HWND hwnd, ATOM aTopic, ATOM aItem, WORD fsStatus, WORD wFmt) { PADVLI pali; AssertF(pLst->cbItem == sizeof(ADVLI), "AddAdvList - bad item size"); if (!aItem) return(TRUE); SEMENTER(); if (!(pali = FindAdvList(pLst, hwnd, aTopic, aItem, wFmt))) { IncHszCount(aItem); // structure copy pali = (PADVLI)NewLstItem(pLst, ILST_FIRST); } AssertF((BOOL)(DWORD)pali, "AddAdvList - NewLstItem() failed") if (pali != NULL) { pali->aItem = aItem; pali->aTopic = aTopic; pali->wFmt = wFmt; pali->fsStatus = fsStatus; pali->hwnd = hwnd; } SEMLEAVE(); return((BOOL)(DWORD)pali); } /* * This will delete the matching Advise loop entry. If wFmt is 0, all * entries with the same hszItem are deleted. * Returns fNotEmptyAfterDelete. */ BOOL DeleteAdvList( PLST pLst, HWND hwnd, ATOM aTopic, ATOM aItem, WORD wFmt) { PADVLI pali; AssertF(pLst->cbItem == sizeof(ADVLI), "DeleteAdvList - bad item size"); SEMENTER(); while (pali = (PADVLI)FindAdvList(pLst, hwnd, aTopic, aItem, wFmt)) { FreeHsz(pali->aItem); RemoveLstItem(pLst, (PLITEM)pali); } SEMLEAVE(); return((BOOL)(DWORD)pLst->pItemFirst); } /***************************** Private Function ****************************\ * This routine searches the advise list for and entry in hszItem. It returns * pAdvli only if the item is found. * * History: * Created 9/12/89 Sanfords \***************************************************************************/ PADVLI FindAdvList( PLST pLst, HWND hwnd, ATOM aTopic, ATOM aItem, WORD wFmt) { ADVLI advli; AssertF(pLst->cbItem == sizeof(ADVLI), "FindAdvList - bad item size"); advli.aItem = aItem; advli.aTopic = aTopic; advli.wFmt = wFmt; advli.hwnd = hwnd; return((PADVLI)FindLstItem(pLst, CmpAdv, (PLITEM)&advli)); } /***************************** Private Function ****************************\ * This routine searches for the next entry for hszItem. It returns * pAdvli only if the item is found. aTopic and hwnd should NOT be 0. * * History: * Created 11/15/89 Sanfords \***************************************************************************/ PADVLI FindNextAdv( PADVLI padvli, HWND hwnd, ATOM aTopic, ATOM aItem) { SEMENTER(); while ((padvli = (PADVLI)padvli->next) != NULL) { if (hwnd == 0 || hwnd == padvli->hwnd) { if (aTopic == 0 || aTopic == padvli->aTopic) { if (aItem == 0 || padvli->aItem == aItem) { break; } } } } SEMLEAVE(); return(padvli); } /***************************** Private Function ****************************\ * This routine removes all list items associated with hwnd. * * History: * Created 4/17/91 Sanfords \***************************************************************************/ VOID CleanupAdvList( HWND hwnd, PCLIENTINFO pci) { PADVLI pali, paliNext; PLST plst; if (pci->ci.fs & ST_CLIENT) { plst = pci->pClientAdvList; } else { plst = pci->ci.pai->pServerAdvList; } AssertF(plst->cbItem == sizeof(ADVLI), "CleanupAdvList - bad item size"); SEMENTER(); for (pali = (PADVLI)plst->pItemFirst; pali; pali = paliNext) { paliNext = (PADVLI)pali->next; if (pali->hwnd == hwnd) { MONLINK(pci->ci.pai, FALSE, pali->fsStatus & DDE_FDEFERUPD, (HSZ)pci->ci.aServerApp, (HSZ)pci->ci.aTopic, (HSZ)pali->aItem, pali->wFmt, (pci->ci.fs & ST_CLIENT) ? FALSE : TRUE, (pci->ci.fs & ST_CLIENT) ? pci->ci.hConvPartner : MAKEHCONV(hwnd), (pci->ci.fs & ST_CLIENT) ? MAKEHCONV(hwnd) : pci->ci.hConvPartner); FreeHsz(pali->aItem); RemoveLstItem(plst, (PLITEM)pali); } } SEMLEAVE(); } /***************************** Pile Functions ********************************\ * * A pile is a list where each item is an array of subitems. This allows * a more memory efficient method of handling unordered lists. * \*****************************************************************************/ PPILE CreatePile(hheap, cbItem, cItemsPerBlock) HANDLE hheap; WORD cbItem; WORD cItemsPerBlock; { PPILE ppile; if (!(ppile = (PPILE)FarAllocMem(hheap, sizeof(PILE)))) { SEMLEAVE(); return(NULL); } ppile->pBlockFirst = NULL; ppile->hheap = hheap; ppile->cbBlock = cbItem * cItemsPerBlock + sizeof(PILEB); ppile->cSubItemsMax = cItemsPerBlock; ppile->cbSubItem = cbItem; return(ppile); } PPILE DestroyPile(pPile) PPILE pPile; { if (pPile == NULL) return(NULL); SEMENTER(); while (pPile->pBlockFirst) RemoveLstItem((PLST)pPile, (PLITEM)pPile->pBlockFirst); FarFreeMem((LPSTR)pPile); SEMLEAVE(); return(NULL); } WORD QPileItemCount(pPile) PPILE pPile; { register WORD c; PPILEB pBlock; if (pPile == NULL) return(0); SEMENTER(); pBlock = pPile->pBlockFirst; c = 0; while (pBlock) { c += pBlock->cItems; pBlock = pBlock->next; } SEMLEAVE(); return(c); } /***************************** Private Function ****************************\ * Locate and return the pointer to the pile subitem who's key fields match * pbSearch using npfnCmp to compare the fields. If pbSearch == NULL, or * npfnCmp == NULL, the first subitem is returned. * * afCmd may be: * FPI_DELETE - delete the located item * In this case, the returned pointer is not valid. * * pppb points to where to store a pointer to the block which contained * the located item. * * if pppb == NULL, it is ignored. * * NULL is returned if pbSearch was not found or if the list was empty. * * History: * Created 9/12/89 Sanfords \***************************************************************************/ LPBYTE FindPileItem(pPile, npfnCmp, pbSearch, afCmd) PPILE pPile; NPFNCMP npfnCmp; LPBYTE pbSearch; WORD afCmd; { LPBYTE psi; // subitem pointer. PPILEB pBlockCur; // current block pointer. register WORD i; if (pPile == NULL) return(NULL); SEMENTER(); pBlockCur = pPile->pBlockFirst; /* * while this block is not the end... */ while (pBlockCur) { for (psi = (LPBYTE)pBlockCur + sizeof(PILEB), i = 0; i < pBlockCur->cItems; psi += pPile->cbSubItem, i++) { if (pbSearch == NULL || npfnCmp == NULL || (*npfnCmp)(psi, pbSearch)) { if (afCmd & FPI_DELETE) { /* * remove entire block if this was the last subitem in it. */ if (--pBlockCur->cItems == 0) { RemoveLstItem((PLST)pPile, (PLITEM)pBlockCur); } else { /* * copy last subitem in the block over the removed item. */ hmemcpy(psi, (LPBYTE)pBlockCur + sizeof(PILEB) + pPile->cbSubItem * pBlockCur->cItems, pPile->cbSubItem); } } return(psi); // found } } pBlockCur = (PPILEB)pBlockCur->next; } SEMLEAVE(); return(NULL); // not found. } /***************************** Private Function ****************************\ * Places a copy of the subitem pointed to by pb into the first available * spot in the pile pPile. If npfnCmp != NULL, the pile is first searched * for a pb match. If found, pb replaces the located data. * * Returns: * API_FOUND if already there * API_ERROR if an error happened * API_ADDED if not found and added * * History: * Created 9/12/89 Sanfords \***************************************************************************/ WORD AddPileItem(pPile, pb, npfnCmp) PPILE pPile; LPBYTE pb; BOOL (*npfnCmp)(LPBYTE pbb, LPBYTE pbSearch); { LPBYTE pbDst; PPILEB ppb; if (pPile == NULL) return(FALSE); SEMENTER(); if (npfnCmp != NULL && (pbDst = FindPileItem(pPile, npfnCmp, pb, 0)) != NULL) { hmemcpy(pbDst, pb, pPile->cbSubItem); SEMLEAVE(); return(API_FOUND); } ppb = pPile->pBlockFirst; /* * locate a block with room */ while ((ppb != NULL) && ppb->cItems == pPile->cSubItemsMax) { ppb = (PPILEB)ppb->next; } /* * If all full or no blocks, make a new one, link it on the bottom. */ if (ppb == NULL) { ppb = (PPILEB)NewLstItem((PLST)pPile, ILST_LAST); if (ppb == NULL) { SEMLEAVE(); return(API_ERROR); } ppb->cItems = 0; } /* * add the subitem */ hmemcpy((LPBYTE)ppb + sizeof(PILEB) + pPile->cbSubItem * ppb->cItems++, pb, pPile->cbSubItem); SEMLEAVE(); return(API_ADDED); } /***************************** Private Function ****************************\ * Fills pb with a copy of the top item's data and removes it from the pile. * returns FALSE if the pile was empty. * * History: * Created 9/12/89 Sanfords \***************************************************************************/ BOOL PopPileSubitem(pPile, pb) PPILE pPile; LPBYTE pb; { PPILEB ppb; LPBYTE pSrc; if ((pPile == NULL) || ((ppb = pPile->pBlockFirst) == NULL)) return(FALSE); SEMENTER(); pSrc = (LPBYTE)pPile->pBlockFirst + sizeof(PILEB); hmemcpy(pb, pSrc, pPile->cbSubItem); /* * remove entire block if this was the last subitem in it. */ if (pPile->pBlockFirst->cItems == 1) { RemoveLstItem((PLST)pPile, (PLITEM)pPile->pBlockFirst); } else { /* * move last item in block to replace copied subitem and decrement * subitem count. */ hmemcpy(pSrc, pSrc + pPile->cbSubItem * --pPile->pBlockFirst->cItems, pPile->cbSubItem); } SEMLEAVE(); return(TRUE); } #if 0 /***************************** Semaphore Functions *************************\ * SEMENTER() and SEMLEAVE() are macros. * * History: 1/1/89 Created sanfords \***************************************************************************/ void SemInit() { LPBYTE pSem; SHORT c; pSem = (LPBYTE) & FSRSemDmg; c = 0; while (c++ < sizeof(DOSFSRSEM)) { *pSem++ = 0; } FSRSemDmg.cb = sizeof(DOSFSRSEM); } void SemCheckIn() { PIDINFO pi; BOOL fin; DosGetPID(&pi); fin = (FSRSemDmg.cUsage > 0) && (FSRSemDmg.pid == pi.pid) && ((FSRSemDmg.tid == pi.tid) || (FSRSemDmg.tid == -1)); /* * !!! NOTE: during exitlists processing, semaphore TIDs are set to -1 */ AssertF(fin, "SemCheckIn - Out of Semaphore"); if (!fin) SEMENTER(); } void SemCheckOut() { PIDINFO pi; BOOL fOut; DosGetPID(&pi); fOut = FSRSemDmg.cUsage == 0 || FSRSemDmg.pid != pi.pid || FSRSemDmg.tid != pi.tid; AssertF(fOut, "SemCheckOut - In Semaphore"); if (!fOut) while (FSRSemDmg.cUsage) SEMLEAVE(); } void SemEnter() { DosFSRamSemRequest(&FSRSemDmg, SEM_INDEFINITE_WAIT); } void SemLeave() { DosFSRamSemClear(&FSRSemDmg); } #endif // 0 BOOL CopyHugeBlock(pSrc, pDst, cb) LPBYTE pSrc; LPBYTE pDst; DWORD cb; { DWORD cFirst; /* * |____________| |___________| |____________| |____________| * ^src ^ * * |____________| |___________| |____________| |____________| * ^dst ^ */ /* * The following check determines whether the copy can be done * in one short copy operation. Checks whether the byte count * is small enough to span the bytes to the right of the greater * of pSrc and pDst. */ cFirst = (DWORD)min(~LOWORD((DWORD)pSrc), ~LOWORD((DWORD)pDst)) + 1L; /* cFirst is # of bytes to end of seg, for buffer w/ biggest offset */ if (cb < cFirst) { hmemcpy(pDst, pSrc, (WORD)cb); return(TRUE); } goto copyit; /* if not, jump into while loop */ /* * Now at least one of the pointers is on a segment boundry. */ while (cb) { cFirst = min(0x10000 - (LOWORD((DWORD)pSrc) | LOWORD((DWORD)pDst)), (LONG)cb); copyit: if (HIWORD(cFirst)) { /* * special case where pSrc and pDst both are on segment * bounds. Copy half at a time. First half first. */ /* * |___________| |____________| |____________| * ^src ^ * * |___________| |____________| |____________| * ^dst ^ */ cFirst >>= 1; /* half the span */ hmemcpy(pDst, pSrc, (WORD)cFirst); pSrc += cFirst; /* inc ptrs */ pDst += cFirst; cb -= cFirst; /* dec bytecount */ } hmemcpy(pDst, pSrc, (WORD)cFirst); pSrc = HugeOffset(pSrc, cFirst); pDst = HugeOffset(pDst, cFirst); cb -= cFirst; /* * |____________| |___________| |____________| |____________| * ^src ^ * * |____________| |___________| |____________| |____________| * ^dst ^ */ } return(TRUE); } /***************************************************************************\ * Kills windows but avoids invalid window rips in debugger. \***************************************************************************/ BOOL DmgDestroyWindow(hwnd) HWND hwnd; { if (IsWindow(hwnd)) return(DestroyWindow(hwnd)); return(TRUE); } BOOL ValidateHConv( HCONV hConv) { return(IsWindow((HWND)hConv) && GetWindowWord((HWND)hConv, GWW_CHECKVAL) == HIWORD(hConv)); } #ifdef DEBUG void _loadds fAssert( BOOL f, LPSTR pszComment, WORD line, LPSTR szfile, BOOL fWarning) { char szT[90]; if (!f) { wsprintf(szT, "\n\rAssertion failure: %s:%d %s\n\r", szfile, line, pszComment); OutputDebugString((LPSTR)szT); if (!fWarning) DEBUGBREAK(); } } #endif /* DEBUG */