Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

539 lines
12 KiB

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