home *** CD-ROM | disk | FTP | other *** search
/ Power GUI Programming with VisualAge C++ / powergui.iso / trialva / ibmcppw / sdk / mapi / win16 / dev / common / imem.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-11  |  14.6 KB  |  561 lines

  1. /*
  2.  *  IMEM.C
  3.  *  
  4.  *  Per-instance global data for WIN32 (trivial), WIN16, and Mac.
  5.  *
  6.  *  Copyright 1993-1995 Microsoft Corporation. All Rights Reserved.
  7.  */
  8.  
  9. #pragma warning(disable:4100)   /* unreferenced formal parameter */
  10. #pragma warning(disable:4201)   /* nameless struct/union */
  11. #pragma warning(disable:4209)   /* benign typedef redefinition */
  12. #pragma warning(disable:4214)   /* bit field types other than int */
  13. #pragma warning(disable:4001)   /* single line comments */
  14. #pragma warning(disable:4115)   /* named type definition in parens */
  15.  
  16. #ifdef WIN32
  17. #define INC_OLE2 /* Get the OLE2 stuff */
  18. #define INC_RPC  /* harmless on Windows NT; Windows 95 needs it */
  19. #endif
  20. #include <windows.h>
  21.  
  22. #include <windowsx.h>
  23. #include <mapiwin.h>
  24. #if defined (WIN32) && !defined (_MAC)
  25. #pragma warning(disable:4001)   /* single line comments */
  26. #include <objerror.h>
  27. #include <objbase.h>
  28. #endif
  29. #ifdef WIN16
  30. #include <compobj.h>
  31. #endif
  32. #include <mapicode.h>
  33. #include <mapidbg.h>
  34.  
  35. #ifdef _MAC
  36. #include <macname1.h>
  37. #include <macos\lowmem.h>
  38. #include <macname2.h>
  39. #include <utilmac.h>
  40. #endif
  41.  
  42. #ifdef  DEBUG
  43. #define STATIC
  44. #else
  45. #define STATIC static
  46. #endif
  47.  
  48. #pragma warning (disable:4514)      /* unreferenced inline function */
  49.  
  50. #ifdef  WIN16
  51.  
  52. #pragma code_seg("IMAlloc")
  53.  
  54. #pragma warning(disable: 4005)      /* redefines MAX_PATH */
  55. #include <toolhelp.h>
  56. #pragma warning(default: 4005)
  57.  
  58. #pragma warning(disable: 4704)      /* Inline assembler */
  59.  
  60. /*
  61.  *  These arrays are parallel. RgwInstKey holds the stack
  62.  *  segment of each task that calls the DLL we're in; rgpvInst
  63.  *  has a pointer to that task's instance globals in the slot with
  64.  *  the same index. Since all Win16 tasks share the same x86
  65.  *  segment descriptor tables, no two tasks can have the same stack
  66.  *  segment.
  67.  *  
  68.  *  Note carefully the last elements of the initializers. The value
  69.  *  in rgwInstKey is a sentinel, which will always stop the scan
  70.  *  whether the value being sought is a valid stack segment or
  71.  *  zero.
  72.  */
  73.  
  74. STATIC WORD   rgwInstKey[cInstMax+1]= { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xFFFF };
  75. STATIC LPVOID rgpvInst[cInstMax+1]=   { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
  76. STATIC DWORD  rgdwPid[cInstMax+1]=    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
  77.  
  78. STATIC WORD   wCachedKey            = 0;
  79. STATIC LPVOID pvCachedInst          = NULL;
  80.  
  81. /*
  82.  -  IFindInst
  83.  -  
  84.  *  Purpose:
  85.  *      Used to locate a particular task's instance pointer, and
  86.  *      also to find a free slot in the table.
  87.  *  
  88.  *  Arguments:
  89.  *      The value to look up. This is either a task's stack
  90.  *      segment, or 0 (if an empty slot is being sought).
  91.  *  
  92.  *  Returns:
  93.  *      Returns the index of the given value in rgwInstKey. 
  94.  *      If the value is not present, returns cInstMax.
  95.  *  
  96.  */
  97.  
  98. #pragma warning(disable: 4035)      /* function return value done in asm */
  99.  
  100. STATIC int
  101. IFindInst(WORD w)
  102. {
  103.     _asm
  104.     {
  105.         mov cx,cInstMax+1           /* count includes sentinel */
  106.         mov ax,ds                   /* point es:di at rgwInstKey */
  107.         mov es,ax
  108.         mov di,OFFSET rgwInstKey
  109.         mov ax,w                    /* scan for this value */
  110.         cld                         /* scan forward... */
  111.         repne scasw                 /* go */
  112.         mov ax,cx                   /* Convert the number of items remaining */
  113.         sub ax,cInstMax+1           /* to the index of the item found. */
  114.         inc ax
  115.         neg ax
  116.     }
  117. }
  118.  
  119. #pragma warning(default: 4035)
  120.  
  121. /*
  122.  -  PvGetInstanceGlobals
  123.  -  
  124.  *  Purpose:
  125.  *      Returns a pointer to the instance global data structre for
  126.  *      the current task.
  127.  *  
  128.  *  Returns:
  129.  *      Pointer to the instance data structure, or NULL if no
  130.  *      structure has yet been installed for this task.
  131.  */
  132.  
  133. LPVOID FAR PASCAL
  134. PvGetInstanceGlobals(void)
  135. {
  136.     int iInst;
  137.     WORD wMe;
  138.     
  139.     _asm mov wMe,ss         ; get key for this process
  140.  
  141.     /* First check cached value */
  142.     if (wCachedKey == wMe)
  143.         return pvCachedInst;
  144.  
  145.     /* Miss, do the lookup */
  146.     iInst = IFindInst(wMe);
  147.  
  148.     /* Cache and return the found value */
  149.     if (iInst != cInstMax)
  150.     {
  151.         wCachedKey = wMe;
  152.         pvCachedInst = rgpvInst[iInst];
  153.     }
  154.     return rgpvInst[iInst];     /* Note: parallel to the lookup sentinel */
  155. }
  156.  
  157. LPVOID FAR PASCAL
  158. PvGetVerifyInstanceGlobals(DWORD dwPid)
  159. {
  160.     int iInst;
  161.     WORD wMe;
  162.     
  163.     _asm mov wMe,ss         ; get key for this process
  164.  
  165.     /* Always do the lookup */
  166.     iInst = IFindInst(wMe);
  167.  
  168.     /* If SS misses, return null right away */
  169.     if (iInst == cInstMax)
  170.         return NULL;
  171.  
  172.     /* SS hit, now check the OLE process ID */
  173.     if (dwPid != rgdwPid[iInst])
  174.     {
  175.         wCachedKey = 0;         /* Take no chances */
  176.         rgwInstKey[iInst] = 0;
  177.         rgpvInst[iInst] = 0;
  178.         rgdwPid[iInst] = 0;
  179.         return NULL;
  180.     }
  181.  
  182.     /* Cache and return the found value */
  183.     wCachedKey = wMe;
  184.     pvCachedInst = rgpvInst[iInst];
  185.     return pvCachedInst;
  186. }
  187.  
  188. LPVOID FAR PASCAL
  189. PvSlowGetInstanceGlobals(DWORD dwPid)
  190. {
  191.     int iInst;
  192.     
  193.     /* Always do the lookup */
  194.     for (iInst = 0; iInst < cInstMax; ++iInst)
  195.     {
  196.         if (rgdwPid[iInst] == dwPid)
  197.             break;
  198.     }
  199.  
  200.     /* If PID misses, return null */
  201.     if (iInst == cInstMax)
  202.         return NULL;
  203.  
  204.     /* Return the found value. Do not cache; this function is being
  205.      * called because SS is not what it "normally" is.
  206.      */
  207.     return rgpvInst[iInst];
  208. }
  209.  
  210. /*
  211.  -  ScSetVerifyInstanceGlobals
  212.  -  
  213.  *  Purpose:
  214.  *      Installs or deinstalls instance global data for the current task.
  215.  *  
  216.  *  Arguments:
  217.  *      pv          in      Pointer to instance data structure (to
  218.  *                          install); NULL (to deinstall).
  219.  *      dwPid       in      Zero or process ID, for better matching.
  220.  *  
  221.  *  Returns:
  222.  *      MAPI_E_NOT_ENOUGH_MEMORY if no slot is available in the
  223.  *      fixed-size table, else 0.
  224.  */
  225.  
  226. LONG FAR PASCAL
  227. ScSetVerifyInstanceGlobals(LPVOID pv, DWORD dwPid)
  228. {
  229.     int iInst;
  230.     WORD wMe;
  231.  
  232.     _asm mov wMe,ss
  233.     if (pv)
  234.     {
  235.         /* I am NOT supposed to be in the array at this time! */
  236.         Assert(IFindInst(wMe) == cInstMax);
  237.  
  238.         /* Installing instance globals. Find a free slot and park there. */
  239.         iInst = IFindInst(0);
  240.         if (iInst == cInstMax)
  241.         {
  242. #ifdef  DEBUG
  243.             OutputDebugString("Instance globals maxed out\r\n");
  244. #endif  
  245.             return MAPI_E_NOT_ENOUGH_MEMORY;
  246.         }
  247.         rgpvInst[iInst] = pv;
  248.         rgwInstKey[iInst] = wMe;
  249.         rgdwPid[iInst] = dwPid;
  250.  
  251.         /* Set the cache. */
  252.         wCachedKey = wMe;
  253.         pvCachedInst = pv;
  254.     }
  255.     else
  256.     {
  257.         /* Deinstalling instance globals. Search and destroy. */
  258.         iInst = IFindInst(wMe);
  259.         if (iInst == cInstMax)
  260.         {
  261. #ifdef  DEBUG
  262.             OutputDebugString("No instance globals to reset\r\n");
  263. #endif  
  264.             return MAPI_E_NOT_INITIALIZED;
  265.         }
  266.         rgpvInst[iInst] = NULL;
  267.         rgwInstKey[iInst] = 0;
  268.         rgdwPid[iInst] = 0L;
  269.  
  270.         /* Clear the cache. */
  271.         wCachedKey = 0;
  272.         pvCachedInst = NULL;
  273.     }
  274.  
  275.     return 0;
  276. }
  277.  
  278. LONG FAR PASCAL
  279. ScSetInstanceGlobals(LPVOID pv)
  280. {
  281.     return ScSetVerifyInstanceGlobals(pv, 0L);
  282. }
  283.  
  284. BOOL __export FAR PASCAL
  285. FCleanupInstanceGlobals(WORD wID, DWORD dwData)
  286. {
  287.     int iInst;
  288.     WORD wMe;
  289.  
  290.     /*
  291.      *  Would be nice if we could release the pmalloc
  292.      *  and the inst structure in this function, but docs say
  293.      *  don't make Windows calls from this callback.
  294.      *  That means also NO DEBUG TRACES
  295.      */
  296.  
  297.     /*
  298.      *  First, double-check that the DLL's data segment is available.
  299.      *  Code snitched from MSDN article "Loading, Initializing, and
  300.      *  Terminating a DLL."
  301.      */
  302.     _asm
  303.     {
  304.         push cx
  305.         mov cx, ds          ; get selector of interest
  306.         lar ax, cx          ; get selector access rights
  307.         pop cx
  308.         jnz bail            ; failed, segment is bad
  309.         test ax, 8000h      ; if bit 8000 is clear, segment is not loaded
  310.         jz bail             ; we're OK
  311.     }
  312.  
  313.     if (wID == NFY_EXITTASK)
  314.     {
  315.         _asm mov wMe,ss
  316.         iInst = IFindInst(wMe);
  317.  
  318.         if (iInst < cInstMax)
  319.         {
  320.             /* Clear this process's entry */
  321.             rgpvInst[iInst] = NULL;
  322.             rgwInstKey[iInst] = 0;
  323.         }
  324.  
  325.         /* Clear the cache too */
  326.         wCachedKey = 0;
  327.         pvCachedInst = NULL;
  328.     }
  329.  
  330. bail:
  331.     return 0;       /* don't suppress further notifications */
  332. }
  333.  
  334. #elif defined(_MAC) /* !WIN16 */
  335.  
  336. #pragma code_seg("imalloc", "fixed")
  337.  
  338. /*
  339.  *  The Mac implementation uses a linked list containing unique keys
  340.  *  to the calling process and pointers to instance data. This linked
  341.  *  list is n-dimensional because the Mac version often groups several
  342.  *  dlls into one exe.
  343.  *
  344.  *  The OLE code that TomSax wrote allows us to keep track of the caller's
  345.  *  %a5 world when we call from another application. This code depends on
  346.  *  on that.
  347.  *
  348.  */
  349.  
  350. typedef struct tag_INSTDATA {
  351.     DWORD                   dwInstKey;
  352.     DWORD                   dwPid;
  353.     LPVOID                  lpvInst[kMaxSet];
  354.     struct tag_INSTDATA     *next;
  355. } INSTDATA, *LPINSTDATA, **HINSTDATA;
  356.  
  357.  
  358. LPINSTDATA      lpInstHead = NULL;
  359.  
  360. #define PvSlowGetInstanceGlobals(_dw, _dwId)    PvGetVerifyInstanceGlobals(_dw, _dwId)
  361.  
  362. VOID
  363. DisposeInstData(LPINSTDATA lpInstPrev, LPINSTDATA lpInst)
  364. {
  365.     HINSTDATA   hInstHead = &lpInstHead;
  366.     
  367.     /* This better only happen when both elements are NULL! */
  368.     if (lpInst->lpvInst[kInstMAPIX] == lpInst->lpvInst[kInstMAPIU])
  369.     {
  370.         /* No inst data, remove element from linked list */
  371.         if (lpInst == *hInstHead)
  372.             *hInstHead = lpInst->next;
  373.         else
  374.             lpInstPrev->next = lpInst->next;
  375.         DisposePtr((Ptr)lpInst);
  376.     }
  377. }
  378.  
  379. /*
  380.  -  PvGetInstanceGlobals
  381.  -  
  382.  *  Purpose:
  383.  *      Returns a pointer to the instance global data structre for
  384.  *      the current task.
  385.  *  
  386.  *  Returns:
  387.  *      Pointer to the instance data structure, or NULL if no
  388.  *      structure has yet been installed for this task.
  389.  */
  390.  
  391. LPVOID FAR PASCAL
  392. PvGetInstanceGlobals(WORD wDataSet)
  393. {
  394.     HINSTDATA       hInstHead = &lpInstHead;
  395.     LPINSTDATA      lpInst = *hInstHead;
  396.  
  397. #ifdef DEBUG
  398.     if (wDataSet >= kMaxSet)
  399.     {
  400.         DebugStr("\pPvGetInstanceGlobals : This data set has not been defined.");
  401.         return NULL;
  402.     }
  403. #endif
  404.  
  405.     while (lpInst)
  406.     {
  407.         if (lpInst->dwInstKey == (DWORD)LMGetCurrentA5())
  408.             break;
  409.         lpInst = lpInst->next;
  410.     } 
  411.     return(lpInst->lpvInst[wDataSet]);
  412. }
  413.  
  414. LPVOID FAR PASCAL
  415. PvGetVerifyInstanceGlobals(DWORD dwPid, DWORD wDataSet)
  416. {
  417.     HINSTDATA   hInstHead = &lpInstHead;
  418.     LPINSTDATA  lpInst, lpInstPrev;
  419.  
  420.     lpInst = lpInstPrev = *hInstHead;
  421.  
  422.     /* Always do the lookup */
  423.     while (lpInst)
  424.     {
  425.         if (lpInst->dwInstKey == (DWORD)LMGetCurrentA5())
  426.             break;
  427.         lpInstPrev = lpInst;
  428.         lpInst = lpInst->next;
  429.     }
  430.  
  431.     /* If PvGetInstanceGlobals() misses, return NULL right away */
  432.     if (lpInst->lpvInst[wDataSet] == NULL)
  433.         return NULL;
  434.  
  435.     /* Found a match, now check the OLE process ID */
  436.     if (dwPid != lpInst->dwPid)
  437.     {
  438.         DisposeInstData(lpInstPrev, lpInst);
  439.         return NULL;
  440.     }
  441.  
  442.  
  443.     /* Return the found value */
  444.     return lpInst->lpvInst[wDataSet];
  445. }
  446.  
  447. /*
  448.  -  ScSetVerifyInstanceGlobals
  449.  -  
  450.  *  Purpose:
  451.  *      Installs or deinstalls instance global data for the current task.
  452.  *  
  453.  *  Arguments:
  454.  *      pv          in      Pointer to instance data structure (to
  455.  *                          install); NULL (to deinstall).
  456.  *      dwPid       in      Zero or process ID, for better matching.
  457.  *      wDataSet    in      Inst data set to init or deinit (MAPIX or MAPIU)
  458.  *  
  459.  *  Returns:
  460.  *      MAPI_E_NOT_ENOUGH_MEMORY if a pointer of INSTDATA size cannot be
  461.  *      created, else 0.
  462.  */
  463.  
  464. LONG FAR PASCAL
  465. ScSetVerifyInstanceGlobals(LPVOID pv, DWORD dwPid, WORD wDataSet)
  466. {
  467.     HINSTDATA       hInstHead = &lpInstHead;
  468.     LPINSTDATA      lpInst, lpInstPrev;
  469.  
  470.     lpInst = lpInstPrev = *hInstHead;
  471.  
  472.     Assert(wDataSet < kMaxSet);
  473.  
  474.     /* Find our linked list element and the one before it */
  475.     while (lpInst)
  476.     {
  477.         if (lpInst->dwInstKey == (DWORD)LMGetCurrentA5())
  478.             break;
  479.         lpInstPrev = lpInst;
  480.         lpInst = lpInst->next;
  481.     }
  482.  
  483.     if (pv)
  484.     {
  485.         if (lpInst)
  486.         {
  487.             /* I am NOT supposed to be in the array at this time! */
  488.             Assert(lpInst->lpvInst[wDataSet] == NULL);
  489.             lpInst->lpvInst[wDataSet] = pv;
  490.         }
  491.         else
  492.         {
  493.             /* Add a new linked list element and store <pv> there. */
  494.             lpInst = (LPVOID) NewPtrClear(sizeof(INSTDATA));
  495.             if (!lpInst)
  496.             {
  497. #ifdef  DEBUG
  498.                 OutputDebugString("Instance globals maxed out\r");
  499. #endif  
  500.                 return MAPI_E_NOT_ENOUGH_MEMORY;
  501.             }
  502.             if (lpInstPrev)
  503.                 lpInstPrev->next = lpInst;
  504.             else
  505.                 *hInstHead = lpInst;
  506.             lpInst->dwInstKey = (DWORD)LMGetCurrentA5();
  507.  
  508.             lpInst->dwPid = dwPid;
  509.             lpInst->lpvInst[wDataSet] = pv;
  510.         }
  511.     }
  512.     else
  513.     {
  514.         /* Deinstalling instance globals. Search and destroy. */
  515.         if (lpInst == NULL || lpInst->lpvInst[wDataSet] == NULL)
  516.         {
  517. #ifdef  DEBUG
  518.             OutputDebugString("No instance globals to reset\r");
  519. #endif  
  520.             return MAPI_E_NOT_INITIALIZED;
  521.         }
  522.         /* The memory for <lpInst->lpvInst[wDataSet]> is disposed of    */
  523.         /* elsewhere. just as it was allocated elsewhere.               */
  524.         lpInst->lpvInst[wDataSet] = NULL;
  525.         DisposeInstData(lpInstPrev, lpInst);
  526.     }
  527.  
  528.     return 0;
  529. }
  530.  
  531.  
  532. LONG FAR PASCAL
  533. ScSetInstanceGlobals(LPVOID pv, WORD wDataSet)
  534. {
  535.     return ScSetVerifyInstanceGlobals(pv, 0L, wDataSet);
  536. }
  537.  
  538. BOOL FAR PASCAL
  539. FCleanupInstanceGlobals(WORD wID, DWORD dwData)
  540. {
  541. /*
  542.  * This is no longer used.
  543.  *
  544.  */
  545.  
  546. #ifdef DEBUG
  547.     DebugStr("\pCalled FCleanupInstanceGlobals : Empty function");
  548. #endif
  549.  
  550.     return 0;
  551. }
  552.  
  553. #else /* !WIN16 && !_MAC */
  554.  
  555. /* This is the entire 32-bit implementation for instance globals. */
  556.  
  557. VOID FAR *pinstX = NULL;
  558.  
  559. #endif  /* WIN16 */
  560.  
  561.