IMEM.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:15k
源码类别:

Windows编程

开发平台:

Visual C++

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