|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1992.
//
// File: lock.cxx
//
// Contents: Remote exclusion stuff for docfile
//
// Functions: GetAccess
// ReleaseAccess
// GetOpen
// ReleaseOpen
//
// History: 09-Mar-92 PhilipLa Created.
// 20-Jul-93 DrewB Added dual locking for Mac
// compatibility
//
//--------------------------------------------------------------------------
#include <exphead.cxx>
#pragma hdrstop
#include <header.hxx>
#include <lock.hxx>
// Offset to next lock group from a particular group
#define OLOCKGROUP 1
// The docfile originally locked at 0xffffff00
// It turned out that the Mac can only lock to 0x7fffffff,
// so for compatibility reasons it was decided that the
// docfile would lock at both places. Thus, we have one routine
// that locks with a mask for the offset so that we can
// selectively suppress the high bit
// Since lock indices fit easily within 16 bits, the two
// lock indices are now combined into the existing ULONG
// value to preserve compatibility with other code. This
// implies that lock indices from these routines must be
// handled opaquely since they are no longer simple numbers
// 09/23/1993 - Further change:
// To avoid a Netware 2.2 problem we are offsetting the lock regions
// so that they differ by more than just the high bit. The high
// lock region was moved to 0xffffff80, moving the low region to
// 0x7fffff80. The 0x80 was then taken out of the high mask so that
// the net is no change for high locks and the low locks moved up by 0x80
// Masks for separate lock locations
// moved to lock.hxx
//In a specific open case (Read-only, deny-write), we don't need to
//take locks.
#define P_NOLOCK(df) (!P_WRITE(df) && P_READ(df) && \
P_DENYWRITE(df) && !P_DENYREAD(df))
//+--------------------------------------------------------------
//
// Function: GetAccessWithMask, private
//
// Synopsis: Takes appropriate access locks on an LStream,
// masking the offset with the given mask
//
// Arguments: [plst] - LStream
// [df] - Permissions needed
// [ulMask] - Mask
// [poReturn] - Index of lock taken
//
// Returns: Appropriate status code
//
// Modifies: [poReturn]
//
// History: 08-Apr-92 DrewB Created
//
//---------------------------------------------------------------
SCODE GetAccessWithMask(ILockBytes *plst, DFLAGS df, ULONG ulMask, ULONG *poReturn) { SCODE sc; ULARGE_INTEGER ulOffset, cbLength;
olDebugOut((DEB_ITRACE, "In GetAccessWithMask(%p, %X, %lX, %p)\n", plst, df, ulMask, poReturn)); olAssert((df & ~(DF_READ | DF_WRITE)) == 0 && P_READ(df) != P_WRITE(df)); *poReturn = NOLOCK; ULISet32(ulOffset, OACCESS & ulMask); if (P_READ(df)) { ULISet32(cbLength, 1); olHChk(plst->LockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); for (USHORT i = 0; i < CREADLOCKS; i++) { ULISetLow(ulOffset, (OREADLOCK+i) & ulMask); sc = DfGetScode(plst->LockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); if (SUCCEEDED(sc)) { *poReturn = i+1; break; } } ULISetLow(ulOffset, OACCESS & ulMask); olHVerSucc(sc = plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); if (i == CREADLOCKS) olErr(EH_Err, STG_E_TOOMANYOPENFILES); } else { olAssert((OACCESS + 1 == OREADLOCK) && aMsg("Bad lock dependency")); ULISet32(cbLength, 1 + CREADLOCKS); olChk(DfGetScode(plst->LockRegion(ulOffset, cbLength, LOCK_ONLYONCE))); *poReturn = 0xFFFF; } olDebugOut((DEB_ITRACE, "Out GetAccessWithMask => %lu\n", *poReturn)); olAssert(*poReturn != NOLOCK); return S_OK; EH_Err: return sc; }
//+--------------------------------------------------------------
//
// Function: ReleaseAccessWithMask, private
//
// Synopsis: Releases an access lock at the given offset
//
// Arguments: [plst] - LStream that is locked
// [df] - Permission to release
// [offset] - Offset of locks taken
// [ulMask] - Mask
//
// History: 08-Apr-92 DrewB Created
//
//---------------------------------------------------------------
void ReleaseAccessWithMask(ILockBytes *plst, DFLAGS df, ULONG offset, ULONG ulMask) { ULARGE_INTEGER ulOffset, cbLength; SCODE scTemp;
olDebugOut((DEB_ITRACE, "In ReleaseAccessWithMask(%p, %lX, %lu, %lX)\n", plst, df, offset, ulMask)); olAssert((df & ~(DF_READ | DF_WRITE)) == 0 && P_READ(df) != P_WRITE(df)); if (offset == NOLOCK) return; if (P_READ(df)) { ULISet32(ulOffset, (offset+OREADLOCK-1) & ulMask); ULISet32(cbLength, 1); scTemp = plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE); } else { olAssert((OACCESS + 1 == OREADLOCK) && aMsg("Bad lock dependency")); ULISet32(ulOffset, OACCESS & ulMask); ULISet32(cbLength, 1 + CREADLOCKS); scTemp = plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE); } olDebugOut((DEB_ITRACE, "Out ReleaseAccessWithMask\n")); }
//+--------------------------------------------------------------
//
// Function: GetAccess, public
//
// Synopsis: Takes appropriate access locks on an LStream
//
// Arguments: [plst] - LStream
// [df] - Permissions needed
// [poReturn] - Index of lock taken
//
// Returns: Appropriate status code
//
// Modifies: [poReturn]
//
// History: 08-Apr-92 DrewB Created
//
//---------------------------------------------------------------
SCODE GetAccess(ILockBytes *plst, DFLAGS df, ULONG *poReturn) { SCODE sc;
olDebugOut((DEB_ITRACE, "In GetAccess(%p, %X, %p)\n", plst, df, poReturn));
// Make sure our lock region hasn't overflowed 32 bits
olAssert(OLOCKREGIONEND > OACCESS);
olChk(GetAccessWithMask(plst, df, 0xFFFFFFFF, poReturn)); olAssert(*poReturn < 0x10000);
olDebugOut((DEB_ITRACE, "Out GetAccess => %lu\n", *poReturn)); return S_OK;
EH_Err: *poReturn = NOLOCK; return sc; }
//+--------------------------------------------------------------
//
// Function: ReleaseAccess, public
//
// Synopsis: Releases access locks
//
// Arguments: [plst] - LStream that is locked
// [df] - Permission to release
// [offset] - Offset of locks taken
//
// History: 08-Apr-92 DrewB Created
//
//---------------------------------------------------------------
void ReleaseAccess(ILockBytes *plst, DFLAGS df, ULONG offset) { olDebugOut((DEB_ITRACE, "In ReleaseAccess(%p, %lX, %lu)\n", plst, df, offset));
ReleaseAccessWithMask(plst, df, offset & 0xffff, 0xFFFFFFFF);
olDebugOut((DEB_ITRACE, "Out ReleaseAccess\n")); }
//+--------------------------------------------------------------
//
// Function: GetOpenWithMask, private
//
// Synopsis: Gets locks on an LStream during opening, masking the offset
//
// Arguments: [plst] - LStream
// [df] - Permissions to take
// [fCheck] - Whether to check for existing locks or not
// [ulMask] - Mask
// [puReturn] - Index of lock taken
//
// Returns: Appropriate status code
//
// Modifies: [puReturn]
//
// History: 08-Apr-92 DrewB Created
//
//---------------------------------------------------------------
#define WAITUPDATE_INITIAL 100
#define WAITUPDATE_TIMEOUT 10000
SCODE GetOpenWithMask(ILockBytes *plst, DFLAGS df, BOOL fCheck, ULONG ulMask, ULONG *puReturn) { SCODE sc; ULONG i; ULARGE_INTEGER ulOffset, cbLength; #ifdef DIRECTWRITERLOCK
BOOL fDirectWriterMode = P_READWRITE(df) && !P_TRANSACTED(df) && !P_DENYREAD(df) && P_DENYWRITE(df); BOOL fDirectReaderMode = P_READ(df) && !P_WRITE(df) && !P_TRANSACTED(df) && !P_DENYREAD(df) && !P_DENYWRITE(df); #endif
olDebugOut((DEB_ITRACE, "In GetOpenWithMask(%p, %lX, %d, %lX, %p)\n", plst, df, fCheck, ulMask, puReturn)); *puReturn = NOLOCK;
ULISet32(ulOffset, OUPDATE & ulMask); ULISet32(cbLength, 1);
//Do a graceful fallback.
DWORD dwWait = WAITUPDATE_INITIAL; for (;;) { sc = plst->LockRegion(ulOffset, cbLength, LOCK_ONLYONCE); if (sc != STG_E_LOCKVIOLATION || dwWait >= WAITUPDATE_TIMEOUT) break; Sleep(dwWait); dwWait *= (GetTickCount() & 1) ? 1 : 2; } olChk(sc);
if (fCheck) { ULISetLow(cbLength, COPENLOCKS); if (P_DENYREAD(df)) { ULISetLow(ulOffset, OOPENREADLOCK & ulMask); olHChkTo(EH_UnlockUpdate, plst->LockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); } #ifndef USE_NOSNAPSHOT
if (P_DENYWRITE(df)) #else
if (P_DENYWRITE(df) || P_NOSNAPSHOT(df)) #endif
{ ULISetLow(ulOffset, OOPENWRITELOCK & ulMask); sc = plst->LockRegion(ulOffset, cbLength, LOCK_ONLYONCE); if (SUCCEEDED(sc)) { olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); } #ifdef USE_NOSNAPSHOT
else if (P_NOSNAPSHOT(df)) { //There is an existing writer. In order for this
//open to succeed, there must also be a lock in the
//no-snapshot region. Otherwise we have a case where
//a normal open proceeded a no-snapshot open attempt,
//and mixing modes is not allowed.
ULISetLow(ulOffset, OOPENNOSNAPSHOTLOCK & ulMask); sc = plst->LockRegion(ulOffset, cbLength, LOCK_ONLYONCE); if (SUCCEEDED(sc)) { //There was no no-snapshot lock. No mixing modes,
//so fail here.
olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); olErr(EH_UnlockUpdate, STG_E_LOCKVIOLATION); } } #endif
else { olErr(EH_UnlockUpdate, sc); } } if (P_READ(df)) { ULISetLow(ulOffset, OOPENDENYREADLOCK & ulMask); olHChkTo(EH_UnlockUpdate, plst->LockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); } if (P_WRITE(df)) { ULISetLow(ulOffset, OOPENDENYWRITELOCK & ulMask); #ifndef USE_NOSNAPSHOT
olHChkTo(EH_UnlockUpdate, plst->LockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); #else
sc = plst->LockRegion(ulOffset, cbLength, LOCK_ONLYONCE); if (P_NOSNAPSHOT(df) && (sc == STG_E_LOCKVIOLATION)) { //The deny-write lock may be the fake holder we use for
//no-snapshot mode. Check then no-snapshot region - if
//there is a lock there too, then this succeeds, otherwise
//the deny-write lock is real and we must fail the call.
ULISetLow(ulOffset, OOPENNOSNAPSHOTLOCK & ulMask); sc = plst->LockRegion(ulOffset, cbLength, LOCK_ONLYONCE); if (sc != STG_E_LOCKVIOLATION) { if (SUCCEEDED(sc)) { olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); olErr(EH_UnlockUpdate, STG_E_LOCKVIOLATION); } else { olErr(EH_UnlockUpdate, sc); } } } else { olHChkTo(EH_UnlockUpdate, sc); olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); } #endif
} } //If we are read-only and deny-write, and we are on our
// ILockBytes, we don't need to lock and can rely on the FS
// to handle the access control.
if (P_NOLOCK(df)) { //QueryInterface to see if this ILockBytes is ours
IFileLockBytes *pfl; if (SUCCEEDED(plst->QueryInterface(IID_IFileLockBytes, (void **) &pfl))) { pfl->Release(); ULISetLow(ulOffset, OUPDATE & ulMask); ULISetLow(cbLength, 1); olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); *puReturn = NOLOCK; return S_OK; } }
ULISetLow(cbLength, 1); for (i = 0; i < COPENLOCKS; i = i + OLOCKGROUP) { ULISetLow(ulOffset, (OOPENREADLOCK+i) & ulMask); olHChkTo(EH_Loop, plst->LockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); ULISetLow(ulOffset, (OOPENWRITELOCK+i) & ulMask); olHChkTo(EH_UnlockR, plst->LockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); ULISetLow(ulOffset, (OOPENDENYREADLOCK+i) & ulMask); #ifdef DIRECTWRITERLOCK
if (fCheck == TRUE || fDirectWriterMode == FALSE) #endif
olHChkTo(EH_UnlockW, plst->LockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); ULISetLow(ulOffset, (OOPENDENYWRITELOCK+i) & ulMask); #ifdef USE_NOSNAPSHOT
olHChkTo(EH_UnlockDR, plst->LockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); if (P_NOSNAPSHOT(df)) { //Note that in the non no-snapshot case we don't need to
//grab this lock, unlike the others where we must grab all
//four to make sure we have a valid slot. This is because
//a no-snapshot open will always have a corresponding
//deny-write lock in the same slot.
ULISetLow(ulOffset, (OOPENNOSNAPSHOTLOCK+i) & ulMask); if (SUCCEEDED(DfGetScode(plst->LockRegion(ulOffset, cbLength, LOCK_ONLYONCE)))) { break; } //Unlock the deny-write lock, then all the rest.
ULISetLow(ulOffset, (OOPENDENYWRITELOCK + i)); olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); } else { //We're not no-snapshot, and we've gotten all our locks
// successfully, so bail.
#ifdef DIRECTWRITERLOCK
if (fDirectReaderMode) { ULISetLow(ulOffset, (ODIRECTWRITERLOCK+i) & ulMask); if(SUCCEEDED(plst->LockRegion(ulOffset,cbLength,LOCK_ONLYONCE))) break; } else #endif
break; } EH_UnlockDR: #else
if (SUCCEEDED(DfGetScode(plst->LockRegion(ulOffset, cbLength, LOCK_ONLYONCE)))) #ifdef DIRECTWRITERLOCK
if (fDirectReaderMode) { ULISetLow(ulOffset, (ODIRECTWRITERLOCK+i) & ulMask); if(SUCCEEDED(plst->LockRegion(ulOffset,cbLength,LOCK_ONLYONCE))) break; } else #endif
break; #endif //USE_NOSNAPSHOT
ULISetLow(ulOffset, (OOPENDENYREADLOCK+i) & ulMask); #ifdef DIRECTWRITERLOCK
if (fCheck == TRUE || fDirectWriterMode == FALSE) #endif
olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); EH_UnlockW: ULISetLow(ulOffset, (OOPENWRITELOCK+i) & ulMask); olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); EH_UnlockR: ULISetLow(ulOffset, (OOPENREADLOCK+i) & ulMask); olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); EH_Loop: ; } if (i >= COPENLOCKS) olErr(EH_UnlockUpdate, STG_E_TOOMANYOPENFILES); if (!P_READ(df)) { ULISetLow(ulOffset, (OOPENREADLOCK+i) & ulMask); olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); } if (!P_WRITE(df)) { ULISetLow(ulOffset, (OOPENWRITELOCK+i) & ulMask); olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); } if (!P_DENYREAD(df)) { ULISetLow(ulOffset, (OOPENDENYREADLOCK+i) & ulMask); #ifdef DIRECTWRITERLOCK
if (fCheck == TRUE || fDirectWriterMode == FALSE) #endif
olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); } #ifdef USE_NOSNAPSHOT
if (!P_DENYWRITE(df) && !P_NOSNAPSHOT(df)) #else
if (!P_DENYWRITE(df)) #endif
{ ULISetLow(ulOffset, (OOPENDENYWRITELOCK+i) & ulMask); olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); } ULISetLow(ulOffset, OUPDATE & ulMask); olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE));
// 0 <= i < COPENLOCKS, but 0 is the invalid value, so increment
// on the way out
*puReturn = i + 1; olAssert(*puReturn != NOLOCK);
olDebugOut((DEB_ITRACE, "Out GetOpenWithMask => %lu\n", *puReturn)); return S_OK; EH_UnlockUpdate: ULISetLow(ulOffset, OUPDATE & ulMask); ULISetLow(cbLength, 1); olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE)); EH_Err: return sc; }
//+--------------------------------------------------------------
//
// Function: ReleaseOpenWithMask, private
//
// Synopsis: Releases opening locks with offset masking
//
// Arguments: [plst] - LStream
// [df] - Locks taken
// [offset] - Index of locks
// [ulMask] - Mask
//
// Requires: offset != NOLOCK
//
// History: 08-Apr-92 DrewB Created
//
//---------------------------------------------------------------
void ReleaseOpenWithMask(ILockBytes *plst, DFLAGS df, ULONG offset, ULONG ulMask) { ULARGE_INTEGER ulOffset, cbLength; SCODE scTemp;
olDebugOut((DEB_ITRACE, "In ReleaseOpenWithMask(%p, %lX, %lu, %lX)\n", plst, df, offset, ulMask));
olAssert(offset != NOLOCK);
// we incremented at the end of GetOpen, so we decrement here
// to restore the proper lock index
offset--;
ULISetHigh(ulOffset, 0); ULISet32(cbLength, 1); if (P_READ(df)) { ULISetLow(ulOffset, (OOPENREADLOCK+offset) & ulMask); scTemp = plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE); } if (P_WRITE(df)) { ULISetLow(ulOffset, (OOPENWRITELOCK+offset) & ulMask); scTemp = plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE); } if (P_DENYREAD(df)) { ULISetLow(ulOffset, (OOPENDENYREADLOCK+offset) & ulMask); scTemp = plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE); } #ifdef USE_NOSNAPSHOT
if (P_DENYWRITE(df) || P_NOSNAPSHOT(df)) #else
if (P_DENYWRITE(df)) #endif
{ ULISetLow(ulOffset, (OOPENDENYWRITELOCK+offset) & ulMask); scTemp = plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE); } #ifdef USE_NOSNAPSHOT
if (P_NOSNAPSHOT(df)) { ULISetLow(ulOffset, (OOPENNOSNAPSHOTLOCK+offset) & ulMask); scTemp = plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE); } #endif
#ifdef DIRECTWRITERLOCK
BOOL fDirectReaderMode = P_READ(df) && !P_WRITE(df) && !P_TRANSACTED(df) && !P_DENYREAD(df) && !P_DENYWRITE(df); if (fDirectReaderMode) { ULISetLow(ulOffset, (ODIRECTWRITERLOCK+offset) & ulMask); scTemp = plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE); } #endif
olDebugOut((DEB_ITRACE, "Out ReleaseOpenWithMask\n")); }
//+--------------------------------------------------------------
//
// Function: GetOpen, public
//
// Synopsis: Gets locks on an LStream during opening
//
// Arguments: [plst] - LStream
// [df] - Permissions to take
// [fCheck] - Whether to check for existing locks or not
// [puReturn] - Index of lock taken
//
// Returns: Appropriate status code
//
// Modifies: [puReturn]
//
// History: 08-Apr-92 DrewB Created
//
//---------------------------------------------------------------
SCODE GetOpen(ILockBytes *plst, DFLAGS df, BOOL fCheck, ULONG *puReturn) { SCODE sc;
olDebugOut((DEB_ITRACE, "In GetOpen(%p, %lX, %d, %p)\n", plst, df, fCheck, puReturn));
// Make sure our lock region hasn't overflowed 32 bits
olAssert(OLOCKREGIONEND > OACCESS);
olChk(GetOpenWithMask(plst, df, fCheck, 0xFFFFFFFF, puReturn)); olAssert(*puReturn < 0x10000);
olDebugOut((DEB_ITRACE, "Out GetOpen => %lu\n", *puReturn)); return S_OK;
EH_Err: *puReturn = NOLOCK; return sc; }
//+--------------------------------------------------------------
//
// Function: ReleaseOpen, public
//
// Synopsis: Releases opening locks
//
// Arguments: [plst] - LStream
// [df] - Locks taken
// [offset] - Index of locks
//
// Requires: offset != NOLOCK
//
// History: 08-Apr-92 DrewB Created
//
//---------------------------------------------------------------
void ReleaseOpen(ILockBytes *plst, DFLAGS df, ULONG offset) { olDebugOut((DEB_ITRACE, "In ReleaseOpen(%p, %lX, %lu)\n", plst, df, offset));
if (offset != NOLOCK) { ReleaseOpenWithMask(plst, df, offset & 0xffff, 0xFFFFFFFF); } olDebugOut((DEB_ITRACE, "Out ReleaseOpen\n")); }
//+---------------------------------------------------------------------------
//
// Function: WaitForAccess, public, 32-bit only
//
// Synopsis: Attempts to get access locks, retrying if necessary
// using exponential backoff
//
// Arguments: [plst] - ILockBytes
// [df] - Access desired
// [poReturn] - Lock index return
//
// Returns: Appropriate status code
//
// Modifies: [poReturn]
//
// History: 23-Sep-93 DrewB Created
//
//----------------------------------------------------------------------------
#ifdef WIN32
#define WAITACCESS_INITIAL 100
#define WAITACCESS_TIMEOUT 100000
SCODE WaitForAccess(ILockBytes *plst, DFLAGS df, ULONG *poReturn) { SCODE sc; DWORD dwWait;
olDebugOut((DEB_ITRACE, "In WaitForAccess(%p, %X, %p)\n", plst, df, poReturn));
dwWait = WAITACCESS_INITIAL; for (;;) { sc = GetAccess(plst, df, poReturn); if (sc != STG_E_LOCKVIOLATION || dwWait >= WAITACCESS_TIMEOUT ) break;
Sleep(dwWait); dwWait *= (GetTickCount() & 1) ? 1 : 2; }
olDebugOut((DEB_ITRACE, "Out WaitForAccess => 0x%lX, %lu\n", sc, poReturn)); return sc; } #endif
|