ole32: Use grfLocksSupported to decide when LockRegion is implemented.
This commit is contained in:
parent
8ff3783586
commit
9cf835a947
|
@ -386,6 +386,8 @@ static HRESULT WINAPI FileLockBytesImpl_Stat(ILockBytes* iface,
|
||||||
pstatstg->cbSize.u.LowPart = GetFileSize(This->hfile, &pstatstg->cbSize.u.HighPart);
|
pstatstg->cbSize.u.LowPart = GetFileSize(This->hfile, &pstatstg->cbSize.u.HighPart);
|
||||||
/* FIXME: If the implementation is exported, we'll need to set other fields. */
|
/* FIXME: If the implementation is exported, we'll need to set other fields. */
|
||||||
|
|
||||||
|
pstatstg->grfLocksSupported = LOCK_EXCLUSIVE|LOCK_ONLYONCE|WINE_LOCK_READ;
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4822,9 +4822,31 @@ static HRESULT StorageImpl_SetTransactionSig(StorageBaseImpl *base,
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static HRESULT StorageImpl_LockRegion(StorageImpl *This, ULARGE_INTEGER offset,
|
||||||
|
ULARGE_INTEGER cb, DWORD dwLockType, BOOL *supported)
|
||||||
|
{
|
||||||
|
if ((dwLockType & This->locks_supported) == 0)
|
||||||
|
{
|
||||||
|
if (supported) *supported = FALSE;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supported) *supported = TRUE;
|
||||||
|
return ILockBytes_LockRegion(This->lockBytes, offset, cb, dwLockType);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT StorageImpl_UnlockRegion(StorageImpl *This, ULARGE_INTEGER offset,
|
||||||
|
ULARGE_INTEGER cb, DWORD dwLockType)
|
||||||
|
{
|
||||||
|
if ((dwLockType & This->locks_supported) == 0)
|
||||||
|
return S_OK;
|
||||||
|
|
||||||
|
return ILockBytes_UnlockRegion(This->lockBytes, offset, cb, dwLockType);
|
||||||
|
}
|
||||||
|
|
||||||
/* Internal function */
|
/* Internal function */
|
||||||
static HRESULT StorageImpl_LockRegionSync(StorageImpl *This, ULARGE_INTEGER offset,
|
static HRESULT StorageImpl_LockRegionSync(StorageImpl *This, ULARGE_INTEGER offset,
|
||||||
ULARGE_INTEGER cb, DWORD dwLockType)
|
ULARGE_INTEGER cb, DWORD dwLockType, BOOL *supported)
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
int delay = 0;
|
int delay = 0;
|
||||||
|
@ -4837,7 +4859,7 @@ static HRESULT StorageImpl_LockRegionSync(StorageImpl *This, ULARGE_INTEGER offs
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
hr = ILockBytes_LockRegion(This->lockBytes, offset, cb, dwLockType);
|
hr = StorageImpl_LockRegion(This, offset, cb, dwLockType, supported);
|
||||||
|
|
||||||
if (hr == STG_E_ACCESSDENIED || hr == STG_E_LOCKVIOLATION)
|
if (hr == STG_E_ACCESSDENIED || hr == STG_E_LOCKVIOLATION)
|
||||||
{
|
{
|
||||||
|
@ -4857,17 +4879,12 @@ static HRESULT StorageImpl_LockRegionSync(StorageImpl *This, ULARGE_INTEGER offs
|
||||||
*
|
*
|
||||||
* This can collide with another attempt to open the file in
|
* This can collide with another attempt to open the file in
|
||||||
* exclusive mode, but it's unlikely, and someone would fail anyway. */
|
* exclusive mode, but it's unlikely, and someone would fail anyway. */
|
||||||
hr = ILockBytes_LockRegion(This->lockBytes, sanity_offset, sanity_cb, 0);
|
hr = StorageImpl_LockRegion(This, sanity_offset, sanity_cb, WINE_LOCK_READ, NULL);
|
||||||
if (hr == STG_E_ACCESSDENIED || hr == STG_E_LOCKVIOLATION)
|
if (hr == STG_E_ACCESSDENIED || hr == STG_E_LOCKVIOLATION)
|
||||||
break;
|
break;
|
||||||
if (hr == STG_E_INVALIDFUNCTION)
|
|
||||||
{
|
|
||||||
/* ignore this, lockbytes might support dwLockType but not 0 */
|
|
||||||
hr = STG_E_ACCESSDENIED;
|
|
||||||
}
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
ILockBytes_UnlockRegion(This->lockBytes, sanity_offset, sanity_cb, 0);
|
StorageImpl_UnlockRegion(This, sanity_offset, sanity_cb, WINE_LOCK_READ);
|
||||||
hr = STG_E_ACCESSDENIED;
|
hr = STG_E_ACCESSDENIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4900,10 +4917,7 @@ static HRESULT StorageImpl_LockTransaction(StorageBaseImpl *base, BOOL write)
|
||||||
cb.QuadPart = 1;
|
cb.QuadPart = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = StorageImpl_LockRegionSync(This, offset, cb, LOCK_ONLYONCE);
|
hr = StorageImpl_LockRegionSync(This, offset, cb, LOCK_ONLYONCE, NULL);
|
||||||
|
|
||||||
if (hr == STG_E_INVALIDFUNCTION)
|
|
||||||
hr = S_OK;
|
|
||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
@ -4925,10 +4939,7 @@ static HRESULT StorageImpl_UnlockTransaction(StorageBaseImpl *base, BOOL write)
|
||||||
cb.QuadPart = 1;
|
cb.QuadPart = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = ILockBytes_UnlockRegion(This->lockBytes, offset, cb, LOCK_ONLYONCE);
|
hr = StorageImpl_UnlockRegion(This, offset, cb, LOCK_ONLYONCE);
|
||||||
|
|
||||||
if (hr == STG_E_INVALIDFUNCTION)
|
|
||||||
hr = S_OK;
|
|
||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
@ -4955,10 +4966,10 @@ static HRESULT StorageImpl_CheckLockRange(StorageImpl *This, ULONG start,
|
||||||
offset.QuadPart = start;
|
offset.QuadPart = start;
|
||||||
cb.QuadPart = 1 + end - start;
|
cb.QuadPart = 1 + end - start;
|
||||||
|
|
||||||
hr = ILockBytes_LockRegion(This->lockBytes, offset, cb, LOCK_ONLYONCE);
|
hr = StorageImpl_LockRegion(This, offset, cb, LOCK_ONLYONCE, NULL);
|
||||||
if (SUCCEEDED(hr)) ILockBytes_UnlockRegion(This->lockBytes, offset, cb, LOCK_ONLYONCE);
|
if (SUCCEEDED(hr)) StorageImpl_UnlockRegion(This, offset, cb, LOCK_ONLYONCE);
|
||||||
|
|
||||||
if (hr == STG_E_ACCESSDENIED || hr == STG_E_LOCKVIOLATION)
|
if (FAILED(hr))
|
||||||
return fail_hr;
|
return fail_hr;
|
||||||
else
|
else
|
||||||
return S_OK;
|
return S_OK;
|
||||||
|
@ -4975,7 +4986,7 @@ static HRESULT StorageImpl_LockOne(StorageImpl *This, ULONG start, ULONG end)
|
||||||
for (i=start; i<=end; i++)
|
for (i=start; i<=end; i++)
|
||||||
{
|
{
|
||||||
offset.QuadPart = i;
|
offset.QuadPart = i;
|
||||||
hr = ILockBytes_LockRegion(This->lockBytes, offset, cb, LOCK_ONLYONCE);
|
hr = StorageImpl_LockRegion(This, offset, cb, LOCK_ONLYONCE, NULL);
|
||||||
if (hr != STG_E_ACCESSDENIED && hr != STG_E_LOCKVIOLATION)
|
if (hr != STG_E_ACCESSDENIED && hr != STG_E_LOCKVIOLATION)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -5001,6 +5012,7 @@ static HRESULT StorageImpl_GrabLocks(StorageImpl *This, DWORD openFlags)
|
||||||
ULARGE_INTEGER offset;
|
ULARGE_INTEGER offset;
|
||||||
ULARGE_INTEGER cb;
|
ULARGE_INTEGER cb;
|
||||||
DWORD share_mode = STGM_SHARE_MODE(openFlags);
|
DWORD share_mode = STGM_SHARE_MODE(openFlags);
|
||||||
|
BOOL supported;
|
||||||
|
|
||||||
if (openFlags & STGM_NOSNAPSHOT)
|
if (openFlags & STGM_NOSNAPSHOT)
|
||||||
{
|
{
|
||||||
|
@ -5012,10 +5024,10 @@ static HRESULT StorageImpl_GrabLocks(StorageImpl *This, DWORD openFlags)
|
||||||
/* Wrap all other locking inside a single lock so we can check ranges safely */
|
/* Wrap all other locking inside a single lock so we can check ranges safely */
|
||||||
offset.QuadPart = RANGELOCK_CHECKLOCKS;
|
offset.QuadPart = RANGELOCK_CHECKLOCKS;
|
||||||
cb.QuadPart = 1;
|
cb.QuadPart = 1;
|
||||||
hr = StorageImpl_LockRegionSync(This, offset, cb, LOCK_ONLYONCE);
|
hr = StorageImpl_LockRegionSync(This, offset, cb, LOCK_ONLYONCE, &supported);
|
||||||
|
|
||||||
/* If the ILockBytes doesn't support locking that's ok. */
|
/* If the ILockBytes doesn't support locking that's ok. */
|
||||||
if (hr == STG_E_INVALIDFUNCTION || hr == STG_E_UNIMPLEMENTEDFUNCTION) return S_OK;
|
if (!supported) return S_OK;
|
||||||
else if (FAILED(hr)) return hr;
|
else if (FAILED(hr)) return hr;
|
||||||
|
|
||||||
hr = S_OK;
|
hr = S_OK;
|
||||||
|
@ -5069,7 +5081,7 @@ static HRESULT StorageImpl_GrabLocks(StorageImpl *This, DWORD openFlags)
|
||||||
|
|
||||||
offset.QuadPart = RANGELOCK_CHECKLOCKS;
|
offset.QuadPart = RANGELOCK_CHECKLOCKS;
|
||||||
cb.QuadPart = 1;
|
cb.QuadPart = 1;
|
||||||
ILockBytes_UnlockRegion(This->lockBytes, offset, cb, LOCK_ONLYONCE);
|
StorageImpl_UnlockRegion(This, offset, cb, LOCK_ONLYONCE);
|
||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
@ -5134,7 +5146,7 @@ static void StorageImpl_Destroy(StorageBaseImpl* iface)
|
||||||
if (This->locked_bytes[i] != 0)
|
if (This->locked_bytes[i] != 0)
|
||||||
{
|
{
|
||||||
offset.QuadPart = This->locked_bytes[i];
|
offset.QuadPart = This->locked_bytes[i];
|
||||||
ILockBytes_UnlockRegion(This->lockBytes, offset, cb, LOCK_ONLYONCE);
|
StorageImpl_UnlockRegion(This, offset, cb, LOCK_ONLYONCE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5202,6 +5214,7 @@ static HRESULT StorageImpl_Construct(
|
||||||
{
|
{
|
||||||
StorageImpl* This;
|
StorageImpl* This;
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
|
STATSTG stat;
|
||||||
|
|
||||||
if ( FAILED( validateSTGM(openFlags) ))
|
if ( FAILED( validateSTGM(openFlags) ))
|
||||||
return STG_E_INVALIDFLAG;
|
return STG_E_INVALIDFLAG;
|
||||||
|
@ -5247,7 +5260,17 @@ static HRESULT StorageImpl_Construct(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
|
hr = ILockBytes_Stat(This->lockBytes, &stat, STATFLAG_NONAME);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
This->locks_supported = stat.grfLocksSupported;
|
||||||
|
if (!hFile)
|
||||||
|
/* Don't try to use wine-internal locking flag with custom ILockBytes */
|
||||||
|
This->locks_supported &= ~WINE_LOCK_READ;
|
||||||
|
|
||||||
hr = StorageImpl_GrabLocks(This, openFlags);
|
hr = StorageImpl_GrabLocks(This, openFlags);
|
||||||
|
}
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
hr = StorageImpl_Refresh(This, TRUE, create);
|
hr = StorageImpl_Refresh(This, TRUE, create);
|
||||||
|
|
|
@ -411,6 +411,8 @@ struct StorageImpl
|
||||||
BlockChainStream* blockChainCache[BLOCKCHAIN_CACHE_SIZE];
|
BlockChainStream* blockChainCache[BLOCKCHAIN_CACHE_SIZE];
|
||||||
UINT blockChainToEvict;
|
UINT blockChainToEvict;
|
||||||
|
|
||||||
|
ULONG locks_supported;
|
||||||
|
|
||||||
ILockBytes* lockBytes;
|
ILockBytes* lockBytes;
|
||||||
|
|
||||||
ULONG locked_bytes[8];
|
ULONG locked_bytes[8];
|
||||||
|
@ -517,6 +519,9 @@ StgStreamImpl* StgStreamImpl_Construct(
|
||||||
#define RANGELOCK_FIRST RANGELOCK_UNK1_FIRST
|
#define RANGELOCK_FIRST RANGELOCK_UNK1_FIRST
|
||||||
#define RANGELOCK_LAST RANGELOCK_UNK2_LAST
|
#define RANGELOCK_LAST RANGELOCK_UNK2_LAST
|
||||||
|
|
||||||
|
/* internal value for LockRegion/UnlockRegion */
|
||||||
|
#define WINE_LOCK_READ 0x80000000
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Endian conversion macros
|
* Endian conversion macros
|
||||||
|
|
|
@ -63,6 +63,9 @@ typedef struct TestLockBytes {
|
||||||
BYTE* contents;
|
BYTE* contents;
|
||||||
ULONG size;
|
ULONG size;
|
||||||
ULONG buffer_size;
|
ULONG buffer_size;
|
||||||
|
HRESULT lock_hr;
|
||||||
|
ULONG locks_supported;
|
||||||
|
ULONG lock_called;
|
||||||
} TestLockBytes;
|
} TestLockBytes;
|
||||||
|
|
||||||
static inline TestLockBytes *impl_from_ILockBytes(ILockBytes *iface)
|
static inline TestLockBytes *impl_from_ILockBytes(ILockBytes *iface)
|
||||||
|
@ -181,13 +184,16 @@ static HRESULT WINAPI TestLockBytes_SetSize(ILockBytes *iface,
|
||||||
static HRESULT WINAPI TestLockBytes_LockRegion(ILockBytes *iface,
|
static HRESULT WINAPI TestLockBytes_LockRegion(ILockBytes *iface,
|
||||||
ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
|
ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
|
||||||
{
|
{
|
||||||
return S_OK;
|
TestLockBytes *This = impl_from_ILockBytes(iface);
|
||||||
|
This->lock_called++;
|
||||||
|
return This->lock_hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI TestLockBytes_UnlockRegion(ILockBytes *iface,
|
static HRESULT WINAPI TestLockBytes_UnlockRegion(ILockBytes *iface,
|
||||||
ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
|
ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
|
||||||
{
|
{
|
||||||
return S_OK;
|
TestLockBytes *This = impl_from_ILockBytes(iface);
|
||||||
|
return This->lock_hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI TestLockBytes_Stat(ILockBytes *iface,
|
static HRESULT WINAPI TestLockBytes_Stat(ILockBytes *iface,
|
||||||
|
@ -209,6 +215,7 @@ static HRESULT WINAPI TestLockBytes_Stat(ILockBytes *iface,
|
||||||
|
|
||||||
pstatstg->type = STGTY_LOCKBYTES;
|
pstatstg->type = STGTY_LOCKBYTES;
|
||||||
pstatstg->cbSize.QuadPart = This->size;
|
pstatstg->cbSize.QuadPart = This->size;
|
||||||
|
pstatstg->grfLocksSupported = This->locks_supported;
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
@ -3855,6 +3862,29 @@ static void test_custom_lockbytes(void)
|
||||||
|
|
||||||
IStorage_Release(stg);
|
IStorage_Release(stg);
|
||||||
|
|
||||||
|
ok(!lockbytes->lock_called, "unexpected call to LockRegion\n");
|
||||||
|
|
||||||
|
lockbytes->locks_supported = LOCK_WRITE|LOCK_EXCLUSIVE|LOCK_ONLYONCE;
|
||||||
|
|
||||||
|
hr = StgCreateDocfileOnILockBytes(&lockbytes->ILockBytes_iface, STGM_CREATE|STGM_READWRITE|STGM_TRANSACTED, 0, &stg);
|
||||||
|
ok(hr==S_OK, "StgCreateDocfileOnILockBytes failed %x\n", hr);
|
||||||
|
|
||||||
|
hr = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &stm);
|
||||||
|
ok(hr==S_OK, "IStorage_CreateStream failed %x\n", hr);
|
||||||
|
|
||||||
|
IStream_Release(stm);
|
||||||
|
|
||||||
|
hr = IStorage_Commit(stg, 0);
|
||||||
|
|
||||||
|
IStorage_Release(stg);
|
||||||
|
|
||||||
|
ok(lockbytes->lock_called, "expected LockRegion to be called\n");
|
||||||
|
|
||||||
|
lockbytes->lock_hr = STG_E_INVALIDFUNCTION;
|
||||||
|
|
||||||
|
hr = StgCreateDocfileOnILockBytes(&lockbytes->ILockBytes_iface, STGM_CREATE|STGM_READWRITE|STGM_TRANSACTED, 0, &stg);
|
||||||
|
ok(hr==STG_E_INVALIDFUNCTION, "StgCreateDocfileOnILockBytes failed %x\n", hr);
|
||||||
|
|
||||||
DeleteTestLockBytes(lockbytes);
|
DeleteTestLockBytes(lockbytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue