Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

loadbits.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * Module Name: loadbits.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * Loads and creates icons / cursors / bitmaps. All 3 functions can either 00007 * load from a client resource file, load from user's resource file, or 00008 * load from the display's resource file. Beware that hmodules are not 00009 * unique across processes! 00010 * 00011 * 05-Apr-1991 ScottLu Rewrote to work with client/server 00012 \***************************************************************************/ 00013 00014 #include "precomp.h" 00015 #pragma hdrstop 00016 #include <wchar.h> 00017 00018 /***************************************************************************\ 00019 * _CreateEmptyCursorObject 00020 * 00021 * Creates a cursor object and links it into a cursor list. 00022 * 00023 * 08-Feb-92 ScottLu Created. 00024 \***************************************************************************/ 00025 00026 HCURSOR _CreateEmptyCursorObject( 00027 BOOL fPublic) 00028 { 00029 PCURSOR pcurT; 00030 00031 /* 00032 * Create the cursor object. 00033 */ 00034 pcurT = (PCURSOR)HMAllocObject(PtiCurrent(), 00035 NULL, 00036 TYPE_CURSOR, 00037 max(sizeof(CURSOR), 00038 sizeof(ACON))); 00039 00040 if (fPublic && (pcurT != NULL)) { 00041 pcurT->head.ppi = NULL; 00042 UserAssert(PtiCurrent()->TIF_flags & (TIF_CSRSSTHREAD | TIF_SYSTEMTHREAD)); 00043 } 00044 00045 return (HCURSOR)PtoH(pcurT); 00046 } 00047 00048 /***************************************************************************\ 00049 * DestroyEmptyCursorObject 00050 * UnlinkCursor 00051 * 00052 * Destroys an empty cursor object (structure holds nothing that needs 00053 * destroying). 00054 * 00055 * 08-Feb-1992 ScottLu Created. 00056 \***************************************************************************/ 00057 VOID UnlinkCursor( 00058 PCURSOR pcur) 00059 { 00060 PCURSOR *ppcurT; 00061 BOOL fTriedPublicCache; 00062 BOOL fTriedThisProcessCache = FALSE; 00063 00064 /* 00065 * First unlink this cursor object from the cursor list (it will be the 00066 * first one in the list, so this'll be fast... but just in case, make 00067 * it a loop). 00068 */ 00069 if (fTriedPublicCache = (pcur->head.ppi == NULL)) { 00070 ppcurT = &gpcurFirst; 00071 } else { 00072 ppcurT = &pcur->head.ppi->pCursorCache; 00073 } 00074 00075 LookAgain: 00076 00077 for (; *ppcurT != NULL; ppcurT = &((*ppcurT)->pcurNext)) { 00078 if (*ppcurT == pcur) { 00079 *ppcurT = pcur->pcurNext; 00080 FreeIt: 00081 pcur->pcurNext = NULL; 00082 pcur->CURSORF_flags &= ~CURSORF_LINKED; 00083 return; 00084 } 00085 } 00086 00087 /* 00088 * If we get here, it means that the cursor used to be public but 00089 * got assigned to the current thread due to being unlocked. We 00090 * have to look for it in the public cache. 00091 */ 00092 if (!fTriedPublicCache) { 00093 ppcurT = &gpcurFirst; 00094 fTriedPublicCache = TRUE; 00095 goto LookAgain; 00096 } 00097 00098 /* 00099 * If we got here, it means that it was locked during process 00100 * cleanup and got assigned to no owner. Try the current process 00101 * cache. 00102 */ 00103 if (!fTriedThisProcessCache) { 00104 ppcurT = &PpiCurrent()->pCursorCache; 00105 fTriedThisProcessCache = TRUE; 00106 goto LookAgain; 00107 } 00108 00109 /* 00110 * Getting Desperate here... Look through every cursor and process 00111 * cache for it. 00112 */ 00113 { 00114 PHE pheMax, pheT; 00115 00116 pheMax = &gSharedInfo.aheList[giheLast]; 00117 for (pheT = gSharedInfo.aheList; pheT <= pheMax; pheT++) { 00118 if (pheT->bType == TYPE_CURSOR) { 00119 if (((PCURSOR)pheT->phead)->pcurNext == pcur) { 00120 ((PCURSOR)pheT->phead)->pcurNext = pcur->pcurNext; 00121 goto FreeIt; 00122 } else if (pheT->pOwner && ((PPROCESSINFO)pheT->pOwner)->pCursorCache == pcur) { 00123 ((PPROCESSINFO)pheT->pOwner)->pCursorCache = pcur->pcurNext; 00124 goto FreeIt; 00125 } 00126 } 00127 } 00128 } 00129 00130 UserAssert(FALSE); 00131 } 00132 00133 /***************************************************************************\ 00134 * DestroyEmptyCursorObject 00135 * 00136 \***************************************************************************/ 00137 00138 VOID DestroyEmptyCursorObject( 00139 PCURSOR pcur) 00140 { 00141 if (pcur->CURSORF_flags & CURSORF_LINKED) { 00142 UnlinkCursor(pcur); 00143 } 00144 00145 HMFreeObject(pcur); 00146 } 00147 00148 /***************************************************************************\ 00149 * ZombieCursor 00150 * 00151 * Unlink the cursor and set its owner to the system process. 00152 * 00153 * 3-Sep-1997 vadimg created 00154 \***************************************************************************/ 00155 00156 VOID ZombieCursor(PCURSOR pcur) 00157 { 00158 if (pcur->CURSORF_flags & CURSORF_LINKED) { 00159 UnlinkCursor(pcur); 00160 } 00161 00162 #if DBG 00163 if (ISTS()) { 00164 PHE phe; 00165 phe = HMPheFromObject(pcur); 00166 00167 if (phe->pOwner == NULL) { 00168 RIPMSG2(RIP_ERROR, "NULL owner for cursor %x phe %x\n", 00169 pcur, phe); 00170 } 00171 } 00172 #endif // DBG 00173 00174 HMChangeOwnerProcess(pcur, gptiRit); 00175 00176 RIPMSG1(RIP_WARNING, "ZombieCursor: 0x%08X became a zombie", pcur); 00177 } 00178 00179 /***************************************************************************\ 00180 * ResStrCmp 00181 * 00182 * This function compares two strings taking into account that one or both 00183 * of them may be resource IDs. The function returns a TRUE if the strings 00184 * are equal, instead of the zero lstrcmp() returns. 00185 * 00186 * History: 00187 * 20-Apr-91 DavidPe Created 00188 \***************************************************************************/ 00189 00190 BOOL ResStrCmp( 00191 PUNICODE_STRING cczpstr1, 00192 PUNICODE_STRING pstr2) 00193 { 00194 BOOL retval = FALSE; 00195 /* 00196 * pstr1 is a STRING that is in kernel space, but the buffer may 00197 * be in client space. 00198 */ 00199 00200 if (cczpstr1->Length == 0) { 00201 00202 /* 00203 * pstr1 is a resource ID, so just compare the values. 00204 */ 00205 if (cczpstr1->Buffer == pstr2->Buffer) 00206 return TRUE; 00207 00208 } else { 00209 00210 try { 00211 /* 00212 * pstr1 is a string. if pstr2 is an actual string compare the 00213 * string values; if pstr2 is not a string then pstr1 may be an 00214 * "integer string" of the form "#123456". so convert it to an 00215 * integer and compare the integers. 00216 * Before calling lstrcmp(), make sure pstr2 is an actual 00217 * string, not a resource ID. 00218 */ 00219 if (pstr2->Length != 0) { 00220 00221 if (RtlEqualUnicodeString(cczpstr1, pstr2, TRUE)) 00222 retval = TRUE; 00223 00224 } else if (cczpstr1->Buffer[0] == '#') { 00225 00226 UNICODE_STRING strId; 00227 int id; 00228 00229 strId.Length = cczpstr1->Length - sizeof(WCHAR); 00230 strId.MaximumLength = strId.Length; 00231 strId.Buffer = cczpstr1->Buffer + 1; 00232 RtlUnicodeStringToInteger(&strId, 10, (PULONG)&id); 00233 00234 if (id == (LONG_PTR)pstr2->Buffer) 00235 retval = TRUE; 00236 } 00237 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 00238 } 00239 } 00240 00241 return retval; 00242 } 00243 00244 /***********************************************************************\ 00245 * SearchIconCache 00246 * 00247 * Worker routine for FindExistingCursorIcon(). 00248 * 00249 * Returns: pCurFound 00250 * 00251 * 28-Sep-1995 SanfordS Created. 00252 \***********************************************************************/ 00253 00254 PCURSOR SearchIconCache( 00255 PCURSOR pCursorCache, 00256 ATOM atomModName, 00257 PUNICODE_STRING cczpstrResName, 00258 PCURSOR pcurSrc, 00259 PCURSORFIND pcfSearch) 00260 { 00261 /* 00262 * Run through the list of 'resource' objects created, 00263 * and see if the cursor requested has already been loaded. 00264 * If so just return it. We do this to be consistent with 00265 * Win 3.0 where they simply return a pointer to the res-data 00266 * for a cursor/icon handle. Many apps count on this and 00267 * call LoadCursor/Icon() often. 00268 * 00269 * LR_SHARED implies: 00270 * 1) icons never get deleted till process (LATER or WOW module) 00271 * goes away. 00272 * 2) This cache is consulted before trying to load a res. 00273 */ 00274 for (; pCursorCache != NULL; pCursorCache = pCursorCache->pcurNext) { 00275 00276 /* 00277 * If we are given a specific cursor to look for, then 00278 * search for that first. 00279 */ 00280 if (pcurSrc && (pCursorCache == pcurSrc)) 00281 return pcurSrc; 00282 00283 /* 00284 * No need to look further if the module name doesn't match. 00285 */ 00286 if (atomModName != pCursorCache->atomModName) 00287 continue; 00288 00289 /* 00290 * We only return images that cannot be destroyed by the app. 00291 * so we don't have to deal with ref counts. This is owned 00292 * by us, but not LR_SHARED. 00293 */ 00294 if (!(pCursorCache->CURSORF_flags & CURSORF_LRSHARED)) 00295 continue; 00296 00297 /* 00298 * Check the other distinguishing search criteria for 00299 * a match. 00300 */ 00301 if ((pCursorCache->rt == LOWORD(pcfSearch->rt)) && 00302 ResStrCmp(cczpstrResName, &pCursorCache->strName)) { 00303 00304 /* 00305 * Acons don't have a size per se because each frame 00306 * can be a different size. We always make it a hit 00307 * on acons so replacement of system icons is possible. 00308 */ 00309 if (pCursorCache->CURSORF_flags & CURSORF_ACON) 00310 return pCursorCache; 00311 00312 /* 00313 * First hit wins. Nothing fancy here. Apps that use 00314 * LR_SHARED have to watch out for this. 00315 */ 00316 if ((!pcfSearch->cx || (pCursorCache->cx == pcfSearch->cx)) && 00317 (!pcfSearch->cy || ((pCursorCache->cy / 2) == pcfSearch->cy)) && 00318 (!pcfSearch->bpp || (pCursorCache->bpp == pcfSearch->bpp))) { 00319 00320 return pCursorCache; 00321 } 00322 } 00323 } 00324 00325 return NULL; 00326 } 00327 00328 /***********************************************************************\ 00329 * _FindExistingCursorIcon 00330 * 00331 * This routine searches all existing icons for one matching the properties 00332 * given. This routine will only return cursors/icons that are of 00333 * the type that cannot be destroyed by the app. (CURSORF_LRSHARED or 00334 * unowned) and will take the first hit it finds. 00335 * 00336 * 32bit apps that call LoadImage() will normally not have this cacheing 00337 * feature unless they specify LR_SHARED. If they do so, it is the apps 00338 * responsability to be careful with how they use the cache since wild 00339 * lookups (ie 0s in cx, cy or bpp) will result in different results 00340 * depending on the history of icon/cursor creation. It is thus recommended 00341 * that apps only use the LR_SHARED option when they are only working 00342 * with one size/colordepth of icon or when they call LoadImage() with 00343 * specific size and/or color content requested. 00344 * 00345 * For the future it would be nice to have a cacheing scheeme that would 00346 * simply be used to speed up reloading of images. To do this right, 00347 * you would need ref counts to allow deletes to work properly and would 00348 * have to remember whether the images in the cache had been stretched 00349 * or color munged so you don't allow restretching. 00350 * 00351 * Returns: pcurFound 00352 * 00353 * 00354 * 17-Sep-1995 SanfordS Created. 00355 \***********************************************************************/ 00356 00357 PCURSOR _FindExistingCursorIcon( 00358 ATOM atomModName, 00359 PUNICODE_STRING cczpstrResName, 00360 PCURSOR pcurSrc, 00361 PCURSORFIND pcfSearch) 00362 { 00363 PCURSOR pcurT = NULL; 00364 00365 /* 00366 * If rt is zero we're doing an indirect create, so matching with 00367 * a previously loaded cursor/icon would be inappropriate. 00368 */ 00369 if (pcfSearch->rt && atomModName) { 00370 00371 pcurT = SearchIconCache(PpiCurrent()->pCursorCache, 00372 atomModName, 00373 cczpstrResName, 00374 pcurSrc, 00375 pcfSearch); 00376 if (pcurT == NULL) { 00377 pcurT = SearchIconCache(gpcurFirst, 00378 atomModName, 00379 cczpstrResName, 00380 pcurSrc, 00381 pcfSearch); 00382 } 00383 } 00384 00385 return pcurT; 00386 } 00387 00388 /***************************************************************************\ 00389 * _InternalGetIconInfo 00390 * 00391 * History: 00392 * 09-Mar-1993 MikeKe Created. 00393 \***************************************************************************/ 00394 00395 BOOL _InternalGetIconInfo( 00396 IN PCURSOR pcur, 00397 OUT PICONINFO ccxpiconinfo, 00398 OUT OPTIONAL PUNICODE_STRING pstrInstanceName, 00399 OUT OPTIONAL PUNICODE_STRING pstrResName, 00400 OUT OPTIONAL LPDWORD ccxpbpp, 00401 IN BOOL fInternalCursor) 00402 { 00403 HBITMAP hbmBitsT; 00404 HBITMAP hbmDstT; 00405 HBITMAP hbmMask; 00406 HBITMAP hbmColor; 00407 00408 /* 00409 * Note -- while the STRING structures are in kernel mode memory, the 00410 * buffers are in user-mode memory. So all use of the buffers should 00411 * be protected bytry blocks. 00412 */ 00413 00414 /* 00415 * If this is an animated cursor, just grab the first frame and return 00416 * the info for it. 00417 */ 00418 if (pcur->CURSORF_flags & CURSORF_ACON) 00419 pcur = ((PACON)pcur)->aspcur[0]; 00420 00421 /* 00422 * Make copies of the bitmaps 00423 * 00424 * If the color bitmap is around, then there is no XOR mask in the 00425 * hbmMask bitmap. 00426 */ 00427 hbmMask = GreCreateBitmap( 00428 pcur->cx, 00429 (pcur->hbmColor && !fInternalCursor) ? pcur->cy / 2 : pcur->cy, 00430 1, 00431 1, 00432 NULL); 00433 00434 if (hbmMask == NULL) 00435 return FALSE; 00436 00437 00438 hbmColor = NULL; 00439 00440 if (pcur->hbmColor != NULL) { 00441 00442 hbmColor = GreCreateCompatibleBitmap(HDCBITS(), 00443 pcur->cx, 00444 pcur->cy / 2); 00445 00446 if (hbmColor == NULL) { 00447 GreDeleteObject(hbmMask); 00448 return FALSE; 00449 } 00450 } 00451 00452 hbmBitsT = GreSelectBitmap(ghdcMem2, pcur->hbmMask); 00453 hbmDstT = GreSelectBitmap(ghdcMem, hbmMask); 00454 00455 GreBitBlt(ghdcMem, 00456 0, 00457 0, 00458 pcur->cx, 00459 (pcur->hbmColor && !fInternalCursor) ? pcur->cy / 2 : pcur->cy, 00460 ghdcMem2, 00461 0, 00462 0, 00463 SRCCOPY, 00464 0x00ffffff); 00465 00466 if (hbmColor != NULL) { 00467 00468 GreSelectBitmap(ghdcMem2, pcur->hbmColor); 00469 GreSelectBitmap(ghdcMem, hbmColor); 00470 00471 GreBitBlt(ghdcMem, 00472 0, 00473 0, 00474 pcur->cx, 00475 pcur->cy / 2, 00476 ghdcMem2, 00477 0, 00478 0, 00479 SRCCOPY, 00480 0); 00481 } 00482 00483 GreSelectBitmap(ghdcMem2, hbmBitsT); 00484 GreSelectBitmap(ghdcMem, hbmDstT); 00485 00486 /* 00487 * Fill in the iconinfo structure. make copies of the bitmaps. 00488 */ 00489 try { 00490 00491 ccxpiconinfo->fIcon = (pcur->rt == PTR_TO_ID(RT_ICON)); 00492 ccxpiconinfo->xHotspot = pcur->xHotspot; 00493 ccxpiconinfo->yHotspot = pcur->yHotspot; 00494 ccxpiconinfo->hbmMask = hbmMask; 00495 ccxpiconinfo->hbmColor = hbmColor; 00496 00497 if (pstrInstanceName != NULL) { 00498 00499 if (pcur->atomModName) { 00500 pstrInstanceName->Length = (USHORT) 00501 UserGetAtomName(pcur->atomModName, 00502 pstrInstanceName->Buffer, 00503 (int) (pstrInstanceName->MaximumLength / sizeof(WCHAR)) 00504 * sizeof(WCHAR)); 00505 } else { 00506 pstrInstanceName->Length = 0; 00507 } 00508 } 00509 00510 if (pstrResName != NULL) { 00511 00512 if (IS_PTR(pcur->strName.Buffer)) { 00513 RtlCopyUnicodeString(pstrResName, &pcur->strName); 00514 } else { 00515 *pstrResName = pcur->strName; 00516 } 00517 } 00518 00519 if (ccxpbpp) 00520 *ccxpbpp = pcur->bpp; 00521 00522 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 00523 GreDeleteObject(hbmMask); 00524 GreDeleteObject(hbmColor); 00525 return FALSE; 00526 } 00527 00528 return TRUE; 00529 } 00530 00531 /***************************************************************************\ 00532 * _DestroyCursor 00533 * 00534 * History: 00535 * 25-Apr-1991 DavidPe Created. 00536 * 04-Aug-1992 DarrinM Now destroys ACONs as well. 00537 \***************************************************************************/ 00538 00539 BOOL _DestroyCursor( 00540 PCURSOR pcur, 00541 DWORD cmdDestroy) 00542 { 00543 PPROCESSINFO ppi; 00544 PPROCESSINFO ppiCursor; 00545 int i; 00546 extern BOOL DestroyAniIcon(PACON pacon); 00547 00548 if (pcur == NULL) { 00549 UserAssert(FALSE); 00550 return(TRUE); 00551 } 00552 ppi = PpiCurrent(); 00553 ppiCursor = GETPPI(pcur); 00554 00555 /* 00556 * Remove this icon from the caption icon cache. 00557 */ 00558 for (i = 0; i < CCACHEDCAPTIONS; i++) { 00559 if (gcachedCaptions[i].spcursor == pcur) { 00560 Unlock( &(gcachedCaptions[i].spcursor) ); 00561 } 00562 } 00563 00564 /* 00565 * First step in destroying an cursor 00566 */ 00567 switch (cmdDestroy) { 00568 00569 case CURSOR_ALWAYSDESTROY: 00570 00571 /* 00572 * Always destroy? then don't do any checking... 00573 */ 00574 break; 00575 00576 case CURSOR_CALLFROMCLIENT: 00577 00578 /* 00579 * Can't destroy public cursors/icons. 00580 */ 00581 if (ppiCursor == NULL) 00582 /* 00583 * Fake success if its a resource loaded icon because 00584 * this is how win95 responded. 00585 */ 00586 return !!(pcur->CURSORF_flags & CURSORF_FROMRESOURCE); 00587 00588 /* 00589 * If this cursor was loaded from a resource, don't free it till the 00590 * process exits. This is the way we stay compatible with win3.0's 00591 * cursors which were actually resources. Resources under win3 have 00592 * reference counting and other "features" like handle values that 00593 * never change. Read more in the comment in 00594 * ServerLoadCreateCursorIcon(). 00595 */ 00596 if (pcur->CURSORF_flags & (CURSORF_LRSHARED | CURSORF_SECRET)) { 00597 return TRUE; 00598 } 00599 00600 /* 00601 * One thread can't destroy the objects created by another. 00602 */ 00603 if (ppiCursor != ppi) { 00604 RIPERR0(ERROR_DESTROY_OBJECT_OF_OTHER_THREAD, RIP_ERROR, "DestroyCursor: cursor belongs to another process"); 00605 return FALSE; 00606 } 00607 00608 /* 00609 * fall through. 00610 */ 00611 00612 case CURSOR_THREADCLEANUP: 00613 00614 /* 00615 * Don't destroy public objects either (pretend it worked though). 00616 */ 00617 if (ppiCursor == NULL) 00618 return TRUE; 00619 break; 00620 } 00621 00622 /* 00623 * First mark the object for destruction. This tells the locking code that 00624 * we want to destroy this object when the lock count goes to 0. If this 00625 * returns FALSE, we can't destroy the object yet. 00626 */ 00627 if (!HMMarkObjectDestroy((PHEAD)pcur)) 00628 return FALSE; 00629 00630 if (pcur->strName.Length != 0) { 00631 UserFreePool((LPSTR)pcur->strName.Buffer); 00632 } 00633 00634 if (pcur->atomModName != 0) { 00635 UserDeleteAtom(pcur->atomModName); 00636 } 00637 00638 /* 00639 * If this is an ACON call its special routine to destroy it. 00640 */ 00641 if (pcur->CURSORF_flags & CURSORF_ACON) { 00642 DestroyAniIcon((PACON)pcur); 00643 } else { 00644 if (pcur->hbmMask != NULL) { 00645 GreDeleteObject(pcur->hbmMask); 00646 GreDecQuotaCount((PW32PROCESS)(pcur->head.ppi)); 00647 } 00648 if (pcur->hbmColor != NULL) { 00649 GreDeleteObject(pcur->hbmColor); 00650 GreDecQuotaCount((PW32PROCESS)(pcur->head.ppi)); 00651 } 00652 if (pcur->hbmAlpha != NULL) { 00653 /* 00654 * This is an internal GDI object, and so not covered by quota. 00655 */ 00656 GreDeleteObject(pcur->hbmAlpha); 00657 } 00658 } 00659 00660 /* 00661 * Ok to destroy... Free the handle (which will free the object and the 00662 * handle). 00663 */ 00664 DestroyEmptyCursorObject(pcur); 00665 return TRUE; 00666 } 00667 00668 00669 00670 /***************************************************************************\ 00671 * DestroyUnlockedCursor 00672 * 00673 * Called when a cursor is destoyed due to an unlock. 00674 * 00675 * History: 00676 * 24-Feb-1997 adams Created. 00677 \***************************************************************************/ 00678 00679 void 00680 DestroyUnlockedCursor(void * pv) 00681 { 00682 _DestroyCursor((PCURSOR)pv, CURSOR_THREADCLEANUP); 00683 } 00684 00685 00686 00687 /***************************************************************************\ 00688 * _SetCursorContents 00689 * 00690 * 00691 * History: 00692 * 27-Apr-1992 ScottLu Created. 00693 \***************************************************************************/ 00694 00695 BOOL _SetCursorContents( 00696 PCURSOR pcur, 00697 PCURSOR pcurNew) 00698 { 00699 HBITMAP hbmpT; 00700 00701 if (!(pcur->CURSORF_flags & CURSORF_ACON)) { 00702 00703 /* 00704 * Swap bitmaps. 00705 */ 00706 hbmpT = pcur->hbmMask; 00707 pcur->hbmMask = pcurNew->hbmMask; 00708 pcurNew->hbmMask = hbmpT; 00709 00710 hbmpT = pcur->hbmColor; 00711 pcur->hbmColor = pcurNew->hbmColor; 00712 pcurNew->hbmColor = hbmpT; 00713 00714 /* 00715 * Remember hotspot info and size info 00716 */ 00717 pcur->xHotspot = pcurNew->xHotspot; 00718 pcur->yHotspot = pcurNew->yHotspot; 00719 pcur->cx = pcurNew->cx; 00720 pcur->cy = pcurNew->cy; 00721 } 00722 00723 /* 00724 * Destroy the cursor we copied from. 00725 */ 00726 _DestroyCursor(pcurNew, CURSOR_THREADCLEANUP); 00727 00728 return (BOOL)TRUE; 00729 }

Generated on Sat May 15 19:40:38 2004 for test by doxygen 1.3.7