Wine-devel
Threads by month
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
July 2020
- 75 participants
- 841 discussions
[PATCH v2 1/5] ntdll/tests: Remove some workarounds for no longer supported versions of Windows.
by Zebediah Figura 18 Jul '20
by Zebediah Figura 18 Jul '20
18 Jul '20
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/ntdll/tests/info.c | 187 +++++++++-------------------------------
1 file changed, 41 insertions(+), 146 deletions(-)
diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c
index e399757b85d..c57de307b2d 100644
--- a/dlls/ntdll/tests/info.c
+++ b/dlls/ntdll/tests/info.c
@@ -70,12 +70,6 @@ static BOOL InitFunctionPtrs(void)
HMODULE hntdll = GetModuleHandleA("ntdll");
HMODULE hkernel32 = GetModuleHandleA("kernel32");
- if (!hntdll)
- {
- win_skip("Not running on NT\n");
- return FALSE;
- }
-
NTDLL_GET_PROC(NtQuerySystemInformation);
NTDLL_GET_PROC(NtSetSystemInformation);
NTDLL_GET_PROC(RtlGetNativeSystemInformation);
@@ -228,7 +222,7 @@ static void test_query_performance(void)
status = pNtQuerySystemInformation(SystemPerformanceInformation, buffer, size + 2, &ReturnLength);
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
- ok( ReturnLength == size || ReturnLength == size + 2,
+ ok( ReturnLength == size || ReturnLength == size + 2 /* win8+ */,
"Inconsistent length %d\n", ReturnLength);
/* Not return values yet, as struct members are unknown */
@@ -250,64 +244,30 @@ static void test_query_timeofday(void)
SYSTEM_TIMEOFDAY_INFORMATION_PRIVATE sti;
- /* The struct size for NT (32 bytes) and Win2K/XP (48 bytes) differ.
- *
- * Windows 2000 and XP return STATUS_INFO_LENGTH_MISMATCH if the given buffer size is greater
- * then 48 and 0 otherwise
- * Windows NT returns STATUS_INFO_LENGTH_MISMATCH when the given buffer size is not correct
- * and 0 otherwise
- *
- * Windows 2000 and XP copy the given buffer size into the provided buffer, if the return code is STATUS_SUCCESS
- * NT only fills the buffer if the return code is STATUS_SUCCESS
- *
- */
+ status = pNtQuerySystemInformation( SystemTimeOfDayInformation, &sti, 0, &ReturnLength );
+ ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
+ ok( 0 == ReturnLength, "ReturnLength should be 0, it is (%d)\n", ReturnLength);
- status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, sizeof(sti), &ReturnLength);
+ sti.uCurrentTimeZoneId = 0xdeadbeef;
+ status = pNtQuerySystemInformation( SystemTimeOfDayInformation, &sti, 24, &ReturnLength );
+ ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
+ ok( 24 == ReturnLength, "ReturnLength should be 24, it is (%d)\n", ReturnLength);
+ ok( 0xdeadbeef == sti.uCurrentTimeZoneId, "This part of the buffer should not have been filled\n");
- if (status == STATUS_INFO_LENGTH_MISMATCH)
- {
- trace("Windows version is NT, we have to cater for differences with W2K/WinXP\n");
-
- status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, 0, &ReturnLength);
- ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status);
- ok( 0 == ReturnLength, "ReturnLength should be 0, it is (%d)\n", ReturnLength);
-
- sti.uCurrentTimeZoneId = 0xdeadbeef;
- status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, 28, &ReturnLength);
- ok(status == STATUS_SUCCESS || broken(status == STATUS_INFO_LENGTH_MISMATCH /* NT4 */), "Expected STATUS_SUCCESS, got %08x\n", status);
- ok( 0xdeadbeef == sti.uCurrentTimeZoneId, "This part of the buffer should not have been filled\n");
-
- status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, 32, &ReturnLength);
- ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
- ok( 32 == ReturnLength, "ReturnLength should be 0, it is (%d)\n", ReturnLength);
- }
- else
- {
- status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, 0, &ReturnLength);
- ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
- ok( 0 == ReturnLength, "ReturnLength should be 0, it is (%d)\n", ReturnLength);
-
- sti.uCurrentTimeZoneId = 0xdeadbeef;
- status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, 24, &ReturnLength);
- ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
- ok( 24 == ReturnLength, "ReturnLength should be 24, it is (%d)\n", ReturnLength);
- ok( 0xdeadbeef == sti.uCurrentTimeZoneId, "This part of the buffer should not have been filled\n");
-
- sti.uCurrentTimeZoneId = 0xdeadbeef;
- status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, 32, &ReturnLength);
- ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
- ok( 32 == ReturnLength, "ReturnLength should be 32, it is (%d)\n", ReturnLength);
- ok( 0xdeadbeef != sti.uCurrentTimeZoneId, "Buffer should have been partially filled\n");
-
- status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, 49, &ReturnLength);
- ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status);
- ok( ReturnLength == 0 || ReturnLength == sizeof(sti) /* vista */,
- "ReturnLength should be 0, it is (%d)\n", ReturnLength);
-
- status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, sizeof(sti), &ReturnLength);
- ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
- ok( sizeof(sti) == ReturnLength, "Inconsistent length %d\n", ReturnLength);
- }
+ sti.uCurrentTimeZoneId = 0xdeadbeef;
+ status = pNtQuerySystemInformation( SystemTimeOfDayInformation, &sti, 32, &ReturnLength );
+ ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
+ ok( 32 == ReturnLength, "ReturnLength should be 32, it is (%d)\n", ReturnLength);
+ ok( 0xdeadbeef != sti.uCurrentTimeZoneId, "Buffer should have been partially filled\n");
+
+ status = pNtQuerySystemInformation( SystemTimeOfDayInformation, &sti, 49, &ReturnLength );
+ ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status);
+ ok( ReturnLength == 0 || ReturnLength == sizeof(sti) /* vista */,
+ "ReturnLength should be 0, it is (%d)\n", ReturnLength);
+
+ status = pNtQuerySystemInformation( SystemTimeOfDayInformation, &sti, sizeof(sti), &ReturnLength );
+ ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
+ ok( sizeof(sti) == ReturnLength, "Inconsistent length %d\n", ReturnLength);
/* Check if we have some return values */
trace("uCurrentTimeZoneId : (%d)\n", sti.uCurrentTimeZoneId);
@@ -319,7 +279,6 @@ static void test_query_process(void)
DWORD last_pid;
ULONG ReturnLength;
int i = 0, k = 0;
- BOOL is_nt = FALSE;
SYSTEM_BASIC_INFORMATION sbi;
PROCESS_BASIC_INFORMATION pbi;
THREAD_BASIC_INFORMATION tbi;
@@ -354,8 +313,7 @@ static void test_query_process(void)
ReturnLength = 0;
status = pNtQuerySystemInformation(SystemProcessInformation, NULL, 0, &ReturnLength);
ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH got %08x\n", status);
- ok( ReturnLength > 0 || broken(ReturnLength == 0) /* NT4, Win2K */,
- "Expected a ReturnLength to show the needed length\n");
+ ok( ReturnLength > 0, "got 0 length\n");
/* W2K3 and later returns the needed length, the rest returns 0, so we have to loop */
for (;;)
@@ -369,59 +327,26 @@ static void test_query_process(void)
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
spi = spi_buf;
- /* Get the first NextEntryOffset, from this we can deduce the OS version we're running
- *
- * W2K/WinXP/W2K3:
- * NextEntryOffset for a process is 184 + (no. of threads) * sizeof(SYSTEM_THREAD_INFORMATION)
- * NT:
- * NextEntryOffset for a process is 136 + (no. of threads) * sizeof(SYSTEM_THREAD_INFORMATION)
- * Wine (with every windows version):
- * NextEntryOffset for a process is 0 if just this test is running
- * NextEntryOffset for a process is 184 + (no. of threads) * sizeof(SYSTEM_THREAD_INFORMATION) +
- * ProcessName.MaximumLength
- * if more wine processes are running
- *
- * Note : On windows the first process is in fact the Idle 'process' with a thread for every processor
- */
-
pNtQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi), &ReturnLength);
- is_nt = ( spi->NextEntryOffset - (sbi.NumberOfProcessors * sizeof(SYSTEM_THREAD_INFORMATION)) == 136);
-
- if (is_nt) win_skip("Windows version is NT, we will skip thread tests\n");
-
- /* Check if we have some return values
- *
- * On windows there will be several processes running (Including the always present Idle and System)
- * On wine we only have one (if this test is the only wine process running)
- */
-
- /* Loop through the processes */
-
for (;;)
{
+ DWORD_PTR tid;
+ DWORD j;
+
i++;
last_pid = (DWORD_PTR)spi->UniqueProcessId;
-
- /* Loop through the threads, skip NT4 for now */
-
- if (!is_nt)
+ ok(!(last_pid & 3), "Unexpected PID low bits: %p\n", spi->UniqueProcessId);
+ for (j = 0; j < spi->dwThreadCount; j++)
{
- DWORD_PTR tid;
- DWORD j;
-
- ok(!(last_pid & 3), "Unexpected PID low bits: %p\n", spi->UniqueProcessId);
- for ( j = 0; j < spi->dwThreadCount; j++)
- {
- k++;
- ok ( spi->ti[j].ClientId.UniqueProcess == spi->UniqueProcessId,
- "The owning pid of the thread (%p) doesn't equal the pid (%p) of the process\n",
- spi->ti[j].ClientId.UniqueProcess, spi->UniqueProcessId);
+ k++;
+ ok ( spi->ti[j].ClientId.UniqueProcess == spi->UniqueProcessId,
+ "The owning pid of the thread (%p) doesn't equal the pid (%p) of the process\n",
+ spi->ti[j].ClientId.UniqueProcess, spi->UniqueProcessId);
- tid = (DWORD_PTR)spi->ti[j].ClientId.UniqueThread;
- ok(!(tid & 3), "Unexpected TID low bits: %p\n", spi->ti[j].ClientId.UniqueThread);
- }
+ tid = (DWORD_PTR)spi->ti[j].ClientId.UniqueThread;
+ ok(!(tid & 3), "Unexpected TID low bits: %p\n", spi->ti[j].ClientId.UniqueThread);
}
if (!spi->NextEntryOffset) break;
@@ -431,18 +356,12 @@ static void test_query_process(void)
spi = (SYSTEM_PROCESS_INFORMATION_PRIVATE*)((char*)spi + spi->NextEntryOffset);
}
trace("Total number of running processes : %d\n", i);
- if (!is_nt) trace("Total number of running threads : %d\n", k);
+ trace("Total number of running threads : %d\n", k);
if (one_before_last_pid == 0) one_before_last_pid = last_pid;
HeapFree( GetProcessHeap(), 0, spi_buf);
- if (is_nt)
- {
- win_skip("skipping ptids low bits tests\n");
- return;
- }
-
for (i = 1; i < 4; ++i)
{
InitializeObjectAttributes( &attr, NULL, 0, NULL, NULL );
@@ -635,10 +554,6 @@ static void test_query_handle(void)
((HANDLE)(ULONG_PTR)shi->Handle[i].HandleValue == EventHandle);
ok( found, "Expected to find event handle %p (pid %x) in handle list\n", EventHandle, GetCurrentProcessId() );
- if (!found)
- for (i = 0; i < shi->Count; i++)
- trace( "%d: handle %x pid %x\n", i, shi->Handle[i].HandleValue, shi->Handle[i].OwnerPid );
-
CloseHandle(EventHandle);
ReturnLength = 0xdeadbeef;
@@ -822,7 +737,7 @@ static void test_query_logicalproc(void)
GetSystemInfo(&si);
status = pNtQuerySystemInformation(SystemLogicalProcessorInformation, NULL, 0, &len);
- if(status == STATUS_INVALID_INFO_CLASS)
+ if (status == STATUS_INVALID_INFO_CLASS) /* wow64 win8+ */
{
win_skip("SystemLogicalProcessorInformation is not supported\n");
return;
@@ -1441,7 +1356,7 @@ static void test_query_process_vm(void)
status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessVmCounters, &pvi, 46, &ReturnLength);
ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status);
- ok( ReturnLength == sizeof(VM_COUNTERS) || ReturnLength == sizeof(pvi), "Inconsistent length %d\n", ReturnLength);
+ todo_wine ok( ReturnLength == sizeof(VM_COUNTERS), "wrong size %d\n", ReturnLength);
/* Check if we have some return values */
dump_vm_counters("VM counters for GetCurrentProcess", &pvi);
@@ -1524,14 +1439,6 @@ static void test_query_process_io(void)
ULONG ReturnLength;
IO_COUNTERS pii;
- /* NT4 doesn't support this information class, so check for it */
- status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessIoCounters, &pii, sizeof(pii), &ReturnLength);
- if (status == STATUS_NOT_SUPPORTED)
- {
- win_skip("ProcessIoCounters information class is not supported\n");
- return;
- }
-
status = pNtQueryInformationProcess(NULL, ProcessIoCounters, NULL, sizeof(pii), NULL);
ok( status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_HANDLE,
"Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_HANDLE(W2K3), got %08x\n", status);
@@ -1637,8 +1544,7 @@ static void test_query_process_debug_port(int argc, char **argv)
status = pNtQueryInformationProcess(NULL, ProcessDebugPort,
NULL, sizeof(debug_port), NULL);
- ok(status == STATUS_INVALID_HANDLE || status == STATUS_ACCESS_VIOLATION,
- "Expected STATUS_INVALID_HANDLE, got %#x.\n", status);
+ ok(status == STATUS_INVALID_HANDLE || status == STATUS_ACCESS_VIOLATION /* XP */, "got %#x\n", status);
status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessDebugPort,
NULL, sizeof(debug_port), NULL);
@@ -1776,11 +1682,6 @@ static void test_query_process_image_file_name(void)
UNICODE_STRING *buffer = NULL;
status = pNtQueryInformationProcess(NULL, ProcessImageFileName, &image_file_name, sizeof(image_file_name), NULL);
- if (status == STATUS_INVALID_INFO_CLASS)
- {
- win_skip("ProcessImageFileName is not supported\n");
- return;
- }
ok( status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got %08x\n", status);
status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessImageFileName, &image_file_name, 2, &ReturnLength);
@@ -1868,11 +1769,6 @@ static void test_query_process_debug_object_handle(int argc, char **argv)
status = pNtQueryInformationProcess(NULL, ProcessDebugObjectHandle, NULL,
0, NULL);
- if (status == STATUS_INVALID_INFO_CLASS || status == STATUS_NOT_IMPLEMENTED)
- {
- win_skip("ProcessDebugObjectHandle is not supported\n");
- return;
- }
ok(status == STATUS_INFO_LENGTH_MISMATCH,
"Expected NtQueryInformationProcess to return STATUS_INFO_LENGTH_MISMATCH, got 0x%08x\n",
status);
@@ -2122,7 +2018,7 @@ static void test_readvirtualmemory(void)
/* illegal remote address */
todo_wine{
status = pNtReadVirtualMemory(process, (void *) 0x1234, buffer, 12, &readcount);
- ok( status == STATUS_PARTIAL_COPY || broken(status == STATUS_ACCESS_VIOLATION), "Expected STATUS_PARTIAL_COPY, got %08x\n", status);
+ ok( status == STATUS_PARTIAL_COPY, "Expected STATUS_PARTIAL_COPY, got %08x\n", status);
if (status == STATUS_PARTIAL_COPY)
ok( readcount == 0, "Expected to read 0 bytes, got %ld\n",readcount);
}
@@ -2419,8 +2315,7 @@ static void test_affinity(void)
{
status = pNtQueryInformationThread( GetCurrentThread(), ThreadBasicInformation, &tbi, sizeof(tbi), NULL );
ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
- ok( broken(tbi.AffinityMask == 1) || tbi.AffinityMask == (1 << si.dwNumberOfProcessors) - 1,
- "Unexpected thread affinity\n" );
+ ok( tbi.AffinityMask == (1 << si.dwNumberOfProcessors) - 1, "unexpected affinity %#lx\n", tbi.AffinityMask );
}
else
skip("Cannot test thread affinity mask for 'all processors' flag\n");
--
2.27.0
2
8
[PATCH 1/2] bcrypt: Improve BCryptSecretAgreement/BCryptDestroySecret/BCryptDeriveKey stubs.
by Brendan Shanks 17 Jul '20
by Brendan Shanks 17 Jul '20
17 Jul '20
Signed-off-by: Brendan Shanks <bshanks(a)codeweavers.com>
---
dlls/bcrypt/bcrypt_internal.h | 6 ++++++
dlls/bcrypt/bcrypt_main.c | 35 ++++++++++++++++++++++++++++-------
2 files changed, 34 insertions(+), 7 deletions(-)
diff --git a/dlls/bcrypt/bcrypt_internal.h b/dlls/bcrypt/bcrypt_internal.h
index 18343a6c749..43be170d77f 100644
--- a/dlls/bcrypt/bcrypt_internal.h
+++ b/dlls/bcrypt/bcrypt_internal.h
@@ -111,6 +111,7 @@ VOID WINAPI A_SHAFinal(SHA_CTX *ctx, PULONG result);
#define MAGIC_ALG (('A' << 24) | ('L' << 16) | ('G' << 8) | '0')
#define MAGIC_HASH (('H' << 24) | ('A' << 16) | ('S' << 8) | 'H')
#define MAGIC_KEY (('K' << 24) | ('E' << 16) | ('Y' << 8) | '0')
+#define MAGIC_SECRET (('S' << 24) | ('C' << 16) | ('R' << 8) | 'T')
struct object
{
ULONG magic;
@@ -239,6 +240,11 @@ struct key
};
#endif
+struct secret
+{
+ struct object hdr;
+};
+
NTSTATUS get_alg_property( const struct algorithm *, const WCHAR *, UCHAR *, ULONG, ULONG * ) DECLSPEC_HIDDEN;
NTSTATUS key_set_property( struct key *, const WCHAR *, UCHAR *, ULONG, ULONG ) DECLSPEC_HIDDEN;
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c
index fee40ebe8d7..bea2001a677 100644
--- a/dlls/bcrypt/bcrypt_main.c
+++ b/dlls/bcrypt/bcrypt_main.c
@@ -1833,26 +1833,47 @@ NTSTATUS WINAPI BCryptDeriveKeyPBKDF2( BCRYPT_ALG_HANDLE handle, UCHAR *pwd, ULO
return STATUS_SUCCESS;
}
-NTSTATUS WINAPI BCryptSecretAgreement(BCRYPT_KEY_HANDLE handle, BCRYPT_KEY_HANDLE key, BCRYPT_SECRET_HANDLE *secret, ULONG flags)
+NTSTATUS WINAPI BCryptSecretAgreement(BCRYPT_KEY_HANDLE privatekey, BCRYPT_KEY_HANDLE publickey, BCRYPT_SECRET_HANDLE *handle, ULONG flags)
{
- FIXME( "%p, %p, %p, %08x\n", handle, key, secret, flags );
+ struct key *privkey = privatekey;
+ struct key *pubkey = publickey;
+ struct secret *secret;
- if(secret)
- *secret = (BCRYPT_SECRET_HANDLE *)0xDEADFEED;
+ FIXME( "%p, %p, %p, %08x\n", privatekey, publickey, handle, flags );
+ if (!privkey || privkey->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
+ if (!pubkey || pubkey->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
+ if (!handle) return STATUS_INVALID_PARAMETER;
+
+ if (!(secret = heap_alloc_zero( sizeof(*secret) ))) return STATUS_NO_MEMORY;
+ secret->hdr.magic = MAGIC_SECRET;
+
+ *handle = secret;
return STATUS_SUCCESS;
}
-NTSTATUS WINAPI BCryptDestroySecret(BCRYPT_SECRET_HANDLE secret)
+NTSTATUS WINAPI BCryptDestroySecret(BCRYPT_SECRET_HANDLE handle)
{
- FIXME( "%p\n", secret );
+ struct secret *secret = handle;
+
+ FIXME( "%p\n", handle );
+
+ if (!secret || secret->hdr.magic != MAGIC_SECRET) return STATUS_INVALID_HANDLE;
+ secret->hdr.magic = 0;
+ heap_free( secret );
return STATUS_SUCCESS;
}
-NTSTATUS WINAPI BCryptDeriveKey(BCRYPT_SECRET_HANDLE secret, LPCWSTR kdf, BCryptBufferDesc *parameter,
+NTSTATUS WINAPI BCryptDeriveKey(BCRYPT_SECRET_HANDLE handle, LPCWSTR kdf, BCryptBufferDesc *parameter,
PUCHAR derived, ULONG derived_size, ULONG *result, ULONG flags)
{
+ struct secret *secret = handle;
+
FIXME( "%p, %s, %p, %p, %d, %p, %08x\n", secret, debugstr_w(kdf), parameter, derived, derived_size, result, flags );
+
+ if (!secret || secret->hdr.magic != MAGIC_SECRET) return STATUS_INVALID_HANDLE;
+ if (!kdf) return STATUS_INVALID_PARAMETER;
+
return STATUS_INTERNAL_ERROR;
}
--
2.26.2
1
1
[PATCH 1/5] ntdll/tests: Remove some workarounds for no longer supported versions of Windows.
by Zebediah Figura 17 Jul '20
by Zebediah Figura 17 Jul '20
17 Jul '20
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/ntdll/tests/info.c | 190 +++++++++-------------------------------
1 file changed, 40 insertions(+), 150 deletions(-)
diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c
index e399757b85d..6c9d35a982b 100644
--- a/dlls/ntdll/tests/info.c
+++ b/dlls/ntdll/tests/info.c
@@ -70,12 +70,6 @@ static BOOL InitFunctionPtrs(void)
HMODULE hntdll = GetModuleHandleA("ntdll");
HMODULE hkernel32 = GetModuleHandleA("kernel32");
- if (!hntdll)
- {
- win_skip("Not running on NT\n");
- return FALSE;
- }
-
NTDLL_GET_PROC(NtQuerySystemInformation);
NTDLL_GET_PROC(NtSetSystemInformation);
NTDLL_GET_PROC(RtlGetNativeSystemInformation);
@@ -228,7 +222,7 @@ static void test_query_performance(void)
status = pNtQuerySystemInformation(SystemPerformanceInformation, buffer, size + 2, &ReturnLength);
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
- ok( ReturnLength == size || ReturnLength == size + 2,
+ ok( ReturnLength == size || ReturnLength == size + 2 /* win8+ */,
"Inconsistent length %d\n", ReturnLength);
/* Not return values yet, as struct members are unknown */
@@ -250,64 +244,30 @@ static void test_query_timeofday(void)
SYSTEM_TIMEOFDAY_INFORMATION_PRIVATE sti;
- /* The struct size for NT (32 bytes) and Win2K/XP (48 bytes) differ.
- *
- * Windows 2000 and XP return STATUS_INFO_LENGTH_MISMATCH if the given buffer size is greater
- * then 48 and 0 otherwise
- * Windows NT returns STATUS_INFO_LENGTH_MISMATCH when the given buffer size is not correct
- * and 0 otherwise
- *
- * Windows 2000 and XP copy the given buffer size into the provided buffer, if the return code is STATUS_SUCCESS
- * NT only fills the buffer if the return code is STATUS_SUCCESS
- *
- */
+ status = pNtQuerySystemInformation( SystemTimeOfDayInformation, &sti, 0, &ReturnLength );
+ ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
+ ok( 0 == ReturnLength, "ReturnLength should be 0, it is (%d)\n", ReturnLength);
- status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, sizeof(sti), &ReturnLength);
+ sti.uCurrentTimeZoneId = 0xdeadbeef;
+ status = pNtQuerySystemInformation( SystemTimeOfDayInformation, &sti, 24, &ReturnLength );
+ ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
+ ok( 24 == ReturnLength, "ReturnLength should be 24, it is (%d)\n", ReturnLength);
+ ok( 0xdeadbeef == sti.uCurrentTimeZoneId, "This part of the buffer should not have been filled\n");
- if (status == STATUS_INFO_LENGTH_MISMATCH)
- {
- trace("Windows version is NT, we have to cater for differences with W2K/WinXP\n");
-
- status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, 0, &ReturnLength);
- ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status);
- ok( 0 == ReturnLength, "ReturnLength should be 0, it is (%d)\n", ReturnLength);
-
- sti.uCurrentTimeZoneId = 0xdeadbeef;
- status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, 28, &ReturnLength);
- ok(status == STATUS_SUCCESS || broken(status == STATUS_INFO_LENGTH_MISMATCH /* NT4 */), "Expected STATUS_SUCCESS, got %08x\n", status);
- ok( 0xdeadbeef == sti.uCurrentTimeZoneId, "This part of the buffer should not have been filled\n");
-
- status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, 32, &ReturnLength);
- ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
- ok( 32 == ReturnLength, "ReturnLength should be 0, it is (%d)\n", ReturnLength);
- }
- else
- {
- status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, 0, &ReturnLength);
- ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
- ok( 0 == ReturnLength, "ReturnLength should be 0, it is (%d)\n", ReturnLength);
-
- sti.uCurrentTimeZoneId = 0xdeadbeef;
- status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, 24, &ReturnLength);
- ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
- ok( 24 == ReturnLength, "ReturnLength should be 24, it is (%d)\n", ReturnLength);
- ok( 0xdeadbeef == sti.uCurrentTimeZoneId, "This part of the buffer should not have been filled\n");
-
- sti.uCurrentTimeZoneId = 0xdeadbeef;
- status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, 32, &ReturnLength);
- ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
- ok( 32 == ReturnLength, "ReturnLength should be 32, it is (%d)\n", ReturnLength);
- ok( 0xdeadbeef != sti.uCurrentTimeZoneId, "Buffer should have been partially filled\n");
-
- status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, 49, &ReturnLength);
- ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status);
- ok( ReturnLength == 0 || ReturnLength == sizeof(sti) /* vista */,
- "ReturnLength should be 0, it is (%d)\n", ReturnLength);
-
- status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, sizeof(sti), &ReturnLength);
- ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
- ok( sizeof(sti) == ReturnLength, "Inconsistent length %d\n", ReturnLength);
- }
+ sti.uCurrentTimeZoneId = 0xdeadbeef;
+ status = pNtQuerySystemInformation( SystemTimeOfDayInformation, &sti, 32, &ReturnLength );
+ ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
+ ok( 32 == ReturnLength, "ReturnLength should be 32, it is (%d)\n", ReturnLength);
+ ok( 0xdeadbeef != sti.uCurrentTimeZoneId, "Buffer should have been partially filled\n");
+
+ status = pNtQuerySystemInformation( SystemTimeOfDayInformation, &sti, 49, &ReturnLength );
+ ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status);
+ ok( ReturnLength == 0 || ReturnLength == sizeof(sti) /* vista */,
+ "ReturnLength should be 0, it is (%d)\n", ReturnLength);
+
+ status = pNtQuerySystemInformation( SystemTimeOfDayInformation, &sti, sizeof(sti), &ReturnLength );
+ ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
+ ok( sizeof(sti) == ReturnLength, "Inconsistent length %d\n", ReturnLength);
/* Check if we have some return values */
trace("uCurrentTimeZoneId : (%d)\n", sti.uCurrentTimeZoneId);
@@ -319,7 +279,6 @@ static void test_query_process(void)
DWORD last_pid;
ULONG ReturnLength;
int i = 0, k = 0;
- BOOL is_nt = FALSE;
SYSTEM_BASIC_INFORMATION sbi;
PROCESS_BASIC_INFORMATION pbi;
THREAD_BASIC_INFORMATION tbi;
@@ -354,8 +313,7 @@ static void test_query_process(void)
ReturnLength = 0;
status = pNtQuerySystemInformation(SystemProcessInformation, NULL, 0, &ReturnLength);
ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH got %08x\n", status);
- ok( ReturnLength > 0 || broken(ReturnLength == 0) /* NT4, Win2K */,
- "Expected a ReturnLength to show the needed length\n");
+ ok( ReturnLength > 0, "got 0 length\n");
/* W2K3 and later returns the needed length, the rest returns 0, so we have to loop */
for (;;)
@@ -369,59 +327,26 @@ static void test_query_process(void)
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
spi = spi_buf;
- /* Get the first NextEntryOffset, from this we can deduce the OS version we're running
- *
- * W2K/WinXP/W2K3:
- * NextEntryOffset for a process is 184 + (no. of threads) * sizeof(SYSTEM_THREAD_INFORMATION)
- * NT:
- * NextEntryOffset for a process is 136 + (no. of threads) * sizeof(SYSTEM_THREAD_INFORMATION)
- * Wine (with every windows version):
- * NextEntryOffset for a process is 0 if just this test is running
- * NextEntryOffset for a process is 184 + (no. of threads) * sizeof(SYSTEM_THREAD_INFORMATION) +
- * ProcessName.MaximumLength
- * if more wine processes are running
- *
- * Note : On windows the first process is in fact the Idle 'process' with a thread for every processor
- */
-
pNtQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi), &ReturnLength);
- is_nt = ( spi->NextEntryOffset - (sbi.NumberOfProcessors * sizeof(SYSTEM_THREAD_INFORMATION)) == 136);
-
- if (is_nt) win_skip("Windows version is NT, we will skip thread tests\n");
-
- /* Check if we have some return values
- *
- * On windows there will be several processes running (Including the always present Idle and System)
- * On wine we only have one (if this test is the only wine process running)
- */
-
- /* Loop through the processes */
-
for (;;)
{
+ DWORD_PTR tid;
+ DWORD j;
+
i++;
last_pid = (DWORD_PTR)spi->UniqueProcessId;
-
- /* Loop through the threads, skip NT4 for now */
-
- if (!is_nt)
+ ok(!(last_pid & 3), "Unexpected PID low bits: %p\n", spi->UniqueProcessId);
+ for (j = 0; j < spi->dwThreadCount; j++)
{
- DWORD_PTR tid;
- DWORD j;
+ k++;
+ ok ( spi->ti[j].ClientId.UniqueProcess == spi->UniqueProcessId,
+ "The owning pid of the thread (%p) doesn't equal the pid (%p) of the process\n",
+ spi->ti[j].ClientId.UniqueProcess, spi->UniqueProcessId);
- ok(!(last_pid & 3), "Unexpected PID low bits: %p\n", spi->UniqueProcessId);
- for ( j = 0; j < spi->dwThreadCount; j++)
- {
- k++;
- ok ( spi->ti[j].ClientId.UniqueProcess == spi->UniqueProcessId,
- "The owning pid of the thread (%p) doesn't equal the pid (%p) of the process\n",
- spi->ti[j].ClientId.UniqueProcess, spi->UniqueProcessId);
-
- tid = (DWORD_PTR)spi->ti[j].ClientId.UniqueThread;
- ok(!(tid & 3), "Unexpected TID low bits: %p\n", spi->ti[j].ClientId.UniqueThread);
- }
+ tid = (DWORD_PTR)spi->ti[j].ClientId.UniqueThread;
+ ok(!(tid & 3), "Unexpected TID low bits: %p\n", spi->ti[j].ClientId.UniqueThread);
}
if (!spi->NextEntryOffset) break;
@@ -431,18 +356,12 @@ static void test_query_process(void)
spi = (SYSTEM_PROCESS_INFORMATION_PRIVATE*)((char*)spi + spi->NextEntryOffset);
}
trace("Total number of running processes : %d\n", i);
- if (!is_nt) trace("Total number of running threads : %d\n", k);
+ trace("Total number of running threads : %d\n", k);
if (one_before_last_pid == 0) one_before_last_pid = last_pid;
HeapFree( GetProcessHeap(), 0, spi_buf);
- if (is_nt)
- {
- win_skip("skipping ptids low bits tests\n");
- return;
- }
-
for (i = 1; i < 4; ++i)
{
InitializeObjectAttributes( &attr, NULL, 0, NULL, NULL );
@@ -635,10 +554,6 @@ static void test_query_handle(void)
((HANDLE)(ULONG_PTR)shi->Handle[i].HandleValue == EventHandle);
ok( found, "Expected to find event handle %p (pid %x) in handle list\n", EventHandle, GetCurrentProcessId() );
- if (!found)
- for (i = 0; i < shi->Count; i++)
- trace( "%d: handle %x pid %x\n", i, shi->Handle[i].HandleValue, shi->Handle[i].OwnerPid );
-
CloseHandle(EventHandle);
ReturnLength = 0xdeadbeef;
@@ -822,11 +737,6 @@ static void test_query_logicalproc(void)
GetSystemInfo(&si);
status = pNtQuerySystemInformation(SystemLogicalProcessorInformation, NULL, 0, &len);
- if(status == STATUS_INVALID_INFO_CLASS)
- {
- win_skip("SystemLogicalProcessorInformation is not supported\n");
- return;
- }
if(status == STATUS_NOT_IMPLEMENTED)
{
todo_wine ok(0, "SystemLogicalProcessorInformation is not implemented\n");
@@ -1441,7 +1351,7 @@ static void test_query_process_vm(void)
status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessVmCounters, &pvi, 46, &ReturnLength);
ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status);
- ok( ReturnLength == sizeof(VM_COUNTERS) || ReturnLength == sizeof(pvi), "Inconsistent length %d\n", ReturnLength);
+ ok( ReturnLength == sizeof(VM_COUNTERS), "Inconsistent length %d\n", ReturnLength);
/* Check if we have some return values */
dump_vm_counters("VM counters for GetCurrentProcess", &pvi);
@@ -1524,14 +1434,6 @@ static void test_query_process_io(void)
ULONG ReturnLength;
IO_COUNTERS pii;
- /* NT4 doesn't support this information class, so check for it */
- status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessIoCounters, &pii, sizeof(pii), &ReturnLength);
- if (status == STATUS_NOT_SUPPORTED)
- {
- win_skip("ProcessIoCounters information class is not supported\n");
- return;
- }
-
status = pNtQueryInformationProcess(NULL, ProcessIoCounters, NULL, sizeof(pii), NULL);
ok( status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_HANDLE,
"Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_HANDLE(W2K3), got %08x\n", status);
@@ -1637,8 +1539,7 @@ static void test_query_process_debug_port(int argc, char **argv)
status = pNtQueryInformationProcess(NULL, ProcessDebugPort,
NULL, sizeof(debug_port), NULL);
- ok(status == STATUS_INVALID_HANDLE || status == STATUS_ACCESS_VIOLATION,
- "Expected STATUS_INVALID_HANDLE, got %#x.\n", status);
+ ok(status == STATUS_INVALID_HANDLE || status == STATUS_ACCESS_VIOLATION /* XP */, "got %#x\n", status);
status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessDebugPort,
NULL, sizeof(debug_port), NULL);
@@ -1776,11 +1677,6 @@ static void test_query_process_image_file_name(void)
UNICODE_STRING *buffer = NULL;
status = pNtQueryInformationProcess(NULL, ProcessImageFileName, &image_file_name, sizeof(image_file_name), NULL);
- if (status == STATUS_INVALID_INFO_CLASS)
- {
- win_skip("ProcessImageFileName is not supported\n");
- return;
- }
ok( status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got %08x\n", status);
status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessImageFileName, &image_file_name, 2, &ReturnLength);
@@ -1868,11 +1764,6 @@ static void test_query_process_debug_object_handle(int argc, char **argv)
status = pNtQueryInformationProcess(NULL, ProcessDebugObjectHandle, NULL,
0, NULL);
- if (status == STATUS_INVALID_INFO_CLASS || status == STATUS_NOT_IMPLEMENTED)
- {
- win_skip("ProcessDebugObjectHandle is not supported\n");
- return;
- }
ok(status == STATUS_INFO_LENGTH_MISMATCH,
"Expected NtQueryInformationProcess to return STATUS_INFO_LENGTH_MISMATCH, got 0x%08x\n",
status);
@@ -2122,7 +2013,7 @@ static void test_readvirtualmemory(void)
/* illegal remote address */
todo_wine{
status = pNtReadVirtualMemory(process, (void *) 0x1234, buffer, 12, &readcount);
- ok( status == STATUS_PARTIAL_COPY || broken(status == STATUS_ACCESS_VIOLATION), "Expected STATUS_PARTIAL_COPY, got %08x\n", status);
+ ok( status == STATUS_PARTIAL_COPY, "Expected STATUS_PARTIAL_COPY, got %08x\n", status);
if (status == STATUS_PARTIAL_COPY)
ok( readcount == 0, "Expected to read 0 bytes, got %ld\n",readcount);
}
@@ -2419,8 +2310,7 @@ static void test_affinity(void)
{
status = pNtQueryInformationThread( GetCurrentThread(), ThreadBasicInformation, &tbi, sizeof(tbi), NULL );
ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
- ok( broken(tbi.AffinityMask == 1) || tbi.AffinityMask == (1 << si.dwNumberOfProcessors) - 1,
- "Unexpected thread affinity\n" );
+ ok( tbi.AffinityMask == (1 << si.dwNumberOfProcessors) - 1, "unexpected affinity %#lx\n", tbi.AffinityMask );
}
else
skip("Cannot test thread affinity mask for 'all processors' flag\n");
--
2.27.0
2
5
Signed-off-by: Derek Lesho <dlesho(a)codeweavers.com>
---
dlls/ntoskrnl.exe/tests/driver.c | 133 ++++++++++++++++++++++++++++-
dlls/ntoskrnl.exe/tests/driver.h | 2 +
dlls/ntoskrnl.exe/tests/ntoskrnl.c | 39 +++++++++
3 files changed, 173 insertions(+), 1 deletion(-)
diff --git a/dlls/ntoskrnl.exe/tests/driver.c b/dlls/ntoskrnl.exe/tests/driver.c
index c1b19b7ed8b..481035557ba 100644
--- a/dlls/ntoskrnl.exe/tests/driver.c
+++ b/dlls/ntoskrnl.exe/tests/driver.c
@@ -47,7 +47,7 @@ static const WCHAR driver_link[] = {'\\','D','o','s','D','e','v','i','c','e','s'
static DRIVER_OBJECT *driver_obj;
static DEVICE_OBJECT *lower_device, *upper_device;
-static POBJECT_TYPE *pExEventObjectType, *pIoFileObjectType, *pPsThreadType, *pIoDriverObjectType;
+static POBJECT_TYPE *pExEventObjectType, *pIoFileObjectType, *pPsThreadType, *pPsProcessType, *pIoDriverObjectType;
static PEPROCESS *pPsInitialSystemProcess;
static void *create_caller_thread;
@@ -1970,6 +1970,133 @@ static void test_dpc(void)
KeRevertToUserAffinityThread();
}
+PKTHREAD current_apc_thread;
+
+void WINAPI apc_receiver(PVOID context)
+{
+ /* kernel mode APCs don't require an alertable wait */
+ wait_single((PKEVENT)context, 50 * -10000000);
+
+ PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
+enum
+{
+ SPECIAL_KERNEL,
+ NORMAL_KERNEL,
+ NORMAL_USER,
+} current_apc_type;
+
+static void WINAPI kernel_routine(PKAPC apc, PKNORMAL_ROUTINE *nrml_routine, PVOID *normal_ctx, PVOID *sysarg1, PVOID *sysarg2)
+{
+ ok(KeGetCurrentThread() == current_apc_thread, "Got unexpected current thread: %p!=%p\n", KeGetCurrentThread(), current_apc_thread);
+ ok(apc && nrml_routine && normal_ctx && sysarg1 && sysarg2, "Missing parameter pointer in kernel_routine\n");
+ if (current_apc_type == SPECIAL_KERNEL)
+ {
+ ok(*nrml_routine == NULL, "Got non-null normal routine value %p in special APC.\n", *nrml_routine);
+ ok(*normal_ctx == NULL, "Got unexpected normal context %p in APC.\n", *normal_ctx);
+ KeSetEvent((PKEVENT)*sysarg2, 0, FALSE);
+ }
+ else
+ {
+ ok(*nrml_routine == (PVOID)(ULONG_PTR)0xdeadbeef, "Got unexpected initial normal routine value: %p\n", *normal_ctx);
+ ok(*normal_ctx == (PVOID)(ULONG_PTR)0xdeadbeef, "Got unexpected normal context: %p\n", *normal_ctx);
+ }
+ /* in a special kernel APC, the normal routine we set should be ignored */
+ /* in a normal routine, the special section has the final say on the normal routine and parameters */
+ *nrml_routine = *sysarg1;
+}
+
+static void WINAPI rundown_routine(PKAPC apc)
+{
+ ok(FALSE, "Unexpected execution of rundown routine\n");
+}
+
+static void WINAPI normal_routine(PVOID normal_ctx, PVOID sysarg1, PVOID sysarg2)
+{
+ ok(KeGetCurrentThread() == current_apc_thread, "Got unexpected current thread: %p!=%p\n", KeGetCurrentThread(), current_apc_thread);
+ ok (current_apc_type == NORMAL_KERNEL, "Got unexpected current APC type: %u\n", current_apc_type);
+ KeSetEvent((PKEVENT)sysarg2, 0, FALSE);
+}
+
+static void test_apc(const struct test_input *test_input)
+{
+ void (WINAPI *pKeInitializeApc)(PRKAPC,PRKTHREAD,KAPC_ENVIRONMENT,PKKERNEL_ROUTINE,PKRUNDOWN_ROUTINE,PKNORMAL_ROUTINE,KPROCESSOR_MODE,PVOID);
+ BOOLEAN (WINAPI *pKeInsertQueueApc)(PKAPC,PVOID,PVOID,KPRIORITY);
+ OBJECT_ATTRIBUTES attr;
+ PEPROCESS user_process;
+ PKTHREAD user_apc_thread;
+ HANDLE user_process_handle;
+ HANDLE done_event_system_handle, done_event_user_handle;
+ KEVENT *done_event, terminate_event;
+ HANDLE apc_reciever_thread;
+ KAPC special_apc, kernel_apc, user_apc;
+ NTSTATUS stat;
+
+ pKeInitializeApc = get_proc_address("KeInitializeApc");
+ pKeInsertQueueApc = get_proc_address("KeInsertQueueApc");
+
+todo_wine
+ ok(pKeInitializeApc && pKeInsertQueueApc, "Unable to find KeInitializeApc and KeInsertQueueApc\n");
+ if (!pKeInitializeApc || !pKeInsertQueueApc)
+ return;
+
+ InitializeObjectAttributes(&attr, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
+ ZwCreateEvent(&done_event_system_handle, SYNCHRONIZE|EVENT_MODIFY_STATE, &attr, SynchronizationEvent, FALSE);
+ ObReferenceObjectByHandle(done_event_system_handle, 0, *pExEventObjectType, KernelMode, (void**)&done_event, NULL);
+
+ KeInitializeEvent(&terminate_event, NotificationEvent, FALSE);
+
+ apc_reciever_thread = create_thread(apc_receiver, &terminate_event);
+ ObReferenceObjectByHandle(apc_reciever_thread, 0, *pPsThreadType, KernelMode, (void**)¤t_apc_thread, NULL);
+ ZwClose(apc_reciever_thread);
+
+ current_apc_type = SPECIAL_KERNEL;
+ pKeInitializeApc(&special_apc, current_apc_thread, OriginalApcEnvironment, kernel_routine, rundown_routine,
+ NULL, KernelMode, (PVOID)(ULONG_PTR)0xdeadbeef);
+ pKeInsertQueueApc(&special_apc, normal_routine, done_event, 0);
+ stat = wait_single(done_event, 5 * -10000000);
+ ok(stat == STATUS_WAIT_0, "Waiting on special kernel APC to complete failed: %#x\n", stat);
+
+ current_apc_type = NORMAL_KERNEL;
+ pKeInitializeApc(&kernel_apc, current_apc_thread, OriginalApcEnvironment, kernel_routine, rundown_routine,
+ (PVOID)(ULONG_PTR)0xdeadbeef, KernelMode, (PVOID)(ULONG_PTR)0xdeadbeef);
+ pKeInsertQueueApc(&kernel_apc, normal_routine, done_event, 0);
+ stat = wait_single(done_event, 5 * -10000000);
+ ok(stat == STATUS_WAIT_0, "Waiting on normal kernel APC to complete failed: %#x\n", stat);
+
+ KeSetEvent(&terminate_event, 0, FALSE);
+ ObDereferenceObject(current_apc_thread);
+
+ /* Get usermode thread accepting APCs */
+ stat = PsLookupThreadByThreadId((HANDLE)(ULONG_PTR)test_input->apc_thread_id, (PETHREAD *)&user_apc_thread);
+ ok(stat == STATUS_SUCCESS, "Got unexpected status %#x.\n", stat);
+
+ /* create handle for done event (once user mode handles are supported, this won't be necessary) */
+ stat = PsLookupProcessByProcessId((HANDLE)(ULONG_PTR)test_input->process_id, &user_process);
+ ok(stat == STATUS_SUCCESS, "Got unexpected status %#x.\n", stat);
+
+ stat = ObOpenObjectByPointer(user_process, OBJ_KERNEL_HANDLE, NULL, PROCESS_DUP_HANDLE, *pPsProcessType, KernelMode, &user_process_handle);
+ ok(stat == STATUS_SUCCESS, "Got unexpected status %#x.\n", stat);
+ ObDereferenceObject(user_process);
+
+ stat = ZwDuplicateObject(NtCurrentProcess(), done_event_system_handle, user_process_handle, &done_event_user_handle, SYNCHRONIZE|EVENT_MODIFY_STATE, 0, DUPLICATE_SAME_ACCESS|DUPLICATE_CLOSE_SOURCE);
+ ok(stat == STATUS_SUCCESS, "Got unexpected status %#x.\n", stat);
+
+ current_apc_type = NORMAL_USER;
+ current_apc_thread = user_apc_thread;
+ pKeInitializeApc(&user_apc, user_apc_thread, OriginalApcEnvironment, kernel_routine, rundown_routine,
+ (PVOID)(ULONG_PTR)0xdeadbeef, UserMode, (PVOID)(ULONG_PTR)0xdeadbeef);
+ pKeInsertQueueApc(&user_apc, test_input->apc_func, done_event_user_handle, 0);
+
+ stat = wait_single(done_event, 5 * -10000000);
+ ok(stat == STATUS_WAIT_0, "Waiting on user APC to complete failed: %#x\n", stat);
+
+ ZwClose(done_event_user_handle);
+ ObDereferenceObject(done_event);
+ ObDereferenceObject(current_apc_thread);
+}
+
static void test_process_memory(const struct test_input *test_input)
{
NTSTATUS (WINAPI *pMmCopyVirtualMemory)(PEPROCESS fromprocess, void *fromaddress, PEPROCESS toprocess,
@@ -2115,6 +2242,9 @@ static NTSTATUS main_test(DEVICE_OBJECT *device, IRP *irp, IO_STACK_LOCATION *st
pPsThreadType = get_proc_address("PsThreadType");
ok(!!pPsThreadType, "IofileObjectType not found\n");
+ pPsProcessType = get_proc_address("PsProcessType");
+ ok(!!pPsProcessType, "PsProcessType not found\n");
+
pPsInitialSystemProcess = get_proc_address("PsInitialSystemProcess");
ok(!!pPsInitialSystemProcess, "PsInitialSystemProcess not found\n");
@@ -2138,6 +2268,7 @@ static NTSTATUS main_test(DEVICE_OBJECT *device, IRP *irp, IO_STACK_LOCATION *st
#endif
test_affinity();
test_dpc();
+ test_apc(test_input);
test_process_memory(test_input);
test_permanence();
diff --git a/dlls/ntoskrnl.exe/tests/driver.h b/dlls/ntoskrnl.exe/tests/driver.h
index 58a92d4838e..d0a609329e0 100644
--- a/dlls/ntoskrnl.exe/tests/driver.h
+++ b/dlls/ntoskrnl.exe/tests/driver.h
@@ -44,6 +44,8 @@ struct test_input
int winetest_report_success;
int winetest_debug;
DWORD process_id;
+ DWORD apc_thread_id;
+ PKNORMAL_ROUTINE apc_func;
SIZE_T teststr_offset;
ULONG64 *modified_value;
WCHAR path[1];
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
index b4ef9d0dcb7..269acb7f43d 100644
--- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
@@ -30,6 +30,7 @@
#include "winsock2.h"
#include "wine/test.h"
#include "wine/heap.h"
+#include "ddk/wdm.h"
#include "driver.h"
@@ -153,6 +154,26 @@ static BOOL start_driver(HANDLE service, BOOL vista_plus)
}
static ULONG64 modified_value;
+static BOOL apc_ran = FALSE;
+
+DWORD WINAPI apc_thread_func(PVOID param)
+{
+ HANDLE done_event = param;
+ DWORD ret;
+
+ WaitForSingleObjectEx(done_event, INFINITE, TRUE);
+ ok (apc_ran == TRUE, "Driver failed to queue user mode APC\n");
+ return 0;
+}
+
+static void WINAPI apc_func(PVOID normal_ctx, PVOID sysarg1, PVOID sysarg2)
+{
+ HANDLE done_event = sysarg2;
+
+ ok(normal_ctx == (PVOID)(ULONG_PTR)0xdeadbeef, "Unexpected normal context %p\n", normal_ctx);
+ apc_ran = TRUE;
+ ok(SetEvent(done_event), "Setting done event failed: %u\n", GetLastError());
+}
static void main_test(void)
{
@@ -160,8 +181,11 @@ static void main_test(void)
WCHAR temppathW[MAX_PATH], pathW[MAX_PATH];
struct test_input *test_input;
DWORD len, written, read;
+ DWORD apc_thread_id = 0;
UNICODE_STRING pathU;
LONG new_failures;
+ HANDLE apc_thread;
+ HANDLE done_event;
char buffer[512];
HANDLE okfile;
BOOL res;
@@ -171,12 +195,24 @@ static void main_test(void)
GetTempFileNameW(temppathW, dokW, 0, pathW);
pRtlDosPathNameToNtPathName_U( pathW, &pathU, NULL, NULL );
+ done_event = CreateEventW(NULL, TRUE, FALSE, NULL);
+ if (done_event)
+ {
+ if ((apc_thread = CreateThread(NULL, 0, apc_thread_func, done_event, 0, &apc_thread_id)))
+ CloseHandle(apc_thread);
+ else
+ CloseHandle(done_event);
+ }
+ ok (apc_thread_id, "APC thread creation failed: %u\n", GetLastError());
+
len = pathU.Length + sizeof(WCHAR);
test_input = heap_alloc( offsetof( struct test_input, path[len / sizeof(WCHAR)]) );
test_input->running_under_wine = !strcmp(winetest_platform, "wine");
test_input->winetest_report_success = winetest_report_success;
test_input->winetest_debug = winetest_debug;
test_input->process_id = GetCurrentProcessId();
+ test_input->apc_thread_id = apc_thread_id;
+ test_input->apc_func = apc_func;
test_input->teststr_offset = (SIZE_T)((BYTE *)&teststr - (BYTE *)NtCurrentTeb()->Peb->ImageBaseAddress);
test_input->modified_value = &modified_value;
modified_value = 0;
@@ -188,6 +224,9 @@ static void main_test(void)
ok(res, "DeviceIoControl failed: %u\n", GetLastError());
ok(written == sizeof(new_failures), "got size %x\n", written);
+ if (apc_thread_id)
+ SetEvent(done_event);
+
okfile = CreateFileW(pathW, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
ok(okfile != INVALID_HANDLE_VALUE, "failed to create %s: %u\n", wine_dbgstr_w(pathW), GetLastError());
--
2.27.0
2
2
Signed-off-by: Gijs Vermeulen <gijsvrm(a)gmail.com>
---
dlls/qdvd/Makefile.in | 3 +-
dlls/qdvd/navigator.c | 67 +++++++++++++
dlls/qdvd/qdvd_classes.idl | 7 ++
dlls/qdvd/qdvd_main.c | 3 +
dlls/qdvd/qdvd_private.h | 1 +
dlls/qdvd/tests/Makefile.in | 3 +-
dlls/qdvd/tests/navigator.c | 191 ++++++++++++++++++++++++++++++++++++
7 files changed, 273 insertions(+), 2 deletions(-)
create mode 100644 dlls/qdvd/navigator.c
create mode 100644 dlls/qdvd/tests/navigator.c
diff --git a/dlls/qdvd/Makefile.in b/dlls/qdvd/Makefile.in
index 8f5089b3ac..364a81e637 100644
--- a/dlls/qdvd/Makefile.in
+++ b/dlls/qdvd/Makefile.in
@@ -1,10 +1,11 @@
MODULE = qdvd.dll
-IMPORTS = strmiids uuid ole32
+IMPORTS = strmbase strmiids uuid ole32
EXTRADLLFLAGS = -mno-cygwin
C_SRCS = \
graph.c \
+ navigator.c \
qdvd_main.c
IDL_SRCS = \
diff --git a/dlls/qdvd/navigator.c b/dlls/qdvd/navigator.c
new file mode 100644
index 0000000000..1e121dde60
--- /dev/null
+++ b/dlls/qdvd/navigator.c
@@ -0,0 +1,67 @@
+/*
+ * Navigator filter
+ *
+ * Copyright 2020 Gijs Vermeulen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "qdvd_private.h"
+#include "wine/strmbase.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(qdvd);
+
+struct navigator
+{
+ struct strmbase_filter filter;
+};
+
+static inline struct navigator *impl_from_strmbase_filter(struct strmbase_filter *filter)
+{
+ return CONTAINING_RECORD(filter, struct navigator, filter);
+}
+
+static struct strmbase_pin *navigator_get_pin(struct strmbase_filter *iface, unsigned int index)
+{
+ return NULL;
+}
+
+static void navigator_destroy(struct strmbase_filter *iface)
+{
+ struct navigator *filter = impl_from_strmbase_filter(iface);
+
+ strmbase_filter_cleanup(&filter->filter);
+ free(filter);
+}
+
+static const struct strmbase_filter_ops filter_ops =
+{
+ .filter_get_pin = navigator_get_pin,
+ .filter_destroy = navigator_destroy,
+};
+
+HRESULT navigator_create(IUnknown *outer, IUnknown **out)
+{
+ struct navigator *object;
+
+ if (!(object = calloc(1, sizeof(*object))))
+ return E_OUTOFMEMORY;
+
+ strmbase_filter_init(&object->filter, outer, &CLSID_DVDNavigator, &filter_ops);
+
+ TRACE("Created DVD Navigator filter %p.\n", object);
+ *out = &object->filter.IUnknown_inner;
+ return S_OK;
+}
diff --git a/dlls/qdvd/qdvd_classes.idl b/dlls/qdvd/qdvd_classes.idl
index 7fd2a081ba..c55c7e3944 100644
--- a/dlls/qdvd/qdvd_classes.idl
+++ b/dlls/qdvd/qdvd_classes.idl
@@ -24,3 +24,10 @@
uuid(fcc152b7-f372-11d0-8e00-00c04fd7c08b),
]
coclass DvdGraphBuilder {}
+
+[
+ helpstring("DVD Navigator Filter"),
+ threading(both),
+ uuid(9b8c4620-2c1a-11d0-8493-00a02438ad48),
+]
+coclass DVDNavigator {}
diff --git a/dlls/qdvd/qdvd_main.c b/dlls/qdvd/qdvd_main.c
index c529533e44..2fdb108877 100644
--- a/dlls/qdvd/qdvd_main.c
+++ b/dlls/qdvd/qdvd_main.c
@@ -100,6 +100,7 @@ static const IClassFactoryVtbl class_factory_vtbl =
};
static struct class_factory graph_builder_cf = {{&class_factory_vtbl}, graph_builder_create};
+static struct class_factory navigator_cf = {{&class_factory_vtbl}, navigator_create};
BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
{
@@ -120,6 +121,8 @@ HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **out)
if (IsEqualGUID(clsid, &CLSID_DvdGraphBuilder))
return IClassFactory_QueryInterface(&graph_builder_cf.IClassFactory_iface, iid, out);
+ if (IsEqualGUID(clsid, &CLSID_DVDNavigator))
+ return IClassFactory_QueryInterface(&navigator_cf.IClassFactory_iface, iid, out);
FIXME("%s not available, returning CLASS_E_CLASSNOTAVAILABLE.\n", debugstr_guid(clsid));
return CLASS_E_CLASSNOTAVAILABLE;
diff --git a/dlls/qdvd/qdvd_private.h b/dlls/qdvd/qdvd_private.h
index 297949ee60..48fced46f1 100644
--- a/dlls/qdvd/qdvd_private.h
+++ b/dlls/qdvd/qdvd_private.h
@@ -26,5 +26,6 @@
#include "wine/debug.h"
HRESULT graph_builder_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
+HRESULT navigator_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
#endif /* QDVD_PRIVATE_H */
diff --git a/dlls/qdvd/tests/Makefile.in b/dlls/qdvd/tests/Makefile.in
index 35d65e224c..fdd769b73e 100644
--- a/dlls/qdvd/tests/Makefile.in
+++ b/dlls/qdvd/tests/Makefile.in
@@ -2,4 +2,5 @@ TESTDLL = qdvd.dll
IMPORTS = strmiids uuid ole32
C_SRCS = \
- graph.c
+ graph.c \
+ navigator.c
diff --git a/dlls/qdvd/tests/navigator.c b/dlls/qdvd/tests/navigator.c
new file mode 100644
index 0000000000..f01e428b4e
--- /dev/null
+++ b/dlls/qdvd/tests/navigator.c
@@ -0,0 +1,191 @@
+/*
+ * Navigator filter unit tests
+ *
+ * Copyright 2020 Gijs Vermeulen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+#include "dshow.h"
+#include "wine/strmbase.h"
+#include "wine/test.h"
+
+static IBaseFilter *create_navigator(void)
+{
+ IBaseFilter *filter = NULL;
+ HRESULT hr = CoCreateInstance(&CLSID_DVDNavigator, NULL,
+ CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (void **)&filter);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ return filter;
+}
+
+static ULONG get_refcount(void *iface)
+{
+ IUnknown *unknown = iface;
+ IUnknown_AddRef(unknown);
+ return IUnknown_Release(unknown);
+}
+
+#define check_interface(a, b, c) check_interface_(__LINE__, a, b, c)
+static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported)
+{
+ IUnknown *iface = iface_ptr;
+ HRESULT hr, expected_hr;
+ IUnknown *unk;
+
+ expected_hr = supported ? S_OK : E_NOINTERFACE;
+
+ hr = IUnknown_QueryInterface(iface, iid, (void **)&unk);
+ ok_(__FILE__, line)(hr == expected_hr, "Got hr %#x, expected %#x.\n", hr, expected_hr);
+ if (SUCCEEDED(hr))
+ IUnknown_Release(unk);
+}
+
+static void test_interfaces(void)
+{
+ IBaseFilter *filter = create_navigator();
+
+ check_interface(filter, &IID_IBaseFilter, TRUE);
+ todo_wine check_interface(filter, &IID_IDvdControl, TRUE);
+ todo_wine check_interface(filter, &IID_IDvdControl2, TRUE);
+ todo_wine check_interface(filter, &IID_IDvdInfo, TRUE);
+ todo_wine check_interface(filter, &IID_IDvdInfo2, TRUE);
+ check_interface(filter, &IID_IMediaFilter, TRUE);
+ check_interface(filter, &IID_IPersist, TRUE);
+ todo_wine check_interface(filter, &IID_ISpecifyPropertyPages, TRUE);
+ check_interface(filter, &IID_IUnknown, TRUE);
+
+ check_interface(filter, &IID_IAMFilterMiscFlags, FALSE);
+ check_interface(filter, &IID_IBasicAudio, FALSE);
+ check_interface(filter, &IID_IBasicVideo, FALSE);
+ check_interface(filter, &IID_IFileSourceFilter, FALSE);
+ check_interface(filter, &IID_IKsPropertySet, FALSE);
+ check_interface(filter, &IID_IMediaPosition, FALSE);
+ check_interface(filter, &IID_IMediaSeeking, FALSE);
+ check_interface(filter, &IID_IPersistPropertyBag, FALSE);
+ check_interface(filter, &IID_IPersistStream, FALSE);
+ check_interface(filter, &IID_IPin, FALSE);
+ check_interface(filter, &IID_IQualityControl, FALSE);
+ check_interface(filter, &IID_IQualProp, FALSE);
+ check_interface(filter, &IID_IReferenceClock, FALSE);
+ check_interface(filter, &IID_IVideoWindow, FALSE);
+
+ IBaseFilter_Release(filter);
+}
+
+static const GUID test_iid = {0x33333333};
+static LONG outer_ref = 1;
+
+static HRESULT WINAPI outer_QueryInterface(IUnknown *iface, REFIID iid, void **out)
+{
+ if (IsEqualGUID(iid, &IID_IUnknown)
+ || IsEqualGUID(iid, &IID_IBaseFilter)
+ || IsEqualGUID(iid, &test_iid))
+ {
+ *out = (IUnknown *)0xdeadbeef;
+ return S_OK;
+ }
+ ok(0, "unexpected call %s\n", wine_dbgstr_guid(iid));
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI outer_AddRef(IUnknown *iface)
+{
+ return InterlockedIncrement(&outer_ref);
+}
+
+static ULONG WINAPI outer_Release(IUnknown *iface)
+{
+ return InterlockedDecrement(&outer_ref);
+}
+
+static const IUnknownVtbl outer_vtbl =
+{
+ outer_QueryInterface,
+ outer_AddRef,
+ outer_Release,
+};
+
+static IUnknown test_outer = {&outer_vtbl};
+
+static void test_aggregation(void)
+{
+ IBaseFilter *filter, *filter2;
+ IUnknown *unk, *unk2;
+ HRESULT hr;
+ ULONG ref;
+
+ filter = (IBaseFilter *)0xdeadbeef;
+ hr = CoCreateInstance(&CLSID_DVDNavigator, &test_outer, CLSCTX_INPROC_SERVER,
+ &IID_IBaseFilter, (void **)&filter);
+ ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
+ ok(!filter, "Got interface %p.\n", filter);
+
+ hr = CoCreateInstance(&CLSID_DVDNavigator, &test_outer, CLSCTX_INPROC_SERVER,
+ &IID_IUnknown, (void **)&unk);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
+ ok(unk != &test_outer, "Returned IUnknown should not be outer IUnknown.\n");
+ ref = get_refcount(unk);
+ ok(ref == 1, "Got unexpected refcount %d.\n", ref);
+
+ ref = IUnknown_AddRef(unk);
+ ok(ref == 2, "Got unexpected refcount %d.\n", ref);
+ ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
+
+ ref = IUnknown_Release(unk);
+ ok(ref == 1, "Got unexpected refcount %d.\n", ref);
+ ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
+
+ hr = IUnknown_QueryInterface(unk, &IID_IUnknown, (void **)&unk2);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(unk2 == unk, "Got unexpected IUnknown %p.\n", unk2);
+ IUnknown_Release(unk2);
+
+ hr = IUnknown_QueryInterface(unk, &IID_IBaseFilter, (void **)&filter);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IBaseFilter_QueryInterface(filter, &IID_IUnknown, (void **)&unk2);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(unk2 == (IUnknown *)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2);
+
+ hr = IBaseFilter_QueryInterface(filter, &IID_IBaseFilter, (void **)&filter2);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(filter2 == (IBaseFilter *)0xdeadbeef, "Got unexpected IBaseFilter %p.\n", filter2);
+
+ hr = IUnknown_QueryInterface(unk, &test_iid, (void **)&unk2);
+ ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
+ ok(!unk2, "Got unexpected IUnknown %p.\n", unk2);
+
+ hr = IBaseFilter_QueryInterface(filter, &test_iid, (void **)&unk2);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(unk2 == (IUnknown *)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2);
+
+ IBaseFilter_Release(filter);
+ ref = IUnknown_Release(unk);
+ ok(!ref, "Got unexpected refcount %d.\n", ref);
+ ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
+}
+
+START_TEST(navigator)
+{
+ CoInitializeEx(NULL, COINIT_MULTITHREADED);
+
+ test_interfaces();
+ test_aggregation();
+
+ CoUninitialize();
+}
--
2.27.0
3
5
[PATCH v2 1/5] quartz/tests: Add tests for DirectSound renderer filter state.
by Zebediah Figura 17 Jul '20
by Zebediah Figura 17 Jul '20
17 Jul '20
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/quartz/tests/dsoundrender.c | 233 +++++++++++++++++++++++--------
1 file changed, 176 insertions(+), 57 deletions(-)
diff --git a/dlls/quartz/tests/dsoundrender.c b/dlls/quartz/tests/dsoundrender.c
index d5c18d389a4..35f935bcad5 100644
--- a/dlls/quartz/tests/dsoundrender.c
+++ b/dlls/quartz/tests/dsoundrender.c
@@ -20,6 +20,7 @@
*/
#define COBJMACROS
+#include <math.h>
#include "dshow.h"
#include "initguid.h"
#include "dsound.h"
@@ -674,8 +675,164 @@ static void test_allocator(IMemInputPin *input)
IMemAllocator_Release(ret_allocator);
}
+struct frame_thread_params
+{
+ IMemInputPin *sink;
+ IMediaSample *sample;
+};
+
+static DWORD WINAPI frame_thread(void *arg)
+{
+ struct frame_thread_params *params = arg;
+ HRESULT hr;
+
+ if (winetest_debug > 1) trace("%04x: Sending frame.\n", GetCurrentThreadId());
+ hr = IMemInputPin_Receive(params->sink, params->sample);
+ if (winetest_debug > 1) trace("%04x: Returned %#x.\n", GetCurrentThreadId(), hr);
+ IMediaSample_Release(params->sample);
+ free(params);
+ return hr;
+}
+
+static HRESULT send_frame(IMemInputPin *sink)
+{
+ struct frame_thread_params *params = malloc(sizeof(*params));
+ REFERENCE_TIME start_time, end_time;
+ IMemAllocator *allocator;
+ unsigned short *words;
+ IMediaSample *sample;
+ unsigned int i;
+ HANDLE thread;
+ HRESULT hr;
+ BYTE *data;
+ DWORD ret;
+
+ hr = IMemInputPin_GetAllocator(sink, &allocator);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaSample_GetPointer(sample, &data);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ words = (unsigned short *)data;
+ for (i = 0; i < 44100 * 2; i += 2)
+ words[i] = words[i+1] = sinf(i / 20.0f) * 0x7fff;
+
+ hr = IMediaSample_SetActualDataLength(sample, 44100 * 4);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ start_time = 0;
+ end_time = start_time + 10000000;
+ hr = IMediaSample_SetTime(sample, &start_time, &end_time);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ params->sink = sink;
+ params->sample = sample;
+ thread = CreateThread(NULL, 0, frame_thread, params, 0, NULL);
+ ret = WaitForSingleObject(thread, 500);
+ todo_wine_if (ret) ok(!ret, "Wait failed.\n");
+ GetExitCodeThread(thread, &ret);
+ CloseHandle(thread);
+
+ IMemAllocator_Release(allocator);
+ return ret;
+}
+
+static void test_filter_state(IMemInputPin *input, IFilterGraph2 *graph)
+{
+ IMediaControl *control;
+ OAFilterState state;
+ HRESULT hr;
+
+ IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
+
+ hr = send_frame(input);
+ ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
+
+ /* The renderer is not fully paused until it receives a sample. The
+ * DirectSound renderer never blocks in Receive(), despite returning S_OK
+ * from ReceiveCanBlock(). Instead it holds on to each sample until its
+ * presentation time, then writes it into the buffer. This is more work
+ * than it's worth to emulate, so for now, we'll ignore this behaviour. */
+
+ hr = IMediaControl_Pause(control);
+ ok(hr == S_FALSE, "Got hr %#x.\n", hr);
+
+ /* It's possible to queue multiple samples while paused. The number of
+ * samples that can be queued depends on the length of each sample, but
+ * it's not particularly clear how. */
+
+ hr = IMediaControl_GetState(control, 0, &state);
+ ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
+
+ hr = send_frame(input);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_GetState(control, 1000, &state);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_Stop(control);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = send_frame(input);
+ ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_Pause(control);
+ ok(hr == S_FALSE, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_GetState(control, 0, &state);
+ ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
+
+ hr = send_frame(input);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_GetState(control, 1000, &state);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_Run(control);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_GetState(control, 0, &state);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = send_frame(input);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = send_frame(input);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_GetState(control, 0, &state);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_Run(control);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_GetState(control, 0, &state);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_Pause(control);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_GetState(control, 0, &state);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_Stop(control);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_GetState(control, 0, &state);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ /* The DirectSound renderer will silently refuse to transition to running
+ * if it hasn't finished pausing yet. Once it does it reports itself as
+ * completely paused. */
+
+ IMediaControl_Release(control);
+}
+
static void test_connect_pin(void)
{
+ ALLOCATOR_PROPERTIES req_props = {1, 4 * 44100, 1, 0}, ret_props;
WAVEFORMATEX wfx =
{
.wFormatTag = WAVE_FORMAT_PCM,
@@ -695,6 +852,7 @@ static void test_connect_pin(void)
};
IBaseFilter *filter = create_dsound_render();
struct testfilter source;
+ IMemAllocator *allocator;
IFilterGraph2 *graph;
IMemInputPin *input;
AM_MEDIA_TYPE mt;
@@ -734,6 +892,22 @@ static void test_connect_pin(void)
test_allocator(input);
+ hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IMemAllocator, (void **)&allocator);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IMemAllocator_SetProperties(allocator, &req_props, &ret_props);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(!memcmp(&ret_props, &req_props, sizeof(req_props)), "Properties did not match.\n");
+ hr = IMemInputPin_NotifyAllocator(input, allocator, TRUE);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IMemAllocator_Commit(allocator);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMemInputPin_ReceiveCanBlock(input);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ test_filter_state(input, graph);
+
hr = IFilterGraph2_Disconnect(graph, pin);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IFilterGraph2_Disconnect(graph, pin);
@@ -749,6 +923,8 @@ static void test_connect_pin(void)
hr = IPin_ConnectionMediaType(pin, &mt);
ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
+ ref = IMemAllocator_Release(allocator);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
IMemInputPin_Release(input);
IPin_Release(pin);
ref = IFilterGraph2_Release(graph);
@@ -759,62 +935,6 @@ static void test_connect_pin(void)
ok(!ref, "Got outstanding refcount %d.\n", ref);
}
-static void test_pin(IPin *pin)
-{
- IMemInputPin *mpin = NULL;
-
- IPin_QueryInterface(pin, &IID_IMemInputPin, (void **)&mpin);
-
- ok(mpin != NULL, "No IMemInputPin found!\n");
- if (mpin)
- {
- ok(IMemInputPin_ReceiveCanBlock(mpin) == S_OK, "Receive can't block for pin!\n");
- ok(IMemInputPin_NotifyAllocator(mpin, NULL, 0) == E_POINTER, "NotifyAllocator likes a NULL pointer argument\n");
- IMemInputPin_Release(mpin);
- }
- /* TODO */
-}
-
-static void test_basefilter(void)
-{
- IEnumPins *pin_enum = NULL;
- IBaseFilter *base = create_dsound_render();
- IPin *pins[2];
- ULONG ref;
- HRESULT hr;
-
- hr = IBaseFilter_EnumPins(base, NULL);
- ok(hr == E_POINTER, "hr = %08x and not E_POINTER\n", hr);
-
- hr= IBaseFilter_EnumPins(base, &pin_enum);
- ok(hr == S_OK, "hr = %08x and not S_OK\n", hr);
-
- hr = IEnumPins_Next(pin_enum, 1, NULL, NULL);
- ok(hr == E_POINTER, "hr = %08x and not E_POINTER\n", hr);
-
- hr = IEnumPins_Next(pin_enum, 2, pins, NULL);
- ok(hr == E_INVALIDARG, "hr = %08x and not E_INVALIDARG\n", hr);
-
- pins[0] = (void *)0xdead;
- pins[1] = (void *)0xdeed;
-
- hr = IEnumPins_Next(pin_enum, 2, pins, &ref);
- ok(hr == S_FALSE, "hr = %08x instead of S_FALSE\n", hr);
- ok(pins[0] != (void *)0xdead && pins[0] != NULL, "pins[0] = %p\n", pins[0]);
- if (pins[0] != (void *)0xdead && pins[0] != NULL)
- {
- test_pin(pins[0]);
- IPin_Release(pins[0]);
- }
-
- ok(pins[1] == (void *)0xdeed, "pins[1] = %p\n", pins[1]);
-
- ref = IEnumPins_Release(pin_enum);
- ok(ref == 0, "ref is %u and not 0!\n", ref);
-
- IBaseFilter_Release(base);
-}
-
static void test_unconnected_filter_state(void)
{
IBaseFilter *filter = create_dsound_render();
@@ -1016,7 +1136,6 @@ START_TEST(dsoundrender)
test_unconnected_filter_state();
test_media_types();
test_connect_pin();
- test_basefilter();
CoUninitialize();
}
--
2.27.0
1
4
[PATCH 1/5] quartz/tests: Add tests for DirectSound renderer filter state.
by Zebediah Figura 17 Jul '20
by Zebediah Figura 17 Jul '20
17 Jul '20
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/quartz/tests/dsoundrender.c | 243 +++++++++++++++++++++++--------
1 file changed, 186 insertions(+), 57 deletions(-)
diff --git a/dlls/quartz/tests/dsoundrender.c b/dlls/quartz/tests/dsoundrender.c
index d5c18d389a4..a11036f6c19 100644
--- a/dlls/quartz/tests/dsoundrender.c
+++ b/dlls/quartz/tests/dsoundrender.c
@@ -20,6 +20,7 @@
*/
#define COBJMACROS
+#include <math.h>
#include "dshow.h"
#include "initguid.h"
#include "dsound.h"
@@ -674,8 +675,174 @@ static void test_allocator(IMemInputPin *input)
IMemAllocator_Release(ret_allocator);
}
+struct frame_thread_params
+{
+ IMemInputPin *sink;
+ IMediaSample *sample;
+};
+
+static DWORD WINAPI frame_thread(void *arg)
+{
+ struct frame_thread_params *params = arg;
+ HRESULT hr;
+
+ if (winetest_debug > 1) trace("%04x: Sending frame.\n", GetCurrentThreadId());
+ hr = IMemInputPin_Receive(params->sink, params->sample);
+ if (winetest_debug > 1) trace("%04x: Returned %#x.\n", GetCurrentThreadId(), hr);
+ IMediaSample_Release(params->sample);
+ free(params);
+ return hr;
+}
+
+static HRESULT send_frame(IMemInputPin *sink)
+{
+ struct frame_thread_params *params = malloc(sizeof(params));
+ REFERENCE_TIME start_time, end_time;
+ IMemAllocator *allocator;
+ unsigned short *words;
+ IMediaSample *sample;
+ unsigned int i;
+ HANDLE thread;
+ HRESULT hr;
+ BYTE *data;
+ DWORD ret;
+
+ hr = IMemInputPin_GetAllocator(sink, &allocator);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaSample_GetPointer(sample, &data);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ words = (unsigned short *)data;
+ for (i = 0; i < 44100 * 2; i += 2)
+ words[i] = words[i+1] = sinf(i / 20.0f) * 0x7fff;
+
+ hr = IMediaSample_SetActualDataLength(sample, 44100 * 4);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ start_time = 0;
+ end_time = start_time + 10000000;
+ hr = IMediaSample_SetTime(sample, &start_time, &end_time);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ params->sink = sink;
+ params->sample = sample;
+ thread = CreateThread(NULL, 0, frame_thread, params, 0, NULL);
+ ret = WaitForSingleObject(thread, 500);
+ todo_wine_if (ret) ok(!ret, "Wait failed.\n");
+ GetExitCodeThread(thread, &ret);
+ CloseHandle(thread);
+
+ IMemAllocator_Release(allocator);
+ return ret;
+}
+
+static void test_filter_state(IMemInputPin *input, IFilterGraph2 *graph)
+{
+ IMemAllocator *allocator;
+ IMediaControl *control;
+ IMediaSample *sample;
+ OAFilterState state;
+ HRESULT hr;
+
+ hr = IMemInputPin_GetAllocator(input, &allocator);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
+
+ hr = send_frame(input);
+ ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
+
+ /* The renderer is not fully paused until it receives a sample. The
+ * DirectSound renderer never blocks in Receive(), despite returning S_OK
+ * from ReceiveCanBlock(). Instead it holds on to each sample until its
+ * presentation time, then writes it into the buffer. This is more work
+ * than it's worth to emulate, so for now, we'll ignore this behaviour. */
+
+ hr = IMediaControl_Pause(control);
+ ok(hr == S_FALSE, "Got hr %#x.\n", hr);
+
+ /* It's possible to queue multiple samples while paused. The number of
+ * samples that can be queued depends on the length of each sample, but
+ * it's not particularly clear how. */
+
+ hr = IMediaControl_GetState(control, 0, &state);
+ ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
+
+ hr = send_frame(input);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_GetState(control, 1000, &state);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_Stop(control);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, AM_GBF_NOWAIT);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ if (hr == S_OK) IMediaSample_Release(sample);
+
+ hr = send_frame(input);
+ ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_Pause(control);
+ ok(hr == S_FALSE, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_GetState(control, 0, &state);
+ ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
+
+ hr = send_frame(input);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_GetState(control, 1000, &state);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_Run(control);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_GetState(control, 0, &state);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = send_frame(input);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = send_frame(input);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_GetState(control, 0, &state);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_Run(control);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_GetState(control, 0, &state);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_Pause(control);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_GetState(control, 0, &state);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_Stop(control);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_GetState(control, 0, &state);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ /* The DirectSound renderer will silently refuse to transition to running
+ * if it hasn't finished pausing yet. Once it does it reports itself as
+ * completely paused. */
+
+ IMediaControl_Release(control);
+ IMemAllocator_Release(allocator);
+}
+
static void test_connect_pin(void)
{
+ ALLOCATOR_PROPERTIES req_props = {1, 4 * 44100, 1, 0}, ret_props;
WAVEFORMATEX wfx =
{
.wFormatTag = WAVE_FORMAT_PCM,
@@ -695,6 +862,7 @@ static void test_connect_pin(void)
};
IBaseFilter *filter = create_dsound_render();
struct testfilter source;
+ IMemAllocator *allocator;
IFilterGraph2 *graph;
IMemInputPin *input;
AM_MEDIA_TYPE mt;
@@ -734,6 +902,22 @@ static void test_connect_pin(void)
test_allocator(input);
+ hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IMemAllocator, (void **)&allocator);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IMemAllocator_SetProperties(allocator, &req_props, &ret_props);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(!memcmp(&ret_props, &req_props, sizeof(req_props)), "Properties did not match.\n");
+ hr = IMemInputPin_NotifyAllocator(input, allocator, TRUE);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IMemAllocator_Commit(allocator);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMemInputPin_ReceiveCanBlock(input);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ test_filter_state(input, graph);
+
hr = IFilterGraph2_Disconnect(graph, pin);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IFilterGraph2_Disconnect(graph, pin);
@@ -749,6 +933,8 @@ static void test_connect_pin(void)
hr = IPin_ConnectionMediaType(pin, &mt);
ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
+ ref = IMemAllocator_Release(allocator);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
IMemInputPin_Release(input);
IPin_Release(pin);
ref = IFilterGraph2_Release(graph);
@@ -759,62 +945,6 @@ static void test_connect_pin(void)
ok(!ref, "Got outstanding refcount %d.\n", ref);
}
-static void test_pin(IPin *pin)
-{
- IMemInputPin *mpin = NULL;
-
- IPin_QueryInterface(pin, &IID_IMemInputPin, (void **)&mpin);
-
- ok(mpin != NULL, "No IMemInputPin found!\n");
- if (mpin)
- {
- ok(IMemInputPin_ReceiveCanBlock(mpin) == S_OK, "Receive can't block for pin!\n");
- ok(IMemInputPin_NotifyAllocator(mpin, NULL, 0) == E_POINTER, "NotifyAllocator likes a NULL pointer argument\n");
- IMemInputPin_Release(mpin);
- }
- /* TODO */
-}
-
-static void test_basefilter(void)
-{
- IEnumPins *pin_enum = NULL;
- IBaseFilter *base = create_dsound_render();
- IPin *pins[2];
- ULONG ref;
- HRESULT hr;
-
- hr = IBaseFilter_EnumPins(base, NULL);
- ok(hr == E_POINTER, "hr = %08x and not E_POINTER\n", hr);
-
- hr= IBaseFilter_EnumPins(base, &pin_enum);
- ok(hr == S_OK, "hr = %08x and not S_OK\n", hr);
-
- hr = IEnumPins_Next(pin_enum, 1, NULL, NULL);
- ok(hr == E_POINTER, "hr = %08x and not E_POINTER\n", hr);
-
- hr = IEnumPins_Next(pin_enum, 2, pins, NULL);
- ok(hr == E_INVALIDARG, "hr = %08x and not E_INVALIDARG\n", hr);
-
- pins[0] = (void *)0xdead;
- pins[1] = (void *)0xdeed;
-
- hr = IEnumPins_Next(pin_enum, 2, pins, &ref);
- ok(hr == S_FALSE, "hr = %08x instead of S_FALSE\n", hr);
- ok(pins[0] != (void *)0xdead && pins[0] != NULL, "pins[0] = %p\n", pins[0]);
- if (pins[0] != (void *)0xdead && pins[0] != NULL)
- {
- test_pin(pins[0]);
- IPin_Release(pins[0]);
- }
-
- ok(pins[1] == (void *)0xdeed, "pins[1] = %p\n", pins[1]);
-
- ref = IEnumPins_Release(pin_enum);
- ok(ref == 0, "ref is %u and not 0!\n", ref);
-
- IBaseFilter_Release(base);
-}
-
static void test_unconnected_filter_state(void)
{
IBaseFilter *filter = create_dsound_render();
@@ -1016,7 +1146,6 @@ START_TEST(dsoundrender)
test_unconnected_filter_state();
test_media_types();
test_connect_pin();
- test_basefilter();
CoUninitialize();
}
--
2.27.0
3
9
Signed-off-by: Gijs Vermeulen <gijsvrm(a)gmail.com>
---
dlls/qdvd/Makefile.in | 3 +-
dlls/qdvd/navigator.c | 67 +++++++++++++
dlls/qdvd/qdvd_classes.idl | 7 ++
dlls/qdvd/qdvd_main.c | 3 +
dlls/qdvd/qdvd_private.h | 1 +
dlls/qdvd/tests/Makefile.in | 3 +-
dlls/qdvd/tests/navigator.c | 191 ++++++++++++++++++++++++++++++++++++
7 files changed, 273 insertions(+), 2 deletions(-)
create mode 100644 dlls/qdvd/navigator.c
create mode 100644 dlls/qdvd/tests/navigator.c
diff --git a/dlls/qdvd/Makefile.in b/dlls/qdvd/Makefile.in
index 8f5089b3ac..364a81e637 100644
--- a/dlls/qdvd/Makefile.in
+++ b/dlls/qdvd/Makefile.in
@@ -1,10 +1,11 @@
MODULE = qdvd.dll
-IMPORTS = strmiids uuid ole32
+IMPORTS = strmbase strmiids uuid ole32
EXTRADLLFLAGS = -mno-cygwin
C_SRCS = \
graph.c \
+ navigator.c \
qdvd_main.c
IDL_SRCS = \
diff --git a/dlls/qdvd/navigator.c b/dlls/qdvd/navigator.c
new file mode 100644
index 0000000000..1e121dde60
--- /dev/null
+++ b/dlls/qdvd/navigator.c
@@ -0,0 +1,67 @@
+/*
+ * Navigator filter
+ *
+ * Copyright 2020 Gijs Vermeulen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "qdvd_private.h"
+#include "wine/strmbase.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(qdvd);
+
+struct navigator
+{
+ struct strmbase_filter filter;
+};
+
+static inline struct navigator *impl_from_strmbase_filter(struct strmbase_filter *filter)
+{
+ return CONTAINING_RECORD(filter, struct navigator, filter);
+}
+
+static struct strmbase_pin *navigator_get_pin(struct strmbase_filter *iface, unsigned int index)
+{
+ return NULL;
+}
+
+static void navigator_destroy(struct strmbase_filter *iface)
+{
+ struct navigator *filter = impl_from_strmbase_filter(iface);
+
+ strmbase_filter_cleanup(&filter->filter);
+ free(filter);
+}
+
+static const struct strmbase_filter_ops filter_ops =
+{
+ .filter_get_pin = navigator_get_pin,
+ .filter_destroy = navigator_destroy,
+};
+
+HRESULT navigator_create(IUnknown *outer, IUnknown **out)
+{
+ struct navigator *object;
+
+ if (!(object = calloc(1, sizeof(*object))))
+ return E_OUTOFMEMORY;
+
+ strmbase_filter_init(&object->filter, outer, &CLSID_DVDNavigator, &filter_ops);
+
+ TRACE("Created DVD Navigator filter %p.\n", object);
+ *out = &object->filter.IUnknown_inner;
+ return S_OK;
+}
diff --git a/dlls/qdvd/qdvd_classes.idl b/dlls/qdvd/qdvd_classes.idl
index 7fd2a081ba..c55c7e3944 100644
--- a/dlls/qdvd/qdvd_classes.idl
+++ b/dlls/qdvd/qdvd_classes.idl
@@ -24,3 +24,10 @@
uuid(fcc152b7-f372-11d0-8e00-00c04fd7c08b),
]
coclass DvdGraphBuilder {}
+
+[
+ helpstring("DVD Navigator Filter"),
+ threading(both),
+ uuid(9b8c4620-2c1a-11d0-8493-00a02438ad48),
+]
+coclass DVDNavigator {}
diff --git a/dlls/qdvd/qdvd_main.c b/dlls/qdvd/qdvd_main.c
index c529533e44..2fdb108877 100644
--- a/dlls/qdvd/qdvd_main.c
+++ b/dlls/qdvd/qdvd_main.c
@@ -100,6 +100,7 @@ static const IClassFactoryVtbl class_factory_vtbl =
};
static struct class_factory graph_builder_cf = {{&class_factory_vtbl}, graph_builder_create};
+static struct class_factory navigator_cf = {{&class_factory_vtbl}, navigator_create};
BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
{
@@ -120,6 +121,8 @@ HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **out)
if (IsEqualGUID(clsid, &CLSID_DvdGraphBuilder))
return IClassFactory_QueryInterface(&graph_builder_cf.IClassFactory_iface, iid, out);
+ if (IsEqualGUID(clsid, &CLSID_DVDNavigator))
+ return IClassFactory_QueryInterface(&navigator_cf.IClassFactory_iface, iid, out);
FIXME("%s not available, returning CLASS_E_CLASSNOTAVAILABLE.\n", debugstr_guid(clsid));
return CLASS_E_CLASSNOTAVAILABLE;
diff --git a/dlls/qdvd/qdvd_private.h b/dlls/qdvd/qdvd_private.h
index 297949ee60..48fced46f1 100644
--- a/dlls/qdvd/qdvd_private.h
+++ b/dlls/qdvd/qdvd_private.h
@@ -26,5 +26,6 @@
#include "wine/debug.h"
HRESULT graph_builder_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
+HRESULT navigator_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
#endif /* QDVD_PRIVATE_H */
diff --git a/dlls/qdvd/tests/Makefile.in b/dlls/qdvd/tests/Makefile.in
index 35d65e224c..fdd769b73e 100644
--- a/dlls/qdvd/tests/Makefile.in
+++ b/dlls/qdvd/tests/Makefile.in
@@ -2,4 +2,5 @@ TESTDLL = qdvd.dll
IMPORTS = strmiids uuid ole32
C_SRCS = \
- graph.c
+ graph.c \
+ navigator.c
diff --git a/dlls/qdvd/tests/navigator.c b/dlls/qdvd/tests/navigator.c
new file mode 100644
index 0000000000..f01e428b4e
--- /dev/null
+++ b/dlls/qdvd/tests/navigator.c
@@ -0,0 +1,191 @@
+/*
+ * Navigator filter unit tests
+ *
+ * Copyright 2020 Gijs Vermeulen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+#include "dshow.h"
+#include "wine/strmbase.h"
+#include "wine/test.h"
+
+static IBaseFilter *create_navigator(void)
+{
+ IBaseFilter *filter = NULL;
+ HRESULT hr = CoCreateInstance(&CLSID_DVDNavigator, NULL,
+ CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (void **)&filter);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ return filter;
+}
+
+static ULONG get_refcount(void *iface)
+{
+ IUnknown *unknown = iface;
+ IUnknown_AddRef(unknown);
+ return IUnknown_Release(unknown);
+}
+
+#define check_interface(a, b, c) check_interface_(__LINE__, a, b, c)
+static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported)
+{
+ IUnknown *iface = iface_ptr;
+ HRESULT hr, expected_hr;
+ IUnknown *unk;
+
+ expected_hr = supported ? S_OK : E_NOINTERFACE;
+
+ hr = IUnknown_QueryInterface(iface, iid, (void **)&unk);
+ ok_(__FILE__, line)(hr == expected_hr, "Got hr %#x, expected %#x.\n", hr, expected_hr);
+ if (SUCCEEDED(hr))
+ IUnknown_Release(unk);
+}
+
+static void test_interfaces(void)
+{
+ IBaseFilter *filter = create_navigator();
+
+ check_interface(filter, &IID_IBaseFilter, TRUE);
+ todo_wine check_interface(filter, &IID_IDvdControl, TRUE);
+ todo_wine check_interface(filter, &IID_IDvdControl2, TRUE);
+ todo_wine check_interface(filter, &IID_IDvdInfo, TRUE);
+ todo_wine check_interface(filter, &IID_IDvdInfo2, TRUE);
+ check_interface(filter, &IID_IMediaFilter, TRUE);
+ check_interface(filter, &IID_IPersist, TRUE);
+ todo_wine check_interface(filter, &IID_ISpecifyPropertyPages, TRUE);
+ check_interface(filter, &IID_IUnknown, TRUE);
+
+ check_interface(filter, &IID_IAMFilterMiscFlags, FALSE);
+ check_interface(filter, &IID_IBasicAudio, FALSE);
+ check_interface(filter, &IID_IBasicVideo, FALSE);
+ check_interface(filter, &IID_IFileSourceFilter, FALSE);
+ check_interface(filter, &IID_IKsPropertySet, FALSE);
+ check_interface(filter, &IID_IMediaPosition, FALSE);
+ check_interface(filter, &IID_IMediaSeeking, FALSE);
+ check_interface(filter, &IID_IPersistPropertyBag, FALSE);
+ check_interface(filter, &IID_IPersistStream, FALSE);
+ check_interface(filter, &IID_IPin, FALSE);
+ check_interface(filter, &IID_IQualityControl, FALSE);
+ check_interface(filter, &IID_IQualProp, FALSE);
+ check_interface(filter, &IID_IReferenceClock, FALSE);
+ check_interface(filter, &IID_IVideoWindow, FALSE);
+
+ IBaseFilter_Release(filter);
+}
+
+static const GUID test_iid = {0x33333333};
+static LONG outer_ref = 1;
+
+static HRESULT WINAPI outer_QueryInterface(IUnknown *iface, REFIID iid, void **out)
+{
+ if (IsEqualGUID(iid, &IID_IUnknown)
+ || IsEqualGUID(iid, &IID_IBaseFilter)
+ || IsEqualGUID(iid, &test_iid))
+ {
+ *out = (IUnknown *)0xdeadbeef;
+ return S_OK;
+ }
+ ok(0, "unexpected call %s\n", wine_dbgstr_guid(iid));
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI outer_AddRef(IUnknown *iface)
+{
+ return InterlockedIncrement(&outer_ref);
+}
+
+static ULONG WINAPI outer_Release(IUnknown *iface)
+{
+ return InterlockedDecrement(&outer_ref);
+}
+
+static const IUnknownVtbl outer_vtbl =
+{
+ outer_QueryInterface,
+ outer_AddRef,
+ outer_Release,
+};
+
+static IUnknown test_outer = {&outer_vtbl};
+
+static void test_aggregation(void)
+{
+ IBaseFilter *filter, *filter2;
+ IUnknown *unk, *unk2;
+ HRESULT hr;
+ ULONG ref;
+
+ filter = (IBaseFilter *)0xdeadbeef;
+ hr = CoCreateInstance(&CLSID_DVDNavigator, &test_outer, CLSCTX_INPROC_SERVER,
+ &IID_IBaseFilter, (void **)&filter);
+ ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
+ ok(!filter, "Got interface %p.\n", filter);
+
+ hr = CoCreateInstance(&CLSID_DVDNavigator, &test_outer, CLSCTX_INPROC_SERVER,
+ &IID_IUnknown, (void **)&unk);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
+ ok(unk != &test_outer, "Returned IUnknown should not be outer IUnknown.\n");
+ ref = get_refcount(unk);
+ ok(ref == 1, "Got unexpected refcount %d.\n", ref);
+
+ ref = IUnknown_AddRef(unk);
+ ok(ref == 2, "Got unexpected refcount %d.\n", ref);
+ ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
+
+ ref = IUnknown_Release(unk);
+ ok(ref == 1, "Got unexpected refcount %d.\n", ref);
+ ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
+
+ hr = IUnknown_QueryInterface(unk, &IID_IUnknown, (void **)&unk2);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(unk2 == unk, "Got unexpected IUnknown %p.\n", unk2);
+ IUnknown_Release(unk2);
+
+ hr = IUnknown_QueryInterface(unk, &IID_IBaseFilter, (void **)&filter);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IBaseFilter_QueryInterface(filter, &IID_IUnknown, (void **)&unk2);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(unk2 == (IUnknown *)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2);
+
+ hr = IBaseFilter_QueryInterface(filter, &IID_IBaseFilter, (void **)&filter2);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(filter2 == (IBaseFilter *)0xdeadbeef, "Got unexpected IBaseFilter %p.\n", filter2);
+
+ hr = IUnknown_QueryInterface(unk, &test_iid, (void **)&unk2);
+ ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
+ ok(!unk2, "Got unexpected IUnknown %p.\n", unk2);
+
+ hr = IBaseFilter_QueryInterface(filter, &test_iid, (void **)&unk2);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(unk2 == (IUnknown *)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2);
+
+ IBaseFilter_Release(filter);
+ ref = IUnknown_Release(unk);
+ ok(!ref, "Got unexpected refcount %d.\n", ref);
+ ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
+}
+
+START_TEST(navigator)
+{
+ CoInitializeEx(NULL, COINIT_MULTITHREADED);
+
+ test_interfaces();
+ test_aggregation();
+
+ CoUninitialize();
+}
--
2.27.0
3
5
Signed-off-by: Piotr Caban <piotr(a)codeweavers.com>
---
dlls/msvcr100/msvcr100.spec | 2 +-
dlls/msvcr110/msvcr110.spec | 2 +-
dlls/msvcr120/msvcr120.spec | 2 +-
dlls/msvcr120_app/msvcr120_app.spec | 2 +-
dlls/msvcr70/msvcr70.spec | 2 +-
dlls/msvcr71/msvcr71.spec | 2 +-
dlls/msvcr80/msvcr80.spec | 2 +-
dlls/msvcr90/msvcr90.spec | 2 +-
dlls/msvcrt/ctype.c | 2 ++
dlls/msvcrt/msvcrt.spec | 2 +-
dlls/msvcrt20/msvcrt20.spec | 2 +-
dlls/msvcrt40/msvcrt40.spec | 2 +-
dlls/msvcrtd/msvcrtd.spec | 2 +-
13 files changed, 14 insertions(+), 12 deletions(-)
1
0
The content of table matches with ucrtbase.dll.
Signed-off-by: Piotr Caban <piotr(a)codeweavers.com>
---
.../api-ms-win-crt-string-l1-1-0.spec | 2 +-
dlls/msvcr100/msvcr100.spec | 2 +-
dlls/msvcr110/msvcr110.spec | 2 +-
dlls/msvcr120/msvcr120.spec | 2 +-
dlls/msvcr120_app/msvcr120_app.spec | 2 +-
dlls/msvcr70/msvcr70.spec | 2 +-
dlls/msvcr71/msvcr71.spec | 2 +-
dlls/msvcr80/msvcr80.spec | 2 +-
dlls/msvcr90/msvcr90.spec | 2 +-
dlls/msvcrt/ctype.c | 53 +++++++++++++++++++
dlls/msvcrt/msvcrt.spec | 2 +-
dlls/ucrtbase/ucrtbase.spec | 2 +-
12 files changed, 64 insertions(+), 11 deletions(-)
1
0