955 lines
23 KiB
C
955 lines
23 KiB
C
/****************************** 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 */
|
|
|