home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / os2sdk / os2sdk12 / ddeml / dmgdb.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-06-22  |  28.9 KB  |  1,163 lines

  1. /****************************** Module Header ******************************\
  2. * Module Name: DMGDB.C
  3. *
  4. * DDE manager data handling routines
  5. *
  6. * Created: 12/14/88 Sanford Staab
  7. *
  8. * Copyright (c) 1988, 1989  Microsoft Corporation
  9. \***************************************************************************/
  10. #include "ddemlp.h"
  11.  
  12. /***************************** Private Function ****************************\
  13. * PAPPINFO GetCurrentAppInfo()
  14. *
  15. * DESCRIPTION:
  16. * This routine uses the pid of the current thread to locate the information
  17. * pertaining to that thread.  If not found, 0 is returned.
  18. *
  19. * This call fails if the DLL is in a callback state to prevent recursion.
  20. * if fChkCallback is set.
  21. *
  22. * History:      1/1/89  Created         sanfords
  23. \***************************************************************************/
  24. PAPPINFO GetCurrentAppInfo(fChkCallback)
  25. BOOL fChkCallback;
  26. {
  27.     PAPPINFO pai;
  28.  
  29.     SemEnter();
  30.     if (pAppInfoList == NULL || !CheckSel(SELECTOROF(pAppInfoList))) {
  31.         SemLeave();
  32.         return(0);
  33.     }
  34.     pai = pAppInfoList;
  35.     while (pai) {
  36.         if (pai->pid == FSRSemDmg.pid && pai->tid == FSRSemDmg.tid) {
  37.             if (fChkCallback && pai->cInCallback > MAX_RECURSE) {
  38.                 pai->LastError = DMGERR_REENTRANCY;
  39.                 break;
  40.             } else {
  41.                 SemLeave();
  42.                 return(pai);
  43.             }
  44.         }
  45.         pai = pai->next;
  46.     }
  47.     SemLeave();
  48.     return(0);
  49. }
  50.  
  51.  
  52. /***************************** Private Function ****************************\
  53. * void UnlinkAppInfo(pai)
  54. * PAPPINFO pai;
  55. *
  56. * DESCRIPTION:
  57. *   unlinks an pai safely.  Does nothing if not linked.
  58. *
  59. * History:      1/1/89  Created         sanfords
  60. \***************************************************************************/
  61. void UnlinkAppInfo(pai)
  62. PAPPINFO pai;
  63. {
  64.     PAPPINFO paiT;
  65.  
  66.     AssertF(pai != NULL, "UnlinkAppInfo - NULL input");
  67.     SemEnter();
  68.     if (pai == pAppInfoList) {
  69.         pAppInfoList = pai->next;
  70.         SemLeave();
  71.         return;
  72.     }
  73.     paiT = pAppInfoList;
  74.     while (paiT && paiT->next != pai)
  75.         paiT = paiT->next;
  76.     if (paiT)
  77.         paiT->next = pai->next;
  78.     SemLeave();
  79.     return;
  80. }
  81.  
  82.  
  83.  
  84.  
  85.  
  86. /***************************** Private Functions ***************************\
  87. * General List management functions.
  88. *
  89. * History:
  90. *   Created     12/15/88    sanfords
  91. \***************************************************************************/
  92. PLST CreateLst(hheap, cbItem)
  93. HHEAP hheap;
  94. USHORT cbItem;
  95. {
  96.     PLST pLst;
  97.  
  98.     SemEnter();
  99.     if (!(pLst = (PLST)FarAllocMem(hheap, sizeof(LST)))) {
  100.         SemLeave();
  101.         return(NULL);
  102.     }
  103.     pLst->hheap = hheap;
  104.     pLst->cbItem = cbItem;
  105.     pLst->pItemFirst = (PLITEM)NULL;
  106.     SemLeave();
  107.     return(pLst);
  108. }
  109.  
  110.  
  111.  
  112. void FlushLst(pLst)
  113. PLST pLst;
  114. {
  115.     if (pLst == NULL)
  116.         return;
  117.     SemEnter();
  118.     while (pLst->pItemFirst) 
  119.         RemoveLstItem(pLst, pLst->pItemFirst);
  120.     SemLeave();
  121. }
  122.  
  123.  
  124.  
  125. void DestroyLst(pLst)
  126. PLST pLst;
  127. {
  128.     if (pLst == NULL)
  129.         return;
  130.     SemEnter();
  131.     while (pLst->pItemFirst) 
  132.         RemoveLstItem(pLst, pLst->pItemFirst);
  133.     FarFreeMem(pLst->hheap, pLst, sizeof(LST));
  134.     SemLeave();
  135. }
  136.  
  137.  
  138.  
  139. PLITEM FindLstItem(pLst, npfnCmp, piSearch)
  140. PLST pLst;
  141. NPFNCMP npfnCmp;
  142. PLITEM piSearch;
  143. {
  144.     PLITEM pi;
  145.  
  146.     if (pLst == NULL)
  147.         return(NULL);
  148.     SemEnter();
  149.     pi = pLst->pItemFirst;
  150.     while (pi) {
  151.         if ((*npfnCmp)
  152.                 ((PBYTE)pi + sizeof(LITEM), (PBYTE)piSearch + sizeof(LITEM))) {
  153.             SemLeave();
  154.             return(pi);
  155.         }
  156.         pi = pi->next;
  157.     }
  158.     SemLeave();
  159. }
  160.  
  161.  
  162.  
  163. /*
  164.  * Comparison functions for FindLstItem() and FindPileItem()
  165.  */
  166.  
  167. BOOL CmpULONG(pb1, pb2)
  168. PBYTE pb1;
  169. PBYTE pb2;
  170. {
  171.     return(*(PULONG)pb1 == *(PULONG)pb2);
  172. }
  173.  
  174. BOOL CmppHsz(pb1, pb2)
  175. PBYTE pb1;
  176. PBYTE pb2;
  177. {
  178.     return(CmpHsz(*(PHSZ)pb1, *(PHSZ)pb2) ? FALSE : TRUE);
  179. }
  180.  
  181.  
  182.  
  183.  
  184. /***************************** Private Function ****************************\
  185. * This routine creates a new list item for pLst and links it in according
  186. * to the ILST_ constant in afCmd.  Returns a pointer to the new item
  187. * or NULL on failure.
  188. *
  189. * Note:  This MUST be in the semaphore for use since the new list item
  190. * is filled with garbage on return yet is linked in.  
  191. *
  192. * History:
  193. *   Created     9/12/89    Sanfords
  194. \***************************************************************************/
  195. PLITEM NewLstItem(pLst, afCmd)
  196. PLST pLst;
  197. USHORT afCmd;
  198. {
  199.     PLITEM pi, piT;
  200.  
  201.     if (pLst == NULL)
  202.         return(NULL);
  203.     SemCheckIn();
  204.     
  205.     pi = (PLITEM)FarAllocMem(pLst->hheap, pLst->cbItem + sizeof(LITEM));
  206.     if (pi == NULL) {
  207.         AssertF(FALSE, "NewLstItem - memory failure");    
  208.         return(NULL);
  209.     }
  210.  
  211.     if (afCmd & ILST_NOLINK) 
  212.         return(pi);
  213.         
  214.     if (((piT = pLst->pItemFirst) == NULL) || (afCmd & ILST_FIRST)) {
  215.         pi->next = piT;
  216.         pLst->pItemFirst = pi;
  217.     } else {                            /* ILST_LAST assumed */
  218.         while (piT->next != NULL) 
  219.             piT = piT->next;
  220.         piT->next = pi;
  221.         pi->next = NULL;
  222.     }
  223.     return(pi);
  224. }
  225.  
  226.  
  227.  
  228. /***************************** Private Function ****************************\
  229. * This routine unlinks and frees pi from pLst.  If pi cannot be located
  230. * within pLst, it is freed anyway.
  231. *
  232. * History:
  233. *   Created     9/12/89    Sanfords
  234. \***************************************************************************/
  235. BOOL RemoveLstItem(pLst, pi)
  236. PLST pLst;
  237. PLITEM pi;
  238. {
  239.     PLITEM piT;
  240.  
  241.     if (pLst == NULL || pi == NULL)
  242.         return(FALSE);
  243.         
  244.     SemCheckIn();
  245.     
  246.     if ((piT = pLst->pItemFirst) != NULL) {
  247.         if (pi == piT) {
  248.             pLst->pItemFirst = pi->next;
  249.         } else {
  250.             while (piT->next != pi && piT->next != NULL)
  251.                 piT = piT->next;
  252.             if (piT->next != NULL)
  253.                 piT->next = pi->next; /* unlink */
  254.         }
  255.     } else {
  256.         AssertF(pi == NULL, "Improper list item removal");
  257.     }
  258.     FarFreeMem(pLst->hheap, pi, pLst->cbItem + sizeof(LITEM));
  259.     return(TRUE);
  260. }
  261.  
  262.  
  263.  
  264. /***************************** Private Function ****************************\
  265. * This routine uses ILST_ constants to insert a list item into the apropriate
  266. * spot of the pLst given.  Only ILST_FIRST or ILST_LAST are allowed.
  267. *
  268. * History:
  269. *   Created     9/11/89    Sanfords
  270. \***************************************************************************/
  271. BOOL InsertLstItem(pLst, pi, afCmd)
  272. PLST pLst;
  273. PLITEM pi;
  274. USHORT afCmd;
  275. {
  276.     PLITEM piT;
  277.  
  278.     if (pLst == NULL)
  279.         return(FALSE);
  280.         
  281.     SemEnter();
  282.     
  283.     if (pLst->pItemFirst == NULL || afCmd & ILST_FIRST) {
  284.         pi->next = pLst->pItemFirst;
  285.         pLst->pItemFirst = pi;
  286.     } else {                    /* ILST_LAST assumed */
  287.         piT = pLst->pItemFirst;
  288.         while (piT->next) 
  289.             piT = piT->next;
  290.         piT->next = pi;
  291.         pi->next = NULL;
  292.     }
  293.     
  294.     SemLeave();
  295.     return(TRUE);
  296. }
  297.  
  298.  
  299.  
  300.  
  301. /*
  302.  * ------------- Specific list routines -------------
  303.  */
  304.  
  305. /*
  306.  * This function is HIGHLY dependent on the ADVLI structure.
  307.  * This will match an exact hsz/fmt pair with a 0 format being wild.
  308.  */
  309. BOOL CmpAdv(pb1, pb2)
  310. PBYTE pb1;
  311. PBYTE pb2;
  312. {
  313.     USHORT usFmt;
  314.     
  315.     if (*(PHSZ)pb1 == *(PHSZ)pb2) {
  316.         if ((usFmt = *(PUSHORT)(pb2 + 4)) == 0)
  317.             return(TRUE);
  318.         if (usFmt == *(PUSHORT)(pb1 + 4))
  319.             return(TRUE);
  320.     }
  321.     return(FALSE);
  322. }
  323.  
  324.  
  325.  
  326. BOOL fSearchHwndList(pLst, hwnd)
  327. PLST pLst;
  328. HWND hwnd;
  329. {
  330.     HWNDLI hwndi;
  331.  
  332.     hwndi.hwnd = hwnd;
  333.     return((BOOL)FindLstItem(pLst, CmpHwnd, (PLITEM)&hwndi));
  334. }
  335.  
  336.  
  337.  
  338. void AddHwndList(hwnd, pLst)
  339. HWND hwnd;
  340. PLST pLst;
  341. {
  342.     HWNDLI hwndli;
  343.     PHWNDLI pli;
  344.  
  345.     AssertF(pLst != NULL, "AddHwndList - NULL pLst");
  346.     AssertF(pLst->cbItem == sizeof(HWNDLI), "AddHwndList - Bad item size");
  347.     SemEnter();
  348.     hwndli.hwnd = hwnd;
  349.     if ((hwnd == NULL) || FindLstItem(pLst, CmpHwnd, (PLITEM)&hwndli)) {
  350.         SemLeave();
  351.         return;
  352.     }
  353.     pli = (PHWNDLI)NewLstItem(pLst, ILST_FIRST);
  354.     pli->hwnd = hwnd;
  355.     SemLeave();
  356. }
  357.  
  358.  
  359.  
  360. /*
  361.  * Insert the given data into the list if one does not already exist
  362.  * under the given hwnd.
  363.  */
  364. void AddAckHwndList(hwnd, hszApp, hszTopic, pLst)
  365. HWND hwnd;
  366. HSZ hszApp;
  367. HSZ hszTopic;
  368. PLST pLst;
  369. {
  370.     HWNDLI hwndli;
  371.     PACKHWNDLI pli;
  372.  
  373.     AssertF(pLst != NULL, "AddAckHwndList - NULL pLst");
  374.     AssertF(pLst->cbItem == sizeof(ACKHWNDLI), "AddAckHwndList - Bad item size");
  375.     SemEnter();
  376.     hwndli.hwnd = hwnd;
  377.     if ((hwnd == NULL) || FindLstItem(pLst, CmpHwnd, (PLITEM)&hwndli)) {
  378.         SemLeave();
  379.         return;
  380.     }
  381.     pli = (PACKHWNDLI)NewLstItem(pLst, ILST_FIRST);
  382.     pli->hwnd = hwnd;
  383.     pli->hszApp = hszApp;
  384.     pli->hszTopic = hszTopic;
  385.     SemLeave();
  386. }
  387.  
  388.  
  389.  
  390.  
  391. /***************************** Private Function ****************************\
  392. * hwnd-hsz list functions
  393. *
  394. * History:      1/20/89     Created         sanfords
  395. \***************************************************************************/
  396. void AddHwndHszList(hsz, hwnd, pLst)
  397. HSZ hsz;
  398. HWND hwnd;
  399. PLST pLst;
  400. {
  401.     PHWNDHSZLI phhi;
  402.  
  403.     AssertF(pLst->cbItem == sizeof(HWNDHSZLI), "AddHwndHszList - Bad item size");
  404.     SemEnter();
  405.     if ((hsz == NULL) || (BOOL)HwndFromHsz(hsz, pLst)) {
  406.         SemLeave();
  407.         return;
  408.     }
  409.     phhi = (PHWNDHSZLI)NewLstItem(pLst, ILST_FIRST);
  410.     phhi->hwnd = hwnd;
  411.     phhi->hsz = hsz;
  412.     IncHszCount(hsz);
  413.     SemLeave();
  414. }
  415.  
  416.  
  417. void DestroyHwndHszList(pLst)
  418. PLST pLst;
  419. {
  420.     AssertF(pLst->cbItem == sizeof(HWNDHSZLI), "DestroyHwndHszList - Bad item size");
  421.     SemEnter();
  422.     while(pLst->pItemFirst) {
  423.         FreeHsz(((PHWNDHSZLI)pLst->pItemFirst)->hsz);
  424.         RemoveLstItem(pLst, pLst->pItemFirst);
  425.     }
  426.     FarFreeMem(pLst->hheap, pLst, sizeof(LST));
  427.     SemLeave();
  428. }
  429.  
  430.  
  431.  
  432. HWND HwndFromHsz(hsz, pLst)
  433. HSZ hsz;
  434. PLST pLst;
  435. {
  436.     HWNDHSZLI hhli;
  437.     PHWNDHSZLI phhli;
  438.  
  439.     hhli.hsz = hsz;
  440.     if (!(phhli = (PHWNDHSZLI)FindLstItem(pLst, CmppHsz, (PLITEM)&hhli)))
  441.         return(NULL);
  442.     return(phhli->hwnd);
  443. }
  444.  
  445.  
  446.  
  447. /***************************** Private Function ****************************\
  448. * DESCRIPTION:
  449. *   Advise list helper functions.
  450. *
  451. * History:      1/20/89     Created         sanfords
  452. \***************************************************************************/
  453. BOOL AddAdvList(pLst, hszItem, fsStatus, usFmt)
  454. PLST pLst;
  455. HSZ hszItem;
  456. USHORT fsStatus;
  457. USHORT usFmt;
  458. {
  459.     PADVLI pali;
  460.  
  461.     AssertF(pLst->cbItem == sizeof(ADVLI), "AddAdvList - bad item size");
  462.     if (hszItem == NULL) 
  463.         return(TRUE);
  464.     SemEnter();
  465.     if (!(pali = FindAdvList(pLst, hszItem, usFmt))) {
  466.         IncHszCount(hszItem);
  467.         pali = (PADVLI)NewLstItem(pLst, ILST_FIRST);
  468.     }
  469.     AssertF((BOOL)pali, "AddAdvList - NewLstItem() failed")
  470.     if (pali != NULL) {
  471.         pali->hszItem = hszItem;
  472.         pali->usFmt = usFmt;
  473.         pali->fsStatus = fsStatus;
  474.     }
  475.     SemLeave();
  476.     return((BOOL)pali);    
  477. }
  478.  
  479.  
  480.  
  481. /*
  482.  * This will delete the matching Advise loop entry.  If usFmt is 0, all
  483.  * entries with the same hszItem are deleted.  Returns fNotEmptyAfterDelete.
  484.  */
  485. BOOL DeleteAdvList(pLst, hszItem, usFmt)
  486. PLST pLst;
  487. HSZ hszItem;
  488. USHORT usFmt;
  489. {
  490.     PADVLI pali;
  491.  
  492.     if (hszItem == NULL) 
  493.         return((BOOL)pLst->pItemFirst);
  494.     SemEnter();
  495.     while (pali = (PADVLI)FindAdvList(pLst, hszItem, usFmt)) {
  496.         FreeHsz((pali)->hszItem);
  497.         RemoveLstItem(pLst, (PLITEM)pali);
  498.     }
  499.     SemLeave();
  500.     return((BOOL)pLst->pItemFirst);
  501. }
  502.  
  503.  
  504.  
  505. /***************************** Private Function ****************************\
  506. * This routine searches the advise list for and entry in hszItem.  It returns
  507. * pAdvli only if the item is found.
  508. *
  509. * History:
  510. *   Created     9/12/89    Sanfords
  511. \***************************************************************************/
  512. PADVLI FindAdvList(pLst, hszItem, usFmt)
  513. PLST pLst;
  514. HSZ hszItem;
  515. USHORT usFmt;
  516. {
  517.     ADVLI advli;
  518.  
  519.     advli.hszItem = hszItem;
  520.     advli.usFmt = usFmt;
  521.     return((PADVLI)FindLstItem(pLst, CmpAdv, (PLITEM)&advli));
  522. }
  523.  
  524.  
  525. /***************************** Private Function ****************************\
  526. * This routine searches for the next entry for hszItem.  It returns
  527. * pAdvli only if the item is found.
  528. *
  529. * History:
  530. *   Created     11/15/89    Sanfords
  531. \***************************************************************************/
  532. PADVLI FindNextAdv(padvli, hszItem)
  533. PADVLI padvli;
  534. HSZ hszItem;
  535. {
  536.     
  537.     SemEnter();
  538.     while ((padvli = (PADVLI)padvli->next) != NULL) {
  539.         if (padvli->hszItem == hszItem) {
  540.             SemLeave();
  541.             return(padvli);
  542.         }
  543.     }
  544.     SemLeave();
  545.     return(NULL);
  546. }
  547.  
  548.  
  549.  
  550. /***************************** Pile Functions ********************************\
  551. *
  552. *  A pile is a list where each item is an array of subitems.  This allows
  553. *  a more memory efficient method of handling unordered lists.
  554. *
  555. \*****************************************************************************/
  556.  
  557. PPILE CreatePile(hheap, cbItem, cItemsPerBlock)
  558. HHEAP hheap;
  559. USHORT cbItem;
  560. USHORT cItemsPerBlock;
  561. {
  562.     PPILE ppile;
  563.  
  564.     if (!(ppile = (PPILE)FarAllocMem(hheap, sizeof(PILE)))) {
  565.         SemLeave();
  566.         return(NULL);
  567.     }
  568.     ppile->pBlockFirst = (PLITEM)NULL;
  569.     ppile->hheap = hheap;
  570.     ppile->cbBlock = cbItem * cItemsPerBlock + sizeof(PILEB);
  571.     ppile->cSubItemsMax = cItemsPerBlock;
  572.     ppile->cbSubItem = cbItem;
  573.     return(ppile);
  574. }
  575.  
  576.  
  577. PPILE DestroyPile(pPile)
  578. PPILE pPile;
  579. {
  580.     if (pPile == NULL)
  581.         return(NULL);
  582.     SemEnter();
  583.     while (pPile->pBlockFirst) 
  584.         RemoveLstItem((PLST)pPile, (PLITEM)pPile->pBlockFirst);
  585.     FarFreeMem(pPile->hheap, pPile, sizeof(PILE));
  586.     SemLeave();
  587.     return(NULL);
  588. }
  589.  
  590. void FlushPile(pPile)
  591. PPILE pPile;
  592. {
  593.     if (pPile == NULL)
  594.         return;
  595.     SemEnter();
  596.     while (pPile->pBlockFirst) 
  597.         RemoveLstItem((PLST)pPile, (PLITEM)pPile->pBlockFirst);
  598.     SemLeave();
  599. }
  600.  
  601.  
  602. USHORT QPileItemCount(pPile)
  603. PPILE pPile;
  604. {
  605.     register USHORT c;
  606.     PPILEB pBlock;
  607.  
  608.     if (pPile == NULL)
  609.         return(0);
  610.  
  611.     SemEnter();
  612.     pBlock = pPile->pBlockFirst;
  613.     c = 0;
  614.     while (pBlock) {
  615.         c += pBlock->cItems;
  616.         pBlock = pBlock->next;
  617.     }
  618.     SemLeave();
  619.     return(c);
  620. }
  621.  
  622.  
  623. BOOL CopyPileItems(pPile, pDst)
  624. PPILE pPile;
  625. PBYTE pDst;
  626. {
  627.     PPILEB pBlock;
  628.     
  629.     AssertF(pDst != NULL, "CopyPileItems - NULL destination");
  630.     if (pPile == NULL)
  631.         return(FALSE);
  632.  
  633.     SemEnter();
  634.     pBlock = pPile->pBlockFirst;
  635.     while (pBlock) {
  636.         CopyBlock((PBYTE)pBlock + sizeof(PILEB), pDst,
  637.                 pBlock->cItems * pPile->cbSubItem);
  638.         pDst += pBlock->cItems * pPile->cbSubItem;
  639.         pBlock = pBlock->next;
  640.     }
  641.     SemLeave();
  642.  
  643.     return(TRUE);
  644. }
  645.  
  646.  
  647.  
  648.  
  649. /***************************** Private Function ****************************\
  650. * Locate and return the pointer to the pile subitem who's key fields match
  651. * pbSearch using npfnCmp to compare the fields.  If pbSearch == NULL, or
  652. * npfnCmp == NULL, the first subitem is returned.
  653. *
  654. * afCmd may be:
  655. * FPI_DELETE - delete the located item
  656. * FPI_COUNT - count number of items that match
  657. * In this case, the returned pointer is not valid.
  658. *
  659. * pppb points to where to store a pointer to the block which contained
  660. * the located item.
  661. *
  662. * if pppb == NULL, it is ignored.
  663. *
  664. * NULL is returned if pbSearch was not found or if the list was empty.
  665. *
  666. * History:
  667. *   Created     9/12/89    Sanfords
  668. \***************************************************************************/
  669. PBYTE FindPileItem(pPile, npfnCmp, pbSearch, afCmd)
  670. PPILE pPile;
  671. NPFNCMP npfnCmp;
  672. PBYTE pbSearch;
  673. USHORT afCmd;
  674. {
  675.     PBYTE pb;
  676.     PPILEB ppbT;
  677.     register int i;
  678.     register int c;
  679.  
  680.     if (pPile == NULL)
  681.         return(NULL);
  682.     c = 0;
  683.     SemEnter();
  684.     ppbT = pPile->pBlockFirst;
  685.     while (ppbT) {
  686.         /*
  687.          * for each block...
  688.          */
  689.         for (pb = (PBYTE)ppbT + sizeof(PILEB), i = 0;
  690.                 i < ppbT->cItems; pb += pPile->cbSubItem, i++) {
  691.             /*
  692.              * and each item within that block..
  693.              */
  694.             if (pbSearch == NULL || npfnCmp == NULL ||
  695.                     (*npfnCmp)(pb, pbSearch)) {
  696.                 /*
  697.                  * If it matches or we don't care...
  698.                  */
  699.                 if (afCmd & FPI_DELETE) {
  700.                     /*
  701.                      * remove entire block if this was the last subitem in it.
  702.                      */
  703.                     if (--ppbT->cItems == 0) {
  704.                         RemoveLstItem((PLST)pPile, (PLITEM)ppbT);
  705.                     } else {
  706.                         /*
  707.                          * copy last subitem in the block over the removed item.
  708.                          */
  709.                         CopyBlock((PBYTE)ppbT + sizeof(PILEB) +
  710.                                 pPile->cbSubItem * ppbT->cItems,
  711.                                 pb, pPile->cbSubItem);
  712.                     }
  713.                 }
  714.                 if (afCmd & FPI_COUNT) {
  715.                     c++;
  716.                 } else {
  717.                     SemLeave();
  718.                     return(pb);
  719.                 }
  720.                 if (afCmd & FPI_DELETE) {
  721.                     pb = (PBYTE)ppbT + sizeof(PILEB);
  722.                     i = 0;
  723.                 }
  724.             }
  725.         }
  726.         ppbT = (PPILEB)ppbT->next;
  727.     }
  728.     SemLeave();
  729.     return((PBYTE)(ULONG)c);
  730. }
  731.  
  732.  
  733. /***************************** Private Function ****************************\
  734. * Places a copy of the subitem pointed to by pb into the first available
  735. * spot in the pile pPile.  If npfnCmp != NULL, the pile is first searched
  736. * for a pb match.  If found, pb replaces the located data but FALSE is
  737. * returned to show that no real addition took place.
  738. *
  739. * History:
  740. *   Created     9/12/89    Sanfords
  741. \***************************************************************************/
  742. BOOL AddPileItem(pPile, pb, npfnCmp)
  743. PPILE pPile;
  744. PBYTE pb;
  745. BOOL (*npfnCmp)(PBYTE pb, PBYTE pbSearch);
  746. {
  747.     PBYTE pbDst;
  748.     PPILEB ppb;
  749.  
  750.     if (pPile == NULL)
  751.         return(FALSE);
  752.     SemEnter();
  753.     if (npfnCmp != NULL &&
  754.             (pbDst = FindPileItem(pPile, npfnCmp, pb, 0)) != NULL) {
  755.         CopyBlock(pb, pbDst, pPile->cbSubItem);
  756.         SemLeave();
  757.         return(FALSE);
  758.     }
  759.     ppb = pPile->pBlockFirst;
  760.     /*
  761.      * locate a block with room
  762.      */
  763.     while ((ppb != NULL) && ppb->cItems == pPile->cSubItemsMax) {
  764.         ppb = (PPILEB)ppb->next;
  765.     }
  766.     /*
  767.      * If all full or no blocks, make a new one, link it on the bottom.
  768.      */
  769.     if (ppb == NULL) {
  770.         if ((ppb = (PPILEB)NewLstItem((PLST)pPile, ILST_LAST)) == NULL) {
  771.             SemLeave();
  772.             return(FALSE);
  773.         }
  774.         ppb->cItems = 0;
  775.     }
  776.     /*
  777.      * add the subitem
  778.      */
  779.     CopyBlock(pb, (PBYTE)ppb + sizeof(PILEB) + pPile->cbSubItem * ppb->cItems++,
  780.         pPile->cbSubItem);
  781.      
  782.     SemLeave();
  783.     return(TRUE);
  784. }
  785.  
  786.  
  787.  
  788.  
  789. /***************************** Private Function ****************************\
  790. * Fills pb with a copy of the top item's data and removes it from the pile.
  791. * returns FALSE if the pile was empty.
  792. *
  793. * History:
  794. *   Created     9/12/89    Sanfords
  795. \***************************************************************************/
  796. BOOL PopPileSubitem(pPile, pb)
  797. PPILE pPile;
  798. PBYTE pb;
  799. {
  800.     PPILEB ppb;
  801.     PBYTE pSrc;
  802.  
  803.     
  804.     if ((pPile == NULL) || ((ppb = pPile->pBlockFirst) == NULL))
  805.         return(FALSE);
  806.         
  807.     SemEnter();
  808.     pSrc = (PBYTE)pPile->pBlockFirst + sizeof(PILEB);
  809.     CopyBlock(pSrc, pb, pPile->cbSubItem);
  810.     /*
  811.      * remove entire block if this was the last subitem in it.
  812.      */
  813.     if (pPile->pBlockFirst->cItems == 1) {
  814.         RemoveLstItem((PLST)pPile, (PLITEM)pPile->pBlockFirst);
  815.     } else {
  816.         /*
  817.          * move last item in block to replace copied subitem and decrement
  818.          * subitem count.
  819.          */
  820.         CopyBlock(pSrc + pPile->cbSubItem * --pPile->pBlockFirst->cItems,
  821.                 pSrc, pPile->cbSubItem);
  822.     }
  823.     SemLeave();
  824.     return(TRUE);
  825. }
  826.     
  827.  
  828. /***************************** Semaphore Functions *************************\
  829. * SemEnter() and SemLeave() are macros.
  830. *
  831. * History:      1/1/89  Created         sanfords
  832. \***************************************************************************/
  833. void SemInit()
  834. {
  835.     PBYTE pSem;
  836.     SHORT c;
  837.  
  838.     pSem = (PBYTE)&FSRSemDmg;
  839.     c = 0;
  840.     while (c++ < sizeof(DOSFSRSEM)) {
  841.         *pSem++ = 0;
  842.     }
  843.     FSRSemDmg.cb = sizeof(DOSFSRSEM);
  844. }
  845.  
  846. #ifdef DEBUG
  847. void SemCheckIn()
  848. {                                                                
  849.     PIDINFO pi;
  850.     BOOL fin;
  851.  
  852.     DosGetPID(&pi);
  853.     fin = (FSRSemDmg.cUsage > 0) &&
  854.             (FSRSemDmg.pid == pi.pid) &&
  855.             ((FSRSemDmg.tid == pi.tid) || (FSRSemDmg.tid == -1));
  856.     /*
  857.      * !!! NOTE: during exitlists processing, semaphore TIDs are set to -1
  858.      */
  859.     AssertF(fin, "SemCheckIn - Out of Semaphore");
  860.     if (!fin)
  861.         SemEnter();
  862. }
  863.  
  864. void SemCheckOut()
  865. {
  866.     PIDINFO pi;
  867.     BOOL fOut;
  868.  
  869.     DosGetPID(&pi);
  870.     fOut = FSRSemDmg.cUsage == 0 || FSRSemDmg.pid != pi.pid ||
  871.                 FSRSemDmg.tid != pi.tid;
  872.     AssertF(fOut, "SemCheckOut - In Semaphore");
  873.     if (!fOut)
  874.         while (FSRSemDmg.cUsage)
  875.             SemLeave();
  876.         
  877. }
  878. #endif
  879.  
  880.  
  881. void SemEnter()
  882. {
  883.     DosFSRamSemRequest(&FSRSemDmg, SEM_INDEFINITE_WAIT);
  884. }
  885.  
  886.  
  887. void SemLeave()
  888. {
  889.     DosFSRamSemClear(&FSRSemDmg);
  890. }
  891.  
  892.  
  893.  
  894. void EXPENTRY ExlstAbort(usTermCode)
  895. USHORT usTermCode;
  896. {
  897.     PAPPINFO pai;
  898.     usTermCode;
  899.     
  900.     SemEnter();     /* get any other processes out of the semaphore */
  901.     if (pai = GetCurrentAppInfo(FALSE)) {
  902.         pai->cInCallback = 0;  /* so Unregister call will work */
  903.         DdeUninitialize();
  904.     } else {
  905.         SemLeave();
  906.         DosExitList(EXLST_REMOVE, (PFNEXITLIST)ExlstAbort);
  907.     }
  908.     DosExitList(EXLST_EXIT, 0);
  909. }
  910.  
  911. BOOL CopyHugeBlock(pSrc, pDst, cb)
  912. PBYTE pSrc;
  913. PBYTE pDst;
  914. ULONG cb;
  915. {
  916.     ULONG cFirst;
  917.     /*
  918.      *  |____________|   |___________|   |____________|  |____________|
  919.      *     ^src                                 ^
  920.      *
  921.      *  |____________|   |___________|   |____________|  |____________|
  922.      *             ^dst                                   ^
  923.      */
  924.     cFirst = (ULONG)min((~(USHORT)pSrc), (~(USHORT)pDst)) + 1L;
  925.     if (cb < cFirst) {
  926.         CopyBlock(pSrc, pDst, (USHORT)cb);
  927.         return(TRUE);
  928.     }
  929.  
  930.     goto copyit;
  931.         
  932.     /*
  933.      * Now at least one of the pointers is on a segment boundry.
  934.      */
  935.     while (cb) {
  936.         cFirst = min(0x10000 - ((USHORT)pSrc | (USHORT)pDst), cb);
  937. copyit:
  938.         if (HIUSHORT(cFirst)) {
  939.             /*
  940.              * special case where pSrc and pDst both are on segment
  941.              * bounds.  Copy half at a time.
  942.              */
  943.             /*
  944.              *  |___________|   |____________|  |____________|
  945.              *  ^src                               ^
  946.              *
  947.              *  |___________|   |____________|  |____________|
  948.              *  ^dst                               ^
  949.              */
  950.             cFirst >>= 1;
  951.             CopyBlock(pSrc, pDst, (USHORT)cFirst);
  952.             pSrc += cFirst;
  953.             pDst += cFirst;
  954.             cb -= cFirst;
  955.         }
  956.         CopyBlock(pSrc, pDst, (USHORT)cFirst);
  957.         pSrc = HugeOffset(pSrc, cFirst);
  958.         pDst = HugeOffset(pDst, cFirst);
  959.         cb -= cFirst;
  960.     /*
  961.      *  |____________|   |___________|   |____________|  |____________|
  962.      *           ^src                           ^
  963.      *
  964.      *  |____________|   |___________|   |____________|  |____________|
  965.      *                   ^dst                             ^
  966.      */
  967.     }
  968.     return(TRUE);
  969. }
  970.  
  971.  
  972.  
  973.  
  974. /***************************************************************************\
  975. * Kills windows but avoids invalid window rips in debugger.
  976. \***************************************************************************/
  977. BOOL DestroyWindow(hwnd)
  978. HWND hwnd;
  979. {
  980.     if (WinIsWindow(DMGHAB, hwnd))
  981.         return(WinDestroyWindow(hwnd));
  982.     return(TRUE);
  983. }
  984.  
  985.  
  986. /***************************** Private Function ****************************\
  987. * Returns hConv of the window passed in is one of the ddeml windows.
  988. *
  989. * History:
  990. *   Created     9/1/89    Sanfords
  991. \***************************************************************************/
  992. HCONV IsDdeWindow(hwnd)
  993. HWND hwnd;
  994. {
  995.     PAPPINFO pai;
  996.  
  997.     pai = pAppInfoList;
  998.     
  999.     while (pai && WinIsChild(hwnd, pai->hwndDmg)) 
  1000.         pai = pai->next;
  1001.         
  1002.     if (pai)
  1003.         return((HCONV)hwnd);
  1004.     else
  1005.         return(0L);
  1006. }
  1007.  
  1008.  
  1009. /***************************** Private Function ****************************\
  1010. * This routine only frees a MYDDES segment if this process is not the owner.
  1011. *
  1012. * History:
  1013. *   Created     9/12/89    Sanfords
  1014. \***************************************************************************/
  1015. void FreeData(
  1016. PMYDDES pmyddes,
  1017. PAPPINFO pai)
  1018. {
  1019.     TID tid;
  1020.     if (!CheckSel(SELECTOROF(pmyddes)) ||
  1021.             (   pmyddes->offszItemName == sizeof(MYDDES) &&
  1022.                 pmyddes->magic == MYDDESMAGIC &&
  1023.                 pmyddes->fs & HDATA_APPOWNED &&
  1024.                 pmyddes->pai == pai) )
  1025.         return;
  1026.  
  1027.     SemEnter();
  1028.     FindPileItem(pai->pHDataPile, CmpULONG, (PBYTE)&pmyddes, FPI_DELETE);
  1029.     tid = pai->tid;
  1030.     do {
  1031.         if (FindPileItem(pai->pHDataPile, CmpULONG, (PBYTE)&pmyddes, FPI_COUNT)) {
  1032.             SemLeave();
  1033.             return;
  1034.         }
  1035.         pai = pai->nextThread;
  1036.     } while (pai && pai->tid != tid);
  1037.     SemLeave();
  1038.     DosFreeSeg(SELECTOROF(pmyddes));
  1039. }
  1040.  
  1041.  
  1042.  
  1043. #ifdef DEBUG
  1044. int APIENTRY DebugOutput(PCH);
  1045. void fAssert(f, pszComment, line, szfile)
  1046. BOOL f;
  1047. PSZ pszComment;
  1048. USHORT line;
  1049. PSZ szfile;
  1050. {
  1051.     char szT[90];
  1052.     PSZ psz, pszLast;
  1053.  
  1054.     if (!f) {
  1055.         szT[0] = '\000';
  1056.         psz = szT;
  1057.         pszLast = &szT[89];
  1058.         psz = lstrcat(psz, "\n\rAssertion failure: ", pszLast);
  1059.         psz = lstrcat(psz, szfile, pszLast);
  1060.         psz = lstrcat(psz, ":", pszLast);
  1061.         psz = dtoa(psz, line, FALSE);
  1062.         psz = lstrcat(psz, " ", pszLast);
  1063.         psz = lstrcat(psz, pszComment, pszLast);
  1064.         psz = lstrcat(psz, "\n\r", pszLast);
  1065.         DebugOutput(szT);
  1066.         DebugBreak(); 
  1067.     }
  1068. }
  1069. #endif
  1070.  
  1071.  
  1072.  
  1073. HDMGDATA PutData(pSrc, cb, cbOff, hszItem, usFmt, afCmd, pai)
  1074. PBYTE pSrc;
  1075. ULONG cb;
  1076. ULONG cbOff;
  1077. HSZ hszItem;
  1078. USHORT usFmt;
  1079. USHORT afCmd;
  1080. PAPPINFO pai;
  1081. {
  1082.     PMYDDES pmyddes;
  1083.     
  1084.     if ((pmyddes = (PMYDDES)AllocDDESel(0, usFmt, hszItem, cb + cbOff, pai))
  1085.             == NULL) {
  1086.         pai->LastError = DMGERR_MEMORY_ERROR;
  1087.         return(0L);
  1088.     }
  1089.     pmyddes->fs = afCmd;
  1090.     
  1091.     if (afCmd & HDATA_APPFREEABLE) {
  1092.         if (!AddPileItem(pai->pHDataPile, (PBYTE)&pmyddes, CmpULONG)) {
  1093.             DosFreeSeg(SELECTOROF(pmyddes));
  1094.             pai->LastError = DMGERR_MEMORY_ERROR;
  1095.             return(0L);
  1096.         } 
  1097.     }
  1098.     if (pSrc)
  1099.         CopyHugeBlock(pSrc, HugeOffset(DDES_PABDATA(pmyddes), cbOff), cb);
  1100.     return(pmyddes);
  1101. }
  1102.  
  1103.  
  1104. /*
  1105.  * This routine adds all HSZ/HAPP pairs it finds for the given pai matching
  1106.  * hszApp to hDataAdd.
  1107.  * poffAdd is the offset into the hDataAdd to start inserting HSZ/HAPP
  1108.  * pairs.  It then truncates the list with a 0 HSZ and returns the offset
  1109.  * to the terminator (ready to be called again to add more).
  1110.  *
  1111.  * returns 0L on error.
  1112.  */
  1113. ULONG
  1114. QueryAppNames(
  1115. PAPPINFO pai,
  1116. HDMGDATA hDataAdd,
  1117. HSZ hszApp,
  1118. ULONG offAdd)
  1119. {
  1120.     USHORT chsz;
  1121.     PHSZ phsz, phszPile;
  1122.     PPILEB pBlock;
  1123.  
  1124.     AssertF(sizeof(HSZ) == sizeof(HAPP), "Type size conflict");
  1125.         
  1126.     SemEnter();
  1127.     if (chsz = (USHORT)FindPileItem(pai->pAppNamePile,
  1128.             hszApp ? CmpULONG : NULL, (PBYTE)&hszApp, FPI_COUNT)) {
  1129.         /*
  1130.          * allocate for additions.
  1131.          */
  1132.         if (!DdeAddData(hDataAdd, NULL,
  1133.                 (chsz + 1L) * (sizeof(HSZ) + sizeof(HDMGDATA)), offAdd)) {
  1134.             offAdd = 0L;
  1135.             GetCurrentAppInfo(FALSE)->LastError = DMGERR_MEMORY_ERROR;
  1136.             goto Exit;
  1137.         }
  1138.         
  1139.         phsz = DDES_PABDATA((PDDESTRUCT)hDataAdd) + offAdd;
  1140.         if (hszApp) {
  1141.             *phsz++ = hszApp;       /* only one per thread expected */
  1142.             *phsz++ = (HSZ)pai->hwndFrame;
  1143.         } else {
  1144.             pBlock = pai->pAppNamePile->pBlockFirst;
  1145.             while (pBlock) {
  1146.                 phszPile = (PHSZ)(pBlock + 1);
  1147.                 for (chsz = 0; chsz < pBlock->cItems; chsz++) {
  1148.                     *(phsz++) = *(phszPile++);
  1149.                     *(phsz++) = (HSZ)pai->hwndFrame;
  1150.                 }
  1151.                 pBlock = pBlock->next;
  1152.             }
  1153.         }
  1154.         *phsz = 0L;
  1155.         offAdd = phsz - DDES_PABDATA((PDDESTRUCT)hDataAdd);
  1156.     }
  1157. Exit:    
  1158.     SemLeave();
  1159.     return(offAdd);
  1160. }
  1161.  
  1162.