Wine-devel
Threads by month
- ----- 2026 -----
- March
- February
- January
- ----- 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
April 2020
- 87 participants
- 854 discussions
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
configure | 2 +
configure.ac | 1 +
dlls/sechost/Makefile.in | 3 +
dlls/sechost/sechost.spec | 208 ++++++++++++++++++++++++++++++++++++++
tools/make_specfiles | 1 +
5 files changed, 215 insertions(+)
create mode 100644 dlls/sechost/Makefile.in
create mode 100644 dlls/sechost/sechost.spec
diff --git a/configure b/configure
index 511837c1c73..1f4080fc545 100755
--- a/configure
+++ b/configure
@@ -1556,6 +1556,7 @@ enable_schedsvc
enable_scrobj
enable_scrrun
enable_scsiport_sys
+enable_sechost
enable_secur32
enable_security
enable_sensapi
@@ -20951,6 +20952,7 @@ wine_fn_config_makefile dlls/scrobj/tests enable_tests
wine_fn_config_makefile dlls/scrrun enable_scrrun
wine_fn_config_makefile dlls/scrrun/tests enable_tests
wine_fn_config_makefile dlls/scsiport.sys enable_scsiport_sys
+wine_fn_config_makefile dlls/sechost enable_sechost
wine_fn_config_makefile dlls/secur32 enable_secur32
wine_fn_config_makefile dlls/secur32/tests enable_tests
wine_fn_config_makefile dlls/security enable_security
diff --git a/configure.ac b/configure.ac
index 00b3f38d4aa..ce2c94eca29 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3641,6 +3641,7 @@ WINE_CONFIG_MAKEFILE(dlls/scrobj/tests)
WINE_CONFIG_MAKEFILE(dlls/scrrun)
WINE_CONFIG_MAKEFILE(dlls/scrrun/tests)
WINE_CONFIG_MAKEFILE(dlls/scsiport.sys)
+WINE_CONFIG_MAKEFILE(dlls/sechost)
WINE_CONFIG_MAKEFILE(dlls/secur32)
WINE_CONFIG_MAKEFILE(dlls/secur32/tests)
WINE_CONFIG_MAKEFILE(dlls/security)
diff --git a/dlls/sechost/Makefile.in b/dlls/sechost/Makefile.in
new file mode 100644
index 00000000000..d326188ad3e
--- /dev/null
+++ b/dlls/sechost/Makefile.in
@@ -0,0 +1,3 @@
+MODULE = sechost.dll
+
+EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/sechost/sechost.spec b/dlls/sechost/sechost.spec
new file mode 100644
index 00000000000..a72f79cd8a0
--- /dev/null
+++ b/dlls/sechost/sechost.spec
@@ -0,0 +1,208 @@
+@ stub I_ScSetServiceBitsA
+@ stub I_ScSetServiceBitsW
+@ stub AuditComputeEffectivePolicyBySid
+@ stub AuditEnumerateCategories
+@ stub AuditEnumeratePerUserPolicy
+@ stub AuditEnumerateSubCategories
+@ stub AuditFree
+@ stub AuditLookupCategoryNameW
+@ stub AuditLookupSubCategoryNameW
+@ stub AuditQueryGlobalSaclW
+@ stub AuditQueryPerUserPolicy
+@ stub AuditQuerySecurity
+@ stdcall AuditQuerySystemPolicy(ptr long ptr) advapi32.AuditQuerySystemPolicy
+@ stub AuditSetGlobalSaclW
+@ stub AuditSetPerUserPolicy
+@ stub AuditSetSecurity
+@ stub AuditSetSystemPolicy
+@ stub BuildSecurityDescriptorForSharingAccess
+@ stub BuildSecurityDescriptorForSharingAccessEx
+@ stub CapabilityCheck
+@ stub CapabilityCheckForSingleSessionSku
+@ stdcall ChangeServiceConfig2A(long long ptr) advapi32.ChangeServiceConfig2A
+@ stdcall ChangeServiceConfig2W(long long ptr) advapi32.ChangeServiceConfig2W
+@ stdcall ChangeServiceConfigA(long long long long wstr str ptr str str str str) advapi32.ChangeServiceConfigA
+@ stdcall ChangeServiceConfigW(long long long long wstr wstr ptr wstr wstr wstr wstr) advapi32.ChangeServiceConfigW
+@ stdcall CloseServiceHandle(long) advapi32.CloseServiceHandle
+@ stdcall CloseTrace(int64) advapi32.CloseTrace
+@ stdcall ControlService(long long ptr) advapi32.ControlService
+@ stub ControlServiceExA
+@ stub ControlServiceExW
+@ stdcall ControlTraceA(int64 str ptr long) advapi32.ControlTraceA
+@ stdcall ControlTraceW(int64 wstr ptr long) advapi32.ControlTraceW
+@ stub ConvertSDToStringSDRootDomainW
+@ stdcall ConvertSecurityDescriptorToStringSecurityDescriptorW(ptr long long ptr ptr) advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW
+@ stdcall ConvertSidToStringSidW(ptr ptr) advapi32.ConvertSidToStringSidW
+@ stub ConvertStringSDToSDDomainA
+@ stub ConvertStringSDToSDDomainW
+@ stub ConvertStringSDToSDRootDomainW
+@ stdcall ConvertStringSecurityDescriptorToSecurityDescriptorW(wstr long ptr ptr) advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW
+@ stdcall ConvertStringSidToSidW(ptr ptr) advapi32.ConvertStringSidToSidW
+@ stdcall CreateServiceA(long str str long long long long str str ptr str str str) advapi32.CreateServiceA
+@ stub CreateServiceEx
+@ stdcall CreateServiceW(long wstr wstr long long long long wstr wstr ptr wstr wstr wstr) advapi32.CreateServiceW
+@ stub CredBackupCredentials
+@ stdcall CredDeleteA(str long long) advapi32.CredDeleteA
+@ stdcall CredDeleteW(wstr long long) advapi32.CredDeleteW
+@ stub CredEncryptAndMarshalBinaryBlob
+@ stdcall CredEnumerateA(str long ptr ptr) advapi32.CredEnumerateA
+@ stdcall CredEnumerateW(wstr long ptr ptr) advapi32.CredEnumerateW
+@ stub CredFindBestCredentialA
+@ stub CredFindBestCredentialW
+@ stdcall CredFree(ptr) advapi32.CredFree
+@ stdcall CredGetSessionTypes(long ptr) advapi32.CredGetSessionTypes
+@ stub CredGetTargetInfoA
+@ stub CredGetTargetInfoW
+@ stdcall CredIsMarshaledCredentialW(wstr) advapi32.CredIsMarshaledCredentialW
+@ stub CredIsProtectedA
+@ stub CredIsProtectedW
+@ stdcall CredMarshalCredentialA(long ptr ptr) advapi32.CredMarshalCredentialA
+@ stdcall CredMarshalCredentialW(long ptr ptr) advapi32.CredMarshalCredentialW
+@ stub CredParseUserNameWithType
+@ stub CredProfileLoaded
+@ stub CredProfileLoadedEx
+@ stub CredProfileUnloaded
+@ stub CredProtectA
+@ stub CredProtectW
+@ stdcall CredReadA(str long long ptr) advapi32.CredReadA
+@ stub CredReadByTokenHandle
+@ stdcall CredReadDomainCredentialsA(ptr long ptr ptr) advapi32.CredReadDomainCredentialsA
+@ stdcall CredReadDomainCredentialsW(ptr long ptr ptr) advapi32.CredReadDomainCredentialsW
+@ stdcall CredReadW(wstr long long ptr) advapi32.CredReadW
+@ stub CredRestoreCredentials
+@ stdcall CredUnmarshalCredentialA(str ptr ptr) advapi32.CredUnmarshalCredentialA
+@ stdcall CredUnmarshalCredentialW(wstr ptr ptr) advapi32.CredUnmarshalCredentialW
+@ stub CredUnprotectA
+@ stub CredUnprotectW
+@ stdcall CredWriteA(ptr long) advapi32.CredWriteA
+@ stub CredWriteDomainCredentialsA
+@ stub CredWriteDomainCredentialsW
+@ stdcall CredWriteW(ptr long) advapi32.CredWriteW
+@ stub CredpConvertCredential
+@ stub CredpConvertOneCredentialSize
+@ stub CredpConvertTargetInfo
+@ stub CredpDecodeCredential
+@ stub CredpEncodeCredential
+@ stub CredpEncodeSecret
+@ stdcall DeleteService(long) advapi32.DeleteService
+@ stdcall EnableTraceEx2(int64 ptr long long int64 int64 long ptr) advapi32.EnableTraceEx2
+@ stdcall EnumDependentServicesW(long long ptr long ptr ptr) advapi32.EnumDependentServicesW
+@ stdcall EnumServicesStatusExW(long long long long ptr long ptr ptr ptr wstr) advapi32.EnumServicesStatusExW
+@ stub EnumerateIdentityProviders
+@ stub EnumerateTraceGuidsEx
+@ stub EtwQueryRealtimeConsumer
+@ stub EventAccessControl
+@ stub EventAccessQuery
+@ stub EventAccessRemove
+@ stub FreeTransientObjectSecurityDescriptor
+@ stub GetDefaultIdentityProvider
+@ stub GetIdentityProviderInfoByGUID
+@ stub GetIdentityProviderInfoByName
+@ stub GetServiceDirectory
+@ stdcall GetServiceDisplayNameW(ptr wstr ptr ptr) advapi32.GetServiceDisplayNameW
+@ stdcall GetServiceKeyNameW(long wstr ptr ptr) advapi32.GetServiceKeyNameW
+@ stub GetServiceRegistryStateKey
+@ stub I_QueryTagInformation
+@ stub I_RegisterSvchostNotificationCallback
+@ stub I_ScBroadcastServiceControlMessage
+@ stub I_ScIsSecurityProcess
+@ stub I_ScPnPGetServiceName
+@ stub I_ScQueryServiceConfig
+@ stub I_ScRegisterDeviceNotification
+@ stub I_ScRegisterPreshutdownRestart
+@ stub I_ScReparseServiceDatabase
+@ stub I_ScRpcBindA
+@ stub I_ScRpcBindW
+@ stub I_ScSendPnPMessage
+@ stub I_ScSendTSMessage
+@ stub I_ScUnregisterDeviceNotification
+@ stub I_ScValidatePnPService
+@ stub LocalGetConditionForString
+@ stub LocalGetReferencedTokenTypesForCondition
+@ stub LocalGetStringForCondition
+@ stub LocalRpcBindingCreateWithSecurity
+@ stub LocalRpcBindingSetAuthInfoEx
+@ stub LookupAccountNameLocalA
+@ stub LookupAccountNameLocalW
+@ stdcall LookupAccountSidLocalA(ptr ptr ptr ptr ptr ptr) advapi32.LookupAccountSidLocalA
+@ stdcall LookupAccountSidLocalW(ptr ptr ptr ptr ptr ptr) advapi32.LookupAccountSidLocalW
+@ stdcall LsaAddAccountRights(ptr ptr ptr long) advapi32.LsaAddAccountRights
+@ stdcall LsaClose(ptr) advapi32.LsaClose
+@ stub LsaCreateSecret
+@ stub LsaDelete
+@ stdcall LsaEnumerateAccountRights(ptr ptr ptr ptr) advapi32.LsaEnumerateAccountRights
+@ stdcall LsaEnumerateAccountsWithUserRight(ptr ptr ptr ptr) advapi32.LsaEnumerateAccountsWithUserRight
+@ stdcall LsaFreeMemory(ptr) advapi32.LsaFreeMemory
+@ stub LsaICLookupNames
+@ stub LsaICLookupNamesWithCreds
+@ stub LsaICLookupSids
+@ stub LsaICLookupSidsWithCreds
+@ stub LsaLookupClose
+@ stub LsaLookupFreeMemory
+@ stub LsaLookupGetDomainInfo
+@ stub LsaLookupManageSidNameMapping
+@ stdcall LsaLookupNames2(ptr long long ptr ptr ptr) advapi32.LsaLookupNames2
+@ stub LsaLookupOpenLocalPolicy
+@ stdcall LsaLookupSids(ptr long ptr ptr ptr) advapi32.LsaLookupSids
+@ stub LsaLookupSids2
+@ stub LsaLookupTranslateNames
+@ stub LsaLookupTranslateSids
+@ stub LsaLookupUserAccountType
+@ stdcall LsaOpenPolicy(long ptr long long) advapi32.LsaOpenPolicy
+@ stub LsaOpenSecret
+@ stdcall LsaQueryInformationPolicy(ptr long ptr) advapi32.LsaQueryInformationPolicy
+@ stub LsaQuerySecret
+@ stdcall LsaRemoveAccountRights(ptr ptr long ptr long) advapi32.LsaRemoveAccountRights
+@ stdcall LsaRetrievePrivateData(ptr ptr ptr) advapi32.LsaRetrievePrivateData
+@ stdcall LsaSetInformationPolicy(long long ptr) advapi32.LsaSetInformationPolicy
+@ stdcall LsaSetSecret(ptr ptr ptr) advapi32.LsaSetSecret
+@ stdcall LsaStorePrivateData(ptr ptr ptr) advapi32.LsaStorePrivateData
+@ stub NotifyServiceStatusChange
+@ stub NotifyServiceStatusChangeA
+@ stdcall NotifyServiceStatusChangeW(ptr long ptr) advapi32.NotifyServiceStatusChangeW
+@ stdcall OpenSCManagerA(str str long) advapi32.OpenSCManagerA
+@ stdcall OpenSCManagerW(wstr wstr long) advapi32.OpenSCManagerW
+@ stdcall OpenServiceA(long str long) advapi32.OpenServiceA
+@ stdcall OpenServiceW(long wstr long) advapi32.OpenServiceW
+@ stdcall -ret64 OpenTraceW(ptr) advapi32.OpenTraceW
+@ stdcall ProcessTrace(ptr long ptr ptr) advapi32.ProcessTrace
+@ stdcall QueryAllTracesA(ptr long ptr) advapi32.QueryAllTracesA
+@ stdcall QueryAllTracesW(ptr long ptr) advapi32.QueryAllTracesW
+@ stub QueryLocalUserServiceName
+@ stdcall QueryServiceConfig2A(long long ptr long ptr) advapi32.QueryServiceConfig2A
+@ stdcall QueryServiceConfig2W(long long ptr long ptr) advapi32.QueryServiceConfig2W
+@ stdcall QueryServiceConfigA(long ptr long ptr) advapi32.QueryServiceConfigA
+@ stdcall QueryServiceConfigW(long ptr long ptr) advapi32.QueryServiceConfigW
+@ stub QueryServiceDynamicInformation
+@ stdcall QueryServiceObjectSecurity(long long ptr long ptr) advapi32.QueryServiceObjectSecurity
+@ stdcall QueryServiceStatus(long ptr) advapi32.QueryServiceStatus
+@ stdcall QueryServiceStatusEx(long long ptr long ptr) advapi32.QueryServiceStatusEx
+@ stub QueryTraceProcessingHandle
+@ stub QueryTransientObjectSecurityDescriptor
+@ stub QueryUserServiceName
+@ stub QueryUserServiceNameForContext
+@ stdcall RegisterServiceCtrlHandlerA(str ptr) advapi32.RegisterServiceCtrlHandlerA
+@ stdcall RegisterServiceCtrlHandlerExA(str ptr ptr) advapi32.RegisterServiceCtrlHandlerExA
+@ stdcall RegisterServiceCtrlHandlerExW(wstr ptr ptr) advapi32.RegisterServiceCtrlHandlerExW
+@ stdcall RegisterServiceCtrlHandlerW(wstr ptr) advapi32.RegisterServiceCtrlHandlerW
+@ stdcall RegisterTraceGuidsA(ptr ptr ptr long ptr str str ptr) advapi32.RegisterTraceGuidsA
+@ stub ReleaseIdentityProviderEnumContext
+@ stub RemoveTraceCallback
+@ stub RpcClientCapabilityCheck
+@ stub SetLocalRpcServerInterfaceSecurity
+@ stub SetLocalRpcServerProtseqSecurity
+@ stdcall SetServiceObjectSecurity(long long ptr) advapi32.SetServiceObjectSecurity
+@ stdcall SetServiceStatus(long ptr) advapi32.SetServiceStatus
+@ stub SetTraceCallback
+@ stdcall StartServiceA(long long ptr) advapi32.StartServiceA
+@ stdcall StartServiceCtrlDispatcherA(ptr) advapi32.StartServiceCtrlDispatcherA
+@ stdcall StartServiceCtrlDispatcherW(ptr) advapi32.StartServiceCtrlDispatcherW
+@ stdcall StartServiceW(long long ptr) advapi32.StartServiceW
+@ stdcall StartTraceA(ptr str ptr) advapi32.StartTraceA
+@ stdcall StartTraceW(ptr wstr ptr) advapi32.StartTraceW
+@ stdcall StopTraceW(int64 wstr ptr) advapi32.StopTraceW
+@ stub SubscribeServiceChangeNotifications
+@ stub TraceQueryInformation
+@ stdcall TraceSetInformation(int64 long ptr long) advapi32.TraceSetInformation
+@ stub UnsubscribeServiceChangeNotifications
+@ stub WaitServiceState
diff --git a/tools/make_specfiles b/tools/make_specfiles
index 95b210752ca..6ce990c107f 100755
--- a/tools/make_specfiles
+++ b/tools/make_specfiles
@@ -148,6 +148,7 @@ my @dll_groups =
"api-ms-win-service-private-l1-1-1",
"api-ms-win-service-winsvc-l1-1-0",
"api-ms-win-service-winsvc-l1-2-0",
+ "sechost",
],
[
"authz",
--
2.26.0
1
1
1
1
[PATCH] wineusb.sys: Avoid touching the IRP structure after queueing it.
by Zebediah Figura 25 Apr '20
by Zebediah Figura 25 Apr '20
25 Apr '20
Spotted by Thomas Faber.
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/wineusb.sys/wineusb.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/dlls/wineusb.sys/wineusb.c b/dlls/wineusb.sys/wineusb.c
index d79112b479..3e6a959a78 100644
--- a/dlls/wineusb.sys/wineusb.c
+++ b/dlls/wineusb.sys/wineusb.c
@@ -498,8 +498,9 @@ static void transfer_cb(struct libusb_transfer *transfer)
static void queue_irp(struct usb_device *device, IRP *irp, struct libusb_transfer *transfer)
{
- EnterCriticalSection(&wineusb_cs);
+ IoMarkIrpPending(irp);
irp->Tail.Overlay.DriverContext[0] = transfer;
+ EnterCriticalSection(&wineusb_cs);
InsertTailList(&device->irp_list, &irp->Tail.Overlay.ListEntry);
LeaveCriticalSection(&wineusb_cs);
}
@@ -729,11 +730,7 @@ static NTSTATUS WINAPI driver_internal_ioctl(DEVICE_OBJECT *device_obj, IRP *irp
code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3);
}
- if (status == STATUS_PENDING)
- {
- IoMarkIrpPending(irp);
- }
- else
+ if (status != STATUS_PENDING)
{
irp->IoStatus.Status = status;
IoCompleteRequest(irp, IO_NO_INCREMENT);
--
2.26.2
1
0
Binary packages for various distributions will be available from:
https://www.winehq.org/download
Summary since last release
* Rebased to current wine 5.7 (844 patches are applied to wine vanilla)
Upstreamed (Either directly from staging or fixed with a similar patch).
* secur32: Add schan_imp_get_application_protocol for macos.
* ntdll: Cache LDR_IMAGE_IS_DLL for InitDLL.
* ntdll: Handle unaligned condition variables when using futexes.
* ntdll: Handle unaligned SRW locks when using keyed events.
* ntdll: Handle unaligned SRW locks when using futexes.
* opengl32: Treat invalid pixel types as PFD_TYPE_RGBA in
wglChoosePixelFormat.
* windowscodecs: Add support for 16bppGray and 32bppGrayFloat formats to
TIFF decoder.
* windowscodecs: Add support for 3bps RGB format to TIFF decoder.
* windowscodecs: Add support for 12bpp RGB format to TIFF decoder.
* windowscodecs: Add support for 128bppRGBAFloat format to TIFF decoder.
* windowscodecs: Add support for 32bppCMYK and 64bppCMYK formats to TIFF
decoder.
* windowscodecs: Add support for 4bpp RGBA format to TIFF decoder.
* windowscodecs: Add support for 16bpp RGBA format to TIFF decoder.
* windowscodecs: Add some tests for various TIFF color formats.
* include: Update LDR_MODULE to more recent windows versions.
Added:
* [49012] Application build with .NET CoreRT crashes due to FLS
callbacks not being called
Updated:
* ntdll-Syscall_Emulation
* user32-rawinput-mouse
Where can you help
* Run Steam/Battle.net/GOG/UPlay/Epic
* Test your favorite game.
* Test your favorite applications.
* Improve staging patches and get them accepted upstream.
As always, if you find a bug, please report it via
https://bugs.winehq.org
Best Regards
Alistair.
1
0
25 Apr '20
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
v3: Add some NtOpenProcess / NtOpenThread tests. This only tries to open
processes using the current process ptid with low bits sets, as it
seems to be enough to give us the check we need.
On Windows XP Pro, it returns STATUS_ACCESS_DENIED but on all other
Windows versions it works and the low ptid bits are ignored.
dlls/ntdll/tests/info.c | 57 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c
index 8dc8bad645f6..a899353f8f9c 100644
--- a/dlls/ntdll/tests/info.c
+++ b/dlls/ntdll/tests/info.c
@@ -319,6 +319,11 @@ static void test_query_process(void)
int i = 0, k = 0;
BOOL is_nt = FALSE;
SYSTEM_BASIC_INFORMATION sbi;
+ PROCESS_BASIC_INFORMATION pbi;
+ THREAD_BASIC_INFORMATION tbi;
+ OBJECT_ATTRIBUTES attr;
+ CLIENT_ID cid;
+ HANDLE handle;
/* Copy of our winternl.h structure turned into a private one */
typedef struct _SYSTEM_PROCESS_INFORMATION_PRIVATE {
@@ -401,13 +406,21 @@ static void test_query_process(void)
if (!is_nt)
{
+ DWORD_PTR tid;
DWORD j;
+
+ todo_wine_if(last_pid & 3)
+ 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;
+ todo_wine_if(tid & 3)
+ ok(!(tid & 3), "Unexpected TID low bits: %p\n", spi->ti[j].ClientId.UniqueThread);
}
}
@@ -423,6 +436,50 @@ static void test_query_process(void)
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 );
+ cid.UniqueProcess = ULongToHandle(GetCurrentProcessId() + i);
+ cid.UniqueThread = 0;
+
+ status = NtOpenProcess( &handle, PROCESS_QUERY_LIMITED_INFORMATION, &attr, &cid );
+ todo_wine_if( status != STATUS_SUCCESS )
+ ok( status == STATUS_SUCCESS, "NtOpenProcess returned:%x\n", status );
+ if (status != STATUS_SUCCESS) continue;
+
+ status = pNtQueryInformationProcess( handle, ProcessBasicInformation, &pbi, sizeof(pbi), NULL );
+ ok( status == STATUS_SUCCESS, "NtQueryInformationProcess returned:%x\n", status );
+ ok( pbi.UniqueProcessId == GetCurrentProcessId(),
+ "Expected pid %p, got %p\n", ULongToHandle(GetCurrentProcessId()), ULongToHandle(pbi.UniqueProcessId) );
+
+ NtClose( handle );
+ }
+
+ for (i = 1; i < 4; ++i)
+ {
+ InitializeObjectAttributes( &attr, NULL, 0, NULL, NULL );
+ cid.UniqueProcess = 0;
+ cid.UniqueThread = ULongToHandle(GetCurrentThreadId() + i);
+
+ status = NtOpenThread( &handle, THREAD_QUERY_LIMITED_INFORMATION, &attr, &cid );
+ todo_wine_if( status != STATUS_SUCCESS )
+ ok( status == STATUS_SUCCESS, "NtOpenThread returned:%x\n", status );
+ if (status != STATUS_SUCCESS) continue;
+
+ status = pNtQueryInformationThread( handle, ThreadBasicInformation, &tbi, sizeof(tbi), NULL );
+ ok( status == STATUS_SUCCESS, "NtQueryInformationThread returned:%x\n", status );
+ ok( tbi.ClientId.UniqueThread == ULongToHandle(GetCurrentThreadId()),
+ "Expected tid %p, got %p\n", ULongToHandle(GetCurrentThreadId()), tbi.ClientId.UniqueThread );
+
+ NtClose( handle );
+ }
}
static void test_query_procperf(void)
--
2.26.1
2
3
[PATCH 1/6] wineusb.sys: Implement URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE.
by Zebediah Figura 25 Apr '20
by Zebediah Figura 25 Apr '20
25 Apr '20
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/wineusb.sys/wineusb.c | 147 +++++++++++++++++++++++++++++++++++++
1 file changed, 147 insertions(+)
diff --git a/dlls/wineusb.sys/wineusb.c b/dlls/wineusb.sys/wineusb.c
index eb1b7a261f..ed82bd3a13 100644
--- a/dlls/wineusb.sys/wineusb.c
+++ b/dlls/wineusb.sys/wineusb.c
@@ -74,6 +74,8 @@ struct usb_device
libusb_device *libusb_device;
libusb_device_handle *handle;
+
+ LIST_ENTRY irp_list;
};
static DRIVER_OBJECT *driver_obj;
@@ -120,6 +122,7 @@ static void add_usb_device(libusb_device *libusb_device)
device->device_obj = device_obj;
device->libusb_device = libusb_ref_device(libusb_device);
device->handle = handle;
+ InitializeListHead(&device->irp_list);
EnterCriticalSection(&wineusb_cs);
list_add_tail(&device_list, &device->entry);
@@ -394,6 +397,149 @@ static NTSTATUS WINAPI driver_pnp(DEVICE_OBJECT *device, IRP *irp)
return pdo_pnp(device, irp);
}
+static NTSTATUS usbd_status_from_libusb(enum libusb_transfer_status status)
+{
+ switch (status)
+ {
+ case LIBUSB_TRANSFER_CANCELLED:
+ return USBD_STATUS_CANCELED;
+ case LIBUSB_TRANSFER_COMPLETED:
+ return USBD_STATUS_SUCCESS;
+ case LIBUSB_TRANSFER_NO_DEVICE:
+ return USBD_STATUS_DEVICE_GONE;
+ case LIBUSB_TRANSFER_STALL:
+ return USBD_STATUS_ENDPOINT_HALTED;
+ case LIBUSB_TRANSFER_TIMED_OUT:
+ return USBD_STATUS_TIMEOUT;
+ default:
+ FIXME("Unhandled status %#x.\n", status);
+ case LIBUSB_TRANSFER_ERROR:
+ return USBD_STATUS_REQUEST_FAILED;
+ }
+}
+
+static void transfer_cb(struct libusb_transfer *transfer)
+{
+ IRP *irp = transfer->user_data;
+ URB *urb = IoGetCurrentIrpStackLocation(irp)->Parameters.Others.Argument1;
+
+ TRACE("Completing IRP %p, status %#x.\n", irp, transfer->status);
+
+ urb->UrbHeader.Status = usbd_status_from_libusb(transfer->status);
+
+ if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
+ {
+ switch (urb->UrbHeader.Function)
+ {
+ case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
+ {
+ struct _URB_CONTROL_DESCRIPTOR_REQUEST *req = &urb->UrbControlDescriptorRequest;
+ req->TransferBufferLength = transfer->actual_length;
+ memcpy(req->TransferBuffer, libusb_control_transfer_get_data(transfer), transfer->actual_length);
+ break;
+ }
+
+ default:
+ ERR("Unexpected function %#x.\n", urb->UrbHeader.Function);
+ }
+ }
+
+ EnterCriticalSection(&wineusb_cs);
+ RemoveEntryList(&irp->Tail.Overlay.ListEntry);
+ LeaveCriticalSection(&wineusb_cs);
+
+ irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest(irp, IO_NO_INCREMENT);
+}
+
+static void queue_irp(struct usb_device *device, IRP *irp, struct libusb_transfer *transfer)
+{
+ EnterCriticalSection(&wineusb_cs);
+ irp->Tail.Overlay.DriverContext[0] = transfer;
+ InsertTailList(&device->irp_list, &irp->Tail.Overlay.ListEntry);
+ LeaveCriticalSection(&wineusb_cs);
+}
+
+static NTSTATUS usb_submit_urb(struct usb_device *device, IRP *irp)
+{
+ URB *urb = IoGetCurrentIrpStackLocation(irp)->Parameters.Others.Argument1;
+ struct libusb_transfer *transfer;
+ int ret;
+
+ TRACE("type %#x.\n", urb->UrbHeader.Function);
+
+ switch (urb->UrbHeader.Function)
+ {
+ case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
+ {
+ struct _URB_CONTROL_DESCRIPTOR_REQUEST *req = &urb->UrbControlDescriptorRequest;
+ unsigned char *buffer;
+
+ if (req->TransferBufferMDL)
+ FIXME("Unhandled MDL output buffer.\n");
+
+ if (!(transfer = libusb_alloc_transfer(0)))
+ return STATUS_NO_MEMORY;
+
+ if (!(buffer = malloc(sizeof(struct libusb_control_setup) + req->TransferBufferLength)))
+ {
+ libusb_free_transfer(transfer);
+ return STATUS_NO_MEMORY;
+ }
+
+ queue_irp(device, irp, transfer);
+ libusb_fill_control_setup(buffer,
+ LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE,
+ LIBUSB_REQUEST_GET_DESCRIPTOR, (req->DescriptorType << 8) | req->Index,
+ req->LanguageId, req->TransferBufferLength);
+ libusb_fill_control_transfer(transfer, device->handle, buffer, transfer_cb, irp, 0);
+ transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER;
+ ret = libusb_submit_transfer(transfer);
+ if (ret < 0)
+ ERR("Failed to submit GET_DESRIPTOR transfer: %s\n", libusb_strerror(ret));
+
+ return STATUS_PENDING;
+ }
+
+ default:
+ FIXME("Unhandled function %#x.\n", urb->UrbHeader.Function);
+ }
+
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS WINAPI driver_internal_ioctl(DEVICE_OBJECT *device_obj, IRP *irp)
+{
+ IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp);
+ ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
+ struct usb_device *device = device_obj->DeviceExtension;
+ NTSTATUS status = STATUS_NOT_IMPLEMENTED;
+
+ TRACE("device_obj %p, irp %p, code %#x.\n", device_obj, irp, code);
+
+ switch (code)
+ {
+ case IOCTL_INTERNAL_USB_SUBMIT_URB:
+ status = usb_submit_urb(device, irp);
+ break;
+
+ default:
+ FIXME("Unhandled ioctl %#x (device %#x, access %#x, function %#x, method %#x).\n",
+ code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3);
+ }
+
+ if (status == STATUS_PENDING)
+ {
+ IoMarkIrpPending(irp);
+ }
+ else
+ {
+ irp->IoStatus.Status = status;
+ IoCompleteRequest(irp, IO_NO_INCREMENT);
+ }
+ return status;
+}
+
static NTSTATUS WINAPI driver_add_device(DRIVER_OBJECT *driver, DEVICE_OBJECT *pdo)
{
NTSTATUS ret;
@@ -437,6 +583,7 @@ NTSTATUS WINAPI DriverEntry(DRIVER_OBJECT *driver, UNICODE_STRING *path)
driver->DriverExtension->AddDevice = driver_add_device;
driver->DriverUnload = driver_unload;
driver->MajorFunction[IRP_MJ_PNP] = driver_pnp;
+ driver->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = driver_internal_ioctl;
return STATUS_SUCCESS;
}
--
2.26.0
2
6
[PATCH 1/3] windowscodecs: Add initial implementation of the GIF encoder.
by Dmitry Timoshkov 25 Apr '20
by Dmitry Timoshkov 25 Apr '20
25 Apr '20
It would be a major pain to try split this into a series, and that would
gain nothing but a waste of time on both sides.
Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru>
---
dlls/gdiplus/tests/image.c | 14 +-
dlls/windowscodecs/clsfactory.c | 1 +
dlls/windowscodecs/gifformat.c | 1012 ++++++++++++++++-
dlls/windowscodecs/regsvr.c | 10 +
dlls/windowscodecs/wincodecs_private.h | 1 +
dlls/windowscodecs/windowscodecs_wincodec.idl | 7 +
6 files changed, 1003 insertions(+), 42 deletions(-)
diff --git a/dlls/gdiplus/tests/image.c b/dlls/gdiplus/tests/image.c
index 145eadbfd3..956e55302a 100644
--- a/dlls/gdiplus/tests/image.c
+++ b/dlls/gdiplus/tests/image.c
@@ -5115,14 +5115,13 @@ static void test_supported_encoders(void)
{
LPCWSTR mime;
const GUID *format;
- BOOL todo;
} td[] =
{
- { bmp_mimetype, &ImageFormatBMP, FALSE },
- { jpeg_mimetype, &ImageFormatJPEG, FALSE },
- { gif_mimetype, &ImageFormatGIF, TRUE },
- { tiff_mimetype, &ImageFormatTIFF, FALSE },
- { png_mimetype, &ImageFormatPNG, FALSE }
+ { bmp_mimetype, &ImageFormatBMP },
+ { jpeg_mimetype, &ImageFormatJPEG },
+ { gif_mimetype, &ImageFormatGIF },
+ { tiff_mimetype, &ImageFormatTIFF },
+ { png_mimetype, &ImageFormatPNG }
};
GUID format, clsid;
BOOL ret;
@@ -5148,8 +5147,7 @@ static void test_supported_encoders(void)
ok(hr == S_OK, "CreateStreamOnHGlobal error %#x\n", hr);
status = GdipSaveImageToStream((GpImage *)bm, stream, &clsid, NULL);
- todo_wine_if (td[i].todo)
- ok(status == Ok, "GdipSaveImageToStream error %d\n", status);
+ ok(status == Ok, "GdipSaveImageToStream error %d\n", status);
IStream_Release(stream);
}
diff --git a/dlls/windowscodecs/clsfactory.c b/dlls/windowscodecs/clsfactory.c
index d3cd9f34aa..21197993ca 100644
--- a/dlls/windowscodecs/clsfactory.c
+++ b/dlls/windowscodecs/clsfactory.c
@@ -52,6 +52,7 @@ static const classinfo wic_classes[] = {
{&CLSID_WICPngEncoder, PngEncoder_CreateInstance},
{&CLSID_WICBmpEncoder, BmpEncoder_CreateInstance},
{&CLSID_WICGifDecoder, GifDecoder_CreateInstance},
+ {&CLSID_WICGifEncoder, GifEncoder_CreateInstance},
{&CLSID_WICIcoDecoder, IcoDecoder_CreateInstance},
{&CLSID_WICJpegDecoder, JpegDecoder_CreateInstance},
{&CLSID_WICJpegEncoder, JpegEncoder_CreateInstance},
diff --git a/dlls/windowscodecs/gifformat.c b/dlls/windowscodecs/gifformat.c
index df202ba45a..9c212c8eb8 100644
--- a/dlls/windowscodecs/gifformat.c
+++ b/dlls/windowscodecs/gifformat.c
@@ -1,6 +1,6 @@
/*
* Copyright 2009 Vincent Povirk for CodeWeavers
- * Copyright 2012 Dmitry Timoshkov
+ * Copyright 2012,2016 Dmitry Timoshkov
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -36,6 +36,40 @@
WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+#include "pshpack1.h"
+
+struct logical_screen_descriptor
+{
+ char signature[6];
+ USHORT width;
+ USHORT height;
+ BYTE packed;
+ /* global_color_table_flag : 1;
+ * color_resolution : 3;
+ * sort_flag : 1;
+ * global_color_table_size : 3;
+ */
+ BYTE background_color_index;
+ BYTE pixel_aspect_ratio;
+};
+
+struct image_descriptor
+{
+ USHORT left;
+ USHORT top;
+ USHORT width;
+ USHORT height;
+ BYTE packed;
+ /* local_color_table_flag : 1;
+ * interlace_flag : 1;
+ * sort_flag : 1;
+ * reserved : 2;
+ * local_color_table_size : 3;
+ */
+};
+
+#include "poppack.h"
+
static LPWSTR strdupAtoW(const char *src)
{
int len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
@@ -47,22 +81,7 @@ static LPWSTR strdupAtoW(const char *src)
static HRESULT load_LSD_metadata(IStream *stream, const GUID *vendor, DWORD options,
MetadataItem **items, DWORD *count)
{
-#include "pshpack1.h"
- struct logical_screen_descriptor
- {
- char signature[6];
- USHORT width;
- USHORT height;
- BYTE packed;
- /* global_color_table_flag : 1;
- * color_resolution : 3;
- * sort_flag : 1;
- * global_color_table_size : 3;
- */
- BYTE background_color_index;
- BYTE pixel_aspect_ratio;
- } lsd_data;
-#include "poppack.h"
+ struct logical_screen_descriptor lsd_data;
HRESULT hr;
ULONG bytesread, i;
MetadataItem *result;
@@ -147,23 +166,6 @@ HRESULT LSDReader_CreateInstance(REFIID iid, void **ppv)
return MetadataReader_Create(&LSDReader_Vtbl, iid, ppv);
}
-#include "pshpack1.h"
-struct image_descriptor
-{
- USHORT left;
- USHORT top;
- USHORT width;
- USHORT height;
- BYTE packed;
- /* local_color_table_flag : 1;
- * interlace_flag : 1;
- * sort_flag : 1;
- * reserved : 2;
- * local_color_table_size : 3;
- */
-};
-#include "poppack.h"
-
static HRESULT load_IMD_metadata(IStream *stream, const GUID *vendor, DWORD options,
MetadataItem **items, DWORD *count)
{
@@ -1449,3 +1451,945 @@ HRESULT GifDecoder_CreateInstance(REFIID iid, void** ppv)
return ret;
}
+
+typedef struct GifEncoder
+{
+ IWICBitmapEncoder IWICBitmapEncoder_iface;
+ LONG ref;
+ IStream *stream;
+ CRITICAL_SECTION lock;
+ BOOL initialized, info_written, committed;
+ UINT n_frames;
+ WICColor palette[256];
+ UINT colors;
+} GifEncoder;
+
+static inline GifEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
+{
+ return CONTAINING_RECORD(iface, GifEncoder, IWICBitmapEncoder_iface);
+}
+
+typedef struct GifFrameEncode
+{
+ IWICBitmapFrameEncode IWICBitmapFrameEncode_iface;
+ LONG ref;
+ GifEncoder *encoder;
+ BOOL initialized, interlace, committed;
+ UINT width, height, lines;
+ double xres, yres;
+ WICColor palette[256];
+ UINT colors;
+ BYTE *image_data;
+} GifFrameEncode;
+
+static inline GifFrameEncode *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
+{
+ return CONTAINING_RECORD(iface, GifFrameEncode, IWICBitmapFrameEncode_iface);
+}
+
+static HRESULT WINAPI GifFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid, void **ppv)
+{
+ TRACE("%p,%s,%p\n", iface, debugstr_guid(iid), ppv);
+
+ if (!ppv) return E_INVALIDARG;
+
+ if (IsEqualIID(&IID_IUnknown, iid) ||
+ IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
+ {
+ IWICBitmapFrameEncode_AddRef(iface);
+ *ppv = iface;
+ return S_OK;
+ }
+
+ *ppv = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI GifFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
+{
+ GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+ ULONG ref = InterlockedIncrement(&This->ref);
+
+ TRACE("%p -> %u\n", iface, ref);
+ return ref;
+}
+
+static ULONG WINAPI GifFrameEncode_Release(IWICBitmapFrameEncode *iface)
+{
+ GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+ ULONG ref = InterlockedDecrement(&This->ref);
+
+ TRACE("%p -> %u\n", iface, ref);
+
+ if (!ref)
+ {
+ IWICBitmapEncoder_Release(&This->encoder->IWICBitmapEncoder_iface);
+ HeapFree(GetProcessHeap(), 0, This->image_data);
+ HeapFree(GetProcessHeap(), 0, This);
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI GifFrameEncode_Initialize(IWICBitmapFrameEncode *iface, IPropertyBag2 *options)
+{
+ GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+ HRESULT hr;
+
+ TRACE("%p,%p\n", iface, options);
+
+ EnterCriticalSection(&This->encoder->lock);
+
+ if (!This->initialized)
+ {
+ This->initialized = TRUE;
+ hr = S_OK;
+ }
+ else
+ hr = WINCODEC_ERR_WRONGSTATE;
+
+ LeaveCriticalSection(&This->encoder->lock);
+
+ return hr;
+}
+
+static HRESULT WINAPI GifFrameEncode_SetSize(IWICBitmapFrameEncode *iface, UINT width, UINT height)
+{
+ GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+ HRESULT hr;
+
+ TRACE("%p,%u,%u\n", iface, width, height);
+
+ if (!width || !height) return E_INVALIDARG;
+
+ EnterCriticalSection(&This->encoder->lock);
+
+ if (This->initialized)
+ {
+ HeapFree(GetProcessHeap(), 0, This->image_data);
+
+ This->image_data = HeapAlloc(GetProcessHeap(), 0, width * height);
+ if (This->image_data)
+ {
+ This->width = width;
+ This->height = height;
+ hr = S_OK;
+ }
+ else
+ hr = E_OUTOFMEMORY;
+ }
+ else
+ hr = WINCODEC_ERR_WRONGSTATE;
+
+ LeaveCriticalSection(&This->encoder->lock);
+
+ return hr;
+}
+
+static HRESULT WINAPI GifFrameEncode_SetResolution(IWICBitmapFrameEncode *iface, double xres, double yres)
+{
+ GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+ HRESULT hr;
+
+ TRACE("%p,%f,%f\n", iface, xres, yres);
+
+ EnterCriticalSection(&This->encoder->lock);
+
+ if (This->initialized)
+ {
+ This->xres = xres;
+ This->yres = yres;
+ hr = S_OK;
+ }
+ else
+ hr = WINCODEC_ERR_WRONGSTATE;
+
+ LeaveCriticalSection(&This->encoder->lock);
+
+ return hr;
+}
+
+static HRESULT WINAPI GifFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface, WICPixelFormatGUID *format)
+{
+ GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+ HRESULT hr;
+
+ TRACE("%p,%s\n", iface, debugstr_guid(format));
+
+ if (!format) return E_INVALIDARG;
+
+ EnterCriticalSection(&This->encoder->lock);
+
+ if (This->initialized)
+ {
+ *format = GUID_WICPixelFormat8bppIndexed;
+ hr = S_OK;
+ }
+ else
+ hr = WINCODEC_ERR_WRONGSTATE;
+
+ LeaveCriticalSection(&This->encoder->lock);
+
+ return hr;
+}
+
+static HRESULT WINAPI GifFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface, UINT count, IWICColorContext **context)
+{
+ FIXME("%p,%u,%p: stub\n", iface, count, context);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI GifFrameEncode_SetPalette(IWICBitmapFrameEncode *iface, IWICPalette *palette)
+{
+ GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+ HRESULT hr;
+
+ TRACE("%p,%p\n", iface, palette);
+
+ if (!palette) return E_INVALIDARG;
+
+ EnterCriticalSection(&This->encoder->lock);
+
+ if (This->initialized)
+ hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors);
+ else
+ hr = WINCODEC_ERR_NOTINITIALIZED;
+
+ LeaveCriticalSection(&This->encoder->lock);
+ return hr;
+}
+
+static HRESULT WINAPI GifFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface, IWICBitmapSource *thumbnail)
+{
+ FIXME("%p,%p: stub\n", iface, thumbnail);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI GifFrameEncode_WritePixels(IWICBitmapFrameEncode *iface, UINT lines, UINT stride, UINT size, BYTE *pixels)
+{
+ GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+ HRESULT hr;
+
+ TRACE("%p,%u,%u,%u,%p\n", iface, lines, stride, size, pixels);
+
+ if (!pixels) return E_INVALIDARG;
+
+ EnterCriticalSection(&This->encoder->lock);
+
+ if (This->initialized && This->image_data)
+ {
+ if (This->lines + lines <= This->height)
+ {
+ UINT i;
+ BYTE *src, *dst;
+
+ src = pixels;
+ dst = This->image_data + This->lines * This->width;
+
+ for (i = 0; i < lines; i++)
+ {
+ memcpy(dst, src, This->width);
+ src += stride;
+ dst += This->width;
+ }
+
+ This->lines += lines;
+ hr = S_OK;
+ }
+ else
+ hr = E_INVALIDARG;
+ }
+ else
+ hr = WINCODEC_ERR_WRONGSTATE;
+
+ LeaveCriticalSection(&This->encoder->lock);
+ return hr;
+}
+
+static HRESULT WINAPI GifFrameEncode_WriteSource(IWICBitmapFrameEncode *iface, IWICBitmapSource *source, WICRect *rc)
+{
+ GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+ HRESULT hr;
+
+ TRACE("%p,%p,%p\n", iface, source, rc);
+
+ if (!source) return E_INVALIDARG;
+
+ EnterCriticalSection(&This->encoder->lock);
+
+ if (This->initialized)
+ {
+ const GUID *format = &GUID_WICPixelFormat8bppIndexed;
+
+ hr = configure_write_source(iface, source, rc, format,
+ This->width, This->height, This->xres, This->yres);
+ if (hr == S_OK)
+ hr = write_source(iface, source, rc, format, 8, FALSE, This->width, This->height);
+ }
+ else
+ hr = WINCODEC_ERR_WRONGSTATE;
+
+ LeaveCriticalSection(&This->encoder->lock);
+ return hr;
+}
+
+#define LZW_DICT_SIZE (1 << 12)
+
+struct lzw_dict
+{
+ short prefix[LZW_DICT_SIZE];
+ unsigned char suffix[LZW_DICT_SIZE];
+};
+
+struct lzw_state
+{
+ struct lzw_dict dict;
+ short init_code_bits, code_bits, next_code, clear_code, eof_code;
+ unsigned bits_buf;
+ int bits_count;
+ int (*user_write_data)(void *user_ptr, void *data, int length);
+ void *user_ptr;
+};
+
+struct input_stream
+{
+ unsigned len;
+ const BYTE *in;
+};
+
+struct output_stream
+{
+ struct
+ {
+ unsigned char len;
+ char data[255];
+ } gif_block;
+ IStream *out;
+};
+
+static int lzw_output_code(struct lzw_state *state, short code)
+{
+ state->bits_buf |= code << state->bits_count;
+ state->bits_count += state->code_bits;
+
+ while (state->bits_count >= 8)
+ {
+ unsigned char byte = (unsigned char)state->bits_buf;
+ if (state->user_write_data(state->user_ptr, &byte, 1) != 1)
+ return 0;
+ state->bits_buf >>= 8;
+ state->bits_count -= 8;
+ }
+
+ return 1;
+}
+
+static inline int lzw_output_clear_code(struct lzw_state *state)
+{
+ return lzw_output_code(state, state->clear_code);
+}
+
+static inline int lzw_output_eof_code(struct lzw_state *state)
+{
+ return lzw_output_code(state, state->eof_code);
+}
+
+static int lzw_flush_bits(struct lzw_state *state)
+{
+ unsigned char byte;
+
+ while (state->bits_count >= 8)
+ {
+ byte = (unsigned char)state->bits_buf;
+ if (state->user_write_data(state->user_ptr, &byte, 1) != 1)
+ return 0;
+ state->bits_buf >>= 8;
+ state->bits_count -= 8;
+ }
+
+ if (state->bits_count)
+ {
+ static const char mask[8] = { 0x00,0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f };
+
+ byte = (unsigned char)state->bits_buf & mask[state->bits_count];
+ if (state->user_write_data(state->user_ptr, &byte, 1) != 1)
+ return 0;
+ }
+
+ state->bits_buf = 0;
+ state->bits_count = 0;
+
+ return 1;
+}
+
+static void lzw_dict_reset(struct lzw_state *state)
+{
+ int i;
+
+ state->code_bits = state->init_code_bits + 1;
+ state->next_code = (1 << state->init_code_bits) + 2;
+
+ for(i = 0; i < LZW_DICT_SIZE; i++)
+ {
+ state->dict.prefix[i] = 1 << 12; /* impossible LZW code value */
+ state->dict.suffix[i] = 0;
+ }
+}
+
+static void lzw_state_init(struct lzw_state *state, short init_code_bits, void *user_write_data, void *user_ptr)
+{
+ state->init_code_bits = init_code_bits;
+ state->clear_code = 1 << init_code_bits;
+ state->eof_code = state->clear_code + 1;
+ state->bits_buf = 0;
+ state->bits_count = 0;
+ state->user_write_data = user_write_data;
+ state->user_ptr = user_ptr;
+
+ lzw_dict_reset(state);
+}
+
+static int lzw_dict_add(struct lzw_state *state, short prefix, unsigned char suffix)
+{
+ if (state->next_code < LZW_DICT_SIZE)
+ {
+ state->dict.prefix[state->next_code] = prefix;
+ state->dict.suffix[state->next_code] = suffix;
+
+ if ((state->next_code & (state->next_code - 1)) == 0)
+ state->code_bits++;
+
+ state->next_code++;
+ return state->next_code;
+ }
+
+ return -1;
+}
+
+static short lzw_dict_lookup(const struct lzw_state *state, short prefix, unsigned char suffix)
+{
+ short i;
+
+ for (i = 0; i < state->next_code; i++)
+ {
+ if (state->dict.prefix[i] == prefix && state->dict.suffix[i] == suffix)
+ return i;
+ }
+
+ return -1;
+}
+
+static inline int write_byte(struct output_stream *out, char byte)
+{
+ if (out->gif_block.len == 255)
+ {
+ if (IStream_Write(out->out, &out->gif_block, sizeof(out->gif_block), NULL) != S_OK)
+ return 0;
+
+ out->gif_block.len = 0;
+ }
+
+ out->gif_block.data[out->gif_block.len++] = byte;
+
+ return 1;
+}
+
+static int write_data(void *user_ptr, void *user_data, int length)
+{
+ unsigned char *data = user_data;
+ struct output_stream *out = user_ptr;
+ int len = length;
+
+ while (len-- > 0)
+ {
+ if (!write_byte(out, *data++)) return 0;
+ }
+
+ return length;
+}
+
+static int flush_output_data(void *user_ptr)
+{
+ struct output_stream *out = user_ptr;
+
+ if (out->gif_block.len)
+ {
+ if (IStream_Write(out->out, &out->gif_block, out->gif_block.len + sizeof(out->gif_block.len), NULL) != S_OK)
+ return 0;
+ }
+
+ /* write GIF block terminator */
+ out->gif_block.len = 0;
+ return IStream_Write(out->out, &out->gif_block, sizeof(out->gif_block.len), NULL) == S_OK;
+}
+
+static inline int read_byte(struct input_stream *in, unsigned char *byte)
+{
+ if (in->len)
+ {
+ in->len--;
+ *byte = *in->in++;
+ return 1;
+ }
+
+ return 0;
+}
+
+static HRESULT gif_compress(IStream *out_stream, const BYTE *in_data, ULONG in_size)
+{
+ struct input_stream in;
+ struct output_stream out;
+ struct lzw_state state;
+ short init_code_bits, prefix, code;
+ unsigned char suffix;
+
+ in.in = in_data;
+ in.len = in_size;
+
+ out.gif_block.len = 0;
+ out.out = out_stream;
+
+ init_code_bits = suffix = 8;
+ if (IStream_Write(out.out, &suffix, sizeof(suffix), NULL) != S_OK)
+ return E_FAIL;
+
+ lzw_state_init(&state, init_code_bits, write_data, &out);
+
+ if (!lzw_output_clear_code(&state))
+ return E_FAIL;
+
+ if (read_byte(&in, &suffix))
+ {
+ prefix = suffix;
+
+ while (read_byte(&in, &suffix))
+ {
+ code = lzw_dict_lookup(&state, prefix, suffix);
+ if (code == -1)
+ {
+ if (!lzw_output_code(&state, prefix))
+ return E_FAIL;
+
+ if (lzw_dict_add(&state, prefix, suffix) == -1)
+ {
+ if (!lzw_output_clear_code(&state))
+ return E_FAIL;
+ lzw_dict_reset(&state);
+ }
+
+ prefix = suffix;
+ }
+ else
+ prefix = code;
+ }
+
+ if (!lzw_output_code(&state, prefix))
+ return E_FAIL;
+ if (!lzw_output_eof_code(&state))
+ return E_FAIL;
+ if (!lzw_flush_bits(&state))
+ return E_FAIL;
+ }
+
+ return flush_output_data(&out) ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI GifFrameEncode_Commit(IWICBitmapFrameEncode *iface)
+{
+ GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+ HRESULT hr;
+
+ TRACE("%p\n", iface);
+
+ EnterCriticalSection(&This->encoder->lock);
+
+ if (This->image_data && This->lines == This->height && !This->committed)
+ {
+ BYTE gif_palette[256][3];
+
+ hr = S_OK;
+
+ if (!This->encoder->info_written)
+ {
+ struct logical_screen_descriptor lsd;
+
+ /* Logical Screen Descriptor */
+ memcpy(lsd.signature, "GIF89a", 6);
+ lsd.width = This->width;
+ lsd.height = This->height;
+ lsd.packed = 0;
+ if (This->encoder->colors)
+ lsd.packed |= 0x80; /* global color table flag */
+ lsd.packed |= 0x07 << 4; /* color resolution */
+ lsd.packed |= 0x07; /* global color table size */
+ lsd.background_color_index = 0; /* FIXME */
+ lsd.pixel_aspect_ratio = 0;
+ hr = IStream_Write(This->encoder->stream, &lsd, sizeof(lsd), NULL);
+ if (hr == S_OK && This->encoder->colors)
+ {
+ UINT i;
+
+ /* Global Color Table */
+ memset(gif_palette, 0, sizeof(gif_palette));
+ for (i = 0; i < This->encoder->colors; i++)
+ {
+ gif_palette[i][0] = (This->encoder->palette[i] >> 16) & 0xff;
+ gif_palette[i][1] = (This->encoder->palette[i] >> 8) & 0xff;
+ gif_palette[i][2] = This->encoder->palette[i] & 0xff;
+ }
+ hr = IStream_Write(This->encoder->stream, gif_palette, sizeof(gif_palette), NULL);
+ }
+
+ /* FIXME: write GCE, APE, etc. GIF extensions */
+
+ if (hr == S_OK)
+ This->encoder->info_written = TRUE;
+ }
+
+ if (hr == S_OK)
+ {
+ char image_separator = 0x2c;
+
+ hr = IStream_Write(This->encoder->stream, &image_separator, sizeof(image_separator), NULL);
+ if (hr == S_OK)
+ {
+ struct image_descriptor imd;
+
+ /* Image Descriptor */
+ imd.left = 0;
+ imd.top = 0;
+ imd.width = This->width;
+ imd.height = This->height;
+ imd.packed = 0;
+ if (This->colors)
+ {
+ imd.packed |= 0x80; /* local color table flag */
+ imd.packed |= 0x07; /* local color table size */
+ }
+ /* FIXME: interlace flag */
+ hr = IStream_Write(This->encoder->stream, &imd, sizeof(imd), NULL);
+ if (hr == S_OK && This->colors)
+ {
+ UINT i;
+
+ /* Local Color Table */
+ memset(gif_palette, 0, sizeof(gif_palette));
+ for (i = 0; i < This->colors; i++)
+ {
+ gif_palette[i][0] = (This->palette[i] >> 16) & 0xff;
+ gif_palette[i][1] = (This->palette[i] >> 8) & 0xff;
+ gif_palette[i][2] = This->palette[i] & 0xff;
+ }
+ hr = IStream_Write(This->encoder->stream, gif_palette, sizeof(gif_palette), NULL);
+ if (hr == S_OK)
+ {
+ /* Image Data */
+ hr = gif_compress(This->encoder->stream, This->image_data, This->width * This->height);
+ if (hr == S_OK)
+ This->committed = TRUE;
+ }
+ }
+ }
+ }
+ }
+ else
+ hr = WINCODEC_ERR_WRONGSTATE;
+
+ LeaveCriticalSection(&This->encoder->lock);
+ return hr;
+}
+
+static HRESULT WINAPI GifFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface, IWICMetadataQueryWriter **writer)
+{
+ FIXME("%p, %p: stub\n", iface, writer);
+ return E_NOTIMPL;
+}
+
+static const IWICBitmapFrameEncodeVtbl GifFrameEncode_Vtbl =
+{
+ GifFrameEncode_QueryInterface,
+ GifFrameEncode_AddRef,
+ GifFrameEncode_Release,
+ GifFrameEncode_Initialize,
+ GifFrameEncode_SetSize,
+ GifFrameEncode_SetResolution,
+ GifFrameEncode_SetPixelFormat,
+ GifFrameEncode_SetColorContexts,
+ GifFrameEncode_SetPalette,
+ GifFrameEncode_SetThumbnail,
+ GifFrameEncode_WritePixels,
+ GifFrameEncode_WriteSource,
+ GifFrameEncode_Commit,
+ GifFrameEncode_GetMetadataQueryWriter
+};
+
+static HRESULT WINAPI GifEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid, void **ppv)
+{
+ TRACE("%p,%s,%p\n", iface, debugstr_guid(iid), ppv);
+
+ if (!ppv) return E_INVALIDARG;
+
+ if (IsEqualIID(&IID_IUnknown, iid) ||
+ IsEqualIID(&IID_IWICBitmapEncoder, iid))
+ {
+ IWICBitmapEncoder_AddRef(iface);
+ *ppv = iface;
+ return S_OK;
+ }
+
+ *ppv = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI GifEncoder_AddRef(IWICBitmapEncoder *iface)
+{
+ GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
+ ULONG ref = InterlockedIncrement(&This->ref);
+
+ TRACE("%p -> %u\n", iface, ref);
+ return ref;
+}
+
+static ULONG WINAPI GifEncoder_Release(IWICBitmapEncoder *iface)
+{
+ GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
+ ULONG ref = InterlockedDecrement(&This->ref);
+
+ TRACE("%p -> %u\n", iface, ref);
+
+ if (!ref)
+ {
+ if (This->stream) IStream_Release(This->stream);
+ This->lock.DebugInfo->Spare[0] = 0;
+ DeleteCriticalSection(&This->lock);
+ HeapFree(GetProcessHeap(), 0, This);
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI GifEncoder_Initialize(IWICBitmapEncoder *iface, IStream *stream, WICBitmapEncoderCacheOption option)
+{
+ GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
+ HRESULT hr;
+
+ TRACE("%p,%p,%#x\n", iface, stream, option);
+
+ if (!stream) return E_INVALIDARG;
+
+ EnterCriticalSection(&This->lock);
+
+ if (!This->initialized)
+ {
+ IStream_AddRef(stream);
+ This->stream = stream;
+ This->initialized = TRUE;
+ hr = S_OK;
+ }
+ else
+ hr = WINCODEC_ERR_WRONGSTATE;
+
+ LeaveCriticalSection(&This->lock);
+
+ return hr;
+}
+
+static HRESULT WINAPI GifEncoder_GetContainerFormat(IWICBitmapEncoder *iface, GUID *format)
+{
+ if (!format) return E_INVALIDARG;
+
+ *format = GUID_ContainerFormatGif;
+ return S_OK;
+}
+
+static HRESULT WINAPI GifEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info)
+{
+ IWICComponentInfo *comp_info;
+ HRESULT hr;
+
+ TRACE("%p,%p\n", iface, info);
+
+ if (!info) return E_INVALIDARG;
+
+ hr = CreateComponentInfo(&CLSID_WICGifEncoder, &comp_info);
+ if (hr == S_OK)
+ {
+ hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info);
+ IWICComponentInfo_Release(comp_info);
+ }
+ return hr;
+}
+
+static HRESULT WINAPI GifEncoder_SetColorContexts(IWICBitmapEncoder *iface, UINT count, IWICColorContext **context)
+{
+ FIXME("%p,%u,%p: stub\n", iface, count, context);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI GifEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *palette)
+{
+ GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
+ HRESULT hr;
+
+ TRACE("%p,%p\n", iface, palette);
+
+ if (!palette) return E_INVALIDARG;
+
+ EnterCriticalSection(&This->lock);
+
+ if (This->initialized)
+ hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors);
+ else
+ hr = WINCODEC_ERR_NOTINITIALIZED;
+
+ LeaveCriticalSection(&This->lock);
+ return hr;
+}
+
+static HRESULT WINAPI GifEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *thumbnail)
+{
+ TRACE("%p,%p\n", iface, thumbnail);
+ return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI GifEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *preview)
+{
+ TRACE("%p,%p\n", iface, preview);
+ return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI GifEncoder_CreateNewFrame(IWICBitmapEncoder *iface, IWICBitmapFrameEncode **frame, IPropertyBag2 **options)
+{
+ GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
+ HRESULT hr;
+
+ TRACE("%p,%p,%p\n", iface, frame, options);
+
+ if (!frame) return E_INVALIDARG;
+
+ EnterCriticalSection(&This->lock);
+
+ if (This->initialized && !This->committed)
+ {
+ GifFrameEncode *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
+ if (ret)
+ {
+ This->n_frames++;
+
+ ret->IWICBitmapFrameEncode_iface.lpVtbl = &GifFrameEncode_Vtbl;
+ ret->ref = 1;
+ ret->encoder = This;
+ ret->initialized = FALSE;
+ ret->interlace = FALSE; /* FIXME: read from the properties */
+ ret->committed = FALSE;
+ ret->width = 0;
+ ret->height = 0;
+ ret->lines = 0;
+ ret->xres = 0.0;
+ ret->yres = 0.0;
+ ret->colors = 0;
+ ret->image_data = NULL;
+ IWICBitmapEncoder_AddRef(iface);
+ *frame = &ret->IWICBitmapFrameEncode_iface;
+
+ hr = S_OK;
+
+ if (options)
+ {
+ hr = CreatePropertyBag2(NULL, 0, options);
+ if (hr != S_OK)
+ {
+ IWICBitmapFrameEncode_Release(*frame);
+ *frame = NULL;
+ }
+ }
+ }
+ else
+ hr = E_OUTOFMEMORY;
+ }
+ else
+ hr = WINCODEC_ERR_WRONGSTATE;
+
+ LeaveCriticalSection(&This->lock);
+
+ return hr;
+
+}
+
+static HRESULT WINAPI GifEncoder_Commit(IWICBitmapEncoder *iface)
+{
+ GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
+ HRESULT hr;
+
+ TRACE("%p\n", iface);
+
+ EnterCriticalSection(&This->lock);
+
+ if (This->initialized && !This->committed)
+ {
+ char gif_trailer = 0x3b;
+
+ /* FIXME: write text, comment GIF extensions */
+
+ hr = IStream_Write(This->stream, &gif_trailer, sizeof(gif_trailer), NULL);
+ if (hr == S_OK)
+ This->committed = TRUE;
+ }
+ else
+ hr = WINCODEC_ERR_WRONGSTATE;
+
+ LeaveCriticalSection(&This->lock);
+ return hr;
+}
+
+static HRESULT WINAPI GifEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface, IWICMetadataQueryWriter **writer)
+{
+ FIXME("%p,%p: stub\n", iface, writer);
+ return E_NOTIMPL;
+}
+
+static const IWICBitmapEncoderVtbl GifEncoder_Vtbl =
+{
+ GifEncoder_QueryInterface,
+ GifEncoder_AddRef,
+ GifEncoder_Release,
+ GifEncoder_Initialize,
+ GifEncoder_GetContainerFormat,
+ GifEncoder_GetEncoderInfo,
+ GifEncoder_SetColorContexts,
+ GifEncoder_SetPalette,
+ GifEncoder_SetThumbnail,
+ GifEncoder_SetPreview,
+ GifEncoder_CreateNewFrame,
+ GifEncoder_Commit,
+ GifEncoder_GetMetadataQueryWriter
+};
+
+HRESULT GifEncoder_CreateInstance(REFIID iid, void **ppv)
+{
+ GifEncoder *This;
+ HRESULT ret;
+
+ TRACE("%s,%p\n", debugstr_guid(iid), ppv);
+
+ *ppv = NULL;
+
+ This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
+ if (!This) return E_OUTOFMEMORY;
+
+ This->IWICBitmapEncoder_iface.lpVtbl = &GifEncoder_Vtbl;
+ This->ref = 1;
+ This->stream = NULL;
+ InitializeCriticalSection(&This->lock);
+ This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": GifEncoder.lock");
+ This->initialized = FALSE;
+ This->info_written = FALSE;
+ This->committed = FALSE;
+ This->n_frames = 0;
+ This->colors = 0;
+
+ ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv);
+ IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
+
+ return ret;
+}
diff --git a/dlls/windowscodecs/regsvr.c b/dlls/windowscodecs/regsvr.c
index 4750ab8484..584897689d 100644
--- a/dlls/windowscodecs/regsvr.c
+++ b/dlls/windowscodecs/regsvr.c
@@ -1434,6 +1434,16 @@ static struct regsvr_encoder const encoder_list[] = {
".bmp,.dib,.rle",
bmp_encode_formats
},
+ { &CLSID_WICGifEncoder,
+ "The Wine Project",
+ "GIF Encoder",
+ "1.0.0.0",
+ &GUID_VendorMicrosoft,
+ &GUID_ContainerFormatGif,
+ "image/gif",
+ ".gif",
+ gif_formats
+ },
{ &CLSID_WICJpegEncoder,
"The Wine Project",
"JPEG Encoder",
diff --git a/dlls/windowscodecs/wincodecs_private.h b/dlls/windowscodecs/wincodecs_private.h
index 48b9b06469..f7665d1173 100644
--- a/dlls/windowscodecs/wincodecs_private.h
+++ b/dlls/windowscodecs/wincodecs_private.h
@@ -143,6 +143,7 @@ extern HRESULT PngEncoder_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDEN
extern HRESULT BmpEncoder_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDEN;
extern HRESULT DibDecoder_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDEN;
extern HRESULT GifDecoder_CreateInstance(REFIID riid, void** ppv) DECLSPEC_HIDDEN;
+extern HRESULT GifEncoder_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDEN;
extern HRESULT IcoDecoder_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDEN;
extern HRESULT JpegDecoder_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDEN;
extern HRESULT JpegEncoder_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDEN;
diff --git a/dlls/windowscodecs/windowscodecs_wincodec.idl b/dlls/windowscodecs/windowscodecs_wincodec.idl
index 24d48bcb5c..3519e6c618 100644
--- a/dlls/windowscodecs/windowscodecs_wincodec.idl
+++ b/dlls/windowscodecs/windowscodecs_wincodec.idl
@@ -76,6 +76,13 @@ coclass WICBmpEncoder { interface IWICBitmapEncoder; }
]
coclass WICGifDecoder { interface IWICBitmapDecoder; }
+[
+ helpstring("WIC GIF Encoder"),
+ threading(both),
+ uuid(114f5598-0b22-40a0-86a1-c83ea495adbd)
+]
+coclass WICGifEncoder { interface IWICBitmapEncoder; }
+
[
helpstring("WIC ICO Decoder"),
threading(both),
--
2.26.2
3
5
[PATCH 1/3] ntdll: Handle NULL object name buffer in nt_to_unix_file_name_attr().
by Paul Gofman 24 Apr '20
by Paul Gofman 24 Apr '20
24 Apr '20
Signed-off-by: Paul Gofman <pgofman(a)codeweavers.com>
---
dlls/ntdll/directory.c | 8 ++++++++
dlls/ntdll/tests/file.c | 22 +++++++++++++++++++++-
2 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c
index b8cfe507ed..0df6c1ce42 100644
--- a/dlls/ntdll/directory.c
+++ b/dlls/ntdll/directory.c
@@ -2674,8 +2674,16 @@ NTSTATUS nt_to_unix_file_name_attr( const OBJECT_ATTRIBUTES *attr, ANSI_STRING *
NTSTATUS status;
BOOLEAN check_case = !(attr->Attributes & OBJ_CASE_INSENSITIVE);
+ if (!attr->ObjectName->Buffer && attr->ObjectName->Length)
+ return STATUS_ACCESS_VIOLATION;
+
if (!attr->RootDirectory) /* without root dir fall back to normal lookup */
+ {
+ if (!attr->ObjectName->Buffer)
+ return STATUS_OBJECT_PATH_SYNTAX_BAD;
+
return wine_nt_to_unix_file_name( attr->ObjectName, unix_name_ret, disposition, check_case );
+ }
name = attr->ObjectName->Buffer;
name_len = attr->ObjectName->Length / sizeof(WCHAR);
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 31c18454f0..4243a7631c 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -144,16 +144,36 @@ static void create_file_test(void)
static const WCHAR pathInvalidDosW[] = {'\\','D','o','s','D','e','v','i','c','e','s','\\',0};
static const char testdata[] = "Hello World";
FILE_NETWORK_OPEN_INFORMATION info;
+ UNICODE_STRING nameW, null_string;
NTSTATUS status;
HANDLE dir, file;
WCHAR path[MAX_PATH];
OBJECT_ATTRIBUTES attr;
IO_STATUS_BLOCK io;
- UNICODE_STRING nameW;
LARGE_INTEGER offset;
char buf[32];
DWORD ret;
+ attr.Length = sizeof(attr);
+ attr.RootDirectory = NULL;
+ attr.ObjectName = &null_string;
+ attr.Attributes = 0;
+ attr.SecurityDescriptor = NULL;
+ attr.SecurityQualityOfService = NULL;
+
+ null_string.Buffer = NULL;
+ null_string.Length = 256;
+
+ /* try various open modes and options on directories */
+ status = pNtCreateFile( &dir, GENERIC_READ|GENERIC_WRITE, &attr, &io, NULL, 0,
+ FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, FILE_DIRECTORY_FILE, NULL, 0 );
+ ok( status == STATUS_ACCESS_VIOLATION, "Got unexpected status %#x.\n", status );
+
+ null_string.Length = 0;
+ status = pNtCreateFile( &dir, GENERIC_READ|GENERIC_WRITE, &attr, &io, NULL, 0,
+ FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, FILE_DIRECTORY_FILE, NULL, 0 );
+ ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "Got unexpected status %#x.\n", status );
+
GetCurrentDirectoryW( MAX_PATH, path );
pRtlDosPathNameToNtPathName_U( path, &nameW, NULL, NULL );
attr.Length = sizeof(attr);
--
2.25.3
2
5
24 Apr '20
Signed-off-by: Sergio Gómez Del Real <sdelreal(a)codeweavers.com>
---
dlls/mf/tests/mf.c | 570 +++++++++++++++++++++++++++++++++++++++------
1 file changed, 501 insertions(+), 69 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
index ae9f58a4bc..72fad1c77e 100644
--- a/dlls/mf/tests/mf.c
+++ b/dlls/mf/tests/mf.c
@@ -32,6 +32,7 @@
DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
DEFINE_GUID(MFVideoFormat_P208, 0x38303250, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
DEFINE_GUID(MFVideoFormat_ABGR32, 0x00000020, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
+DEFINE_GUID(MFAudioFormat_ZZZ, 0x20202020, 0x2020, 0x2020, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20);
#undef INITGUID
#include <guiddef.h>
@@ -54,34 +55,6 @@ static void _expect_ref(IUnknown* obj, ULONG expected_refcount, int line)
expected_refcount);
}
-static WCHAR *load_resource(const WCHAR *name)
-{
- static WCHAR pathW[MAX_PATH];
- DWORD written;
- HANDLE file;
- HRSRC res;
- void *ptr;
-
- GetTempPathW(ARRAY_SIZE(pathW), pathW);
- lstrcatW(pathW, name);
-
- file = CreateFileW(pathW, GENERIC_READ|GENERIC_WRITE, 0,
- NULL, CREATE_ALWAYS, 0, 0);
- ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %d\n",
- wine_dbgstr_w(pathW), GetLastError());
-
- res = FindResourceW(NULL, name, (LPCWSTR)RT_RCDATA);
- ok(res != 0, "couldn't find resource\n");
- ptr = LockResource(LoadResource(GetModuleHandleA(NULL), res));
- WriteFile(file, ptr, SizeofResource(GetModuleHandleA(NULL), res),
- &written, NULL);
- ok(written == SizeofResource(GetModuleHandleA(NULL), res),
- "couldn't write resource\n" );
- CloseHandle(file);
-
- return pathW;
-}
-
static HRESULT WINAPI test_unk_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
{
if (IsEqualIID(riid, &IID_IUnknown))
@@ -1303,27 +1276,367 @@ static const IMFSampleGrabberSinkCallbackVtbl test_grabber_callback_vtbl =
test_grabber_callback_OnShutdown,
};
+static HRESULT WINAPI test_media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out)
+{
+ if (IsEqualIID(riid, &IID_IMFMediaSource) ||
+ IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *out = iface;
+ IUnknown_AddRef((IUnknown*)*out);
+ return S_OK;
+ }
+
+ *out = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI test_media_source_AddRef(IMFMediaSource *iface)
+{
+ return 2;
+}
+
+static ULONG WINAPI test_media_source_Release(IMFMediaSource *iface)
+{
+ return 1;
+}
+
+static HRESULT WINAPI test_media_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_media_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_media_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_media_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type,
+ HRESULT hr, const PROPVARIANT *value)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_media_source_GetCharacteristics(IMFMediaSource *iface, DWORD *characteristics)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_media_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *descriptor,
+ const GUID *time_format, const PROPVARIANT *start_position)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_media_source_Stop(IMFMediaSource *iface)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_media_source_Pause(IMFMediaSource *iface)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_media_source_Shutdown(IMFMediaSource *iface)
+{
+ return S_OK;
+}
+
+static const IMFMediaSourceVtbl test_media_source_vtbl =
+{
+ test_media_source_QueryInterface,
+ test_media_source_AddRef,
+ test_media_source_Release,
+ test_media_source_GetEvent,
+ test_media_source_BeginGetEvent,
+ test_media_source_EndGetEvent,
+ test_media_source_QueueEvent,
+ test_media_source_GetCharacteristics,
+ test_media_source_CreatePresentationDescriptor,
+ test_media_source_Start,
+ test_media_source_Stop,
+ test_media_source_Pause,
+ test_media_source_Shutdown,
+};
+
+static HRESULT WINAPI test_mft_generic_QueryInterface(IMFTransform *iface, REFIID riid, void **out)
+{
+ if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IMFTransform))
+ {
+ *out = iface;
+ IUnknown_AddRef((IUnknown*)*out);
+ return S_OK;
+ }
+
+ *out = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI test_mft_generic_AddRef(IMFTransform *iface)
+{
+ return 2;
+}
+
+static ULONG WINAPI test_mft_generic_Release(IMFTransform *iface)
+{
+ return 1;
+}
+
+static HRESULT WINAPI test_mft_generic_GetStreamLimits(IMFTransform *iface, DWORD *inputmin, DWORD *inputmax, DWORD *outputmin, DWORD *outputmax)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_mft_generic_GetStreamCount(IMFTransform *iface, DWORD *input_streams, DWORD *output_streams)
+{
+ *input_streams = 1;
+ *output_streams = 1;
+ return S_OK;
+}
+
+static HRESULT WINAPI test_mft_generic_GetStreamIDs(IMFTransform *iface, DWORD inputidsize, DWORD *inputids, DWORD outputidsize, DWORD *outputids)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_mft_generic_GetInputStreamInfo(IMFTransform *iface, DWORD inputstream, MFT_INPUT_STREAM_INFO *streaminfo)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_mft_generic_GetOutputStreamInfo(IMFTransform *iface, DWORD outputstream, MFT_OUTPUT_STREAM_INFO *streaminfo)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_mft_generic_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_mft_generic_GetInputStreamAttributes(IMFTransform *iface, DWORD inputstream, IMFAttributes **attributes)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_mft_generic_GetOutputStreamAttributes(IMFTransform *iface, DWORD outputstream, IMFAttributes **attributes)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_mft_generic_DeleteInputStream(IMFTransform *iface, DWORD streamid)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_mft_generic_AddInputStreams(IMFTransform *iface, DWORD num_streams, DWORD *streamids)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_mft_generic_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_mft_conv_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type)
+{
+ static IMFMediaType *conv_out_type;
+
+ if (id != 0 || index != 0)
+ return MF_E_NO_MORE_TYPES;
+
+ MFCreateMediaType(&conv_out_type);
+ IMFMediaType_SetGUID(conv_out_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio);
+ IMFMediaType_SetGUID(conv_out_type, &MF_MT_SUBTYPE, &MFAudioFormat_ZZZ);
+ IMFMediaType_SetUINT32(conv_out_type, &MF_MT_AUDIO_NUM_CHANNELS, 1);
+ IMFMediaType_SetUINT32(conv_out_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, 32000);
+
+ *type = conv_out_type;
+ return S_OK;
+}
+
+static HRESULT WINAPI test_mft_conv_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
+{
+ UINT32 num_channels, sample;
+
+ IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &num_channels);
+ IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &sample);
+
+ if (num_channels == 2 && sample == 44100)
+ return S_OK;
+
+ return MF_E_INVALIDMEDIATYPE;
+}
+
+static HRESULT WINAPI test_mft_conv_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
+{
+ UINT32 num_channels, sample;
+
+ IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &num_channels);
+ IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &sample);
+
+ if (num_channels == 1 && sample == 32000)
+ return S_OK;
+
+ return MF_E_INVALIDMEDIATYPE;
+}
+
+static HRESULT WINAPI test_mft_conv_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_mft_conv_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_mft_generic_GetInputStatus(IMFTransform *iface, DWORD inputstream, DWORD *flags)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_mft_generic_GetOutputStatus(IMFTransform *iface, DWORD *flags)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_mft_generic_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_mft_generic_ProcessEvent(IMFTransform *iface, DWORD inputstream, IMFMediaEvent *event)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_mft_generic_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE type, ULONG_PTR param)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_mft_generic_ProcessInput(IMFTransform *iface, DWORD inputstream, IMFSample *sample, DWORD flags)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_mft_generic_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD outbufcount, MFT_OUTPUT_DATA_BUFFER *outsamples, DWORD *status)
+{
+ return E_NOTIMPL;
+}
+
+static const IMFTransformVtbl test_mft_conv_vtbl =
+{
+ test_mft_generic_QueryInterface,
+ test_mft_generic_AddRef,
+ test_mft_generic_Release,
+ test_mft_generic_GetStreamLimits,
+ test_mft_generic_GetStreamCount,
+ test_mft_generic_GetStreamIDs,
+ test_mft_generic_GetInputStreamInfo,
+ test_mft_generic_GetOutputStreamInfo,
+ test_mft_generic_GetAttributes,
+ test_mft_generic_GetInputStreamAttributes,
+ test_mft_generic_GetOutputStreamAttributes,
+ test_mft_generic_DeleteInputStream,
+ test_mft_generic_AddInputStreams,
+ test_mft_generic_GetInputAvailableType,
+ test_mft_conv_GetOutputAvailableType,
+ test_mft_conv_SetInputType,
+ test_mft_conv_SetOutputType,
+ test_mft_conv_GetInputCurrentType,
+ test_mft_conv_GetOutputCurrentType,
+ test_mft_generic_GetInputStatus,
+ test_mft_generic_GetOutputStatus,
+ test_mft_generic_SetOutputBounds,
+ test_mft_generic_ProcessEvent,
+ test_mft_generic_ProcessMessage,
+ test_mft_generic_ProcessInput,
+ test_mft_generic_ProcessOutput,
+};
+
+static IMFTransform test_mft_conv = { &test_mft_conv_vtbl };
+
+static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
+{
+ if (IsEqualGUID(riid, &IID_IUnknown) || (IsEqualGUID(riid, &IID_IClassFactory))) {
+ *ppv = iface;
+ return S_OK;
+ }
+
+ *ppv = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
+{
+ return 2;
+}
+
+static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
+{
+ return 1;
+}
+
+static HRESULT WINAPI ClassFactoryConv_CreateInstance(IClassFactory *iface,
+ IUnknown *pUnkOuter, REFIID riid, void **ppv)
+{
+ *ppv = &test_mft_conv;
+ return S_OK;
+}
+
+static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL fLock)
+{
+ ok(0, "unexpected call\n");
+ return E_NOTIMPL;
+}
+
+static const IClassFactoryVtbl ClassFactoryConvVtbl = {
+ ClassFactory_QueryInterface,
+ ClassFactory_AddRef,
+ ClassFactory_Release,
+ ClassFactoryConv_CreateInstance,
+ ClassFactory_LockServer
+};
+
+static IClassFactory ClassFactoryConv = { &ClassFactoryConvVtbl };
+
+static const CLSID test_conv_clsid = { 0x12345678, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
static void test_topology_loader(void)
{
IMFSampleGrabberSinkCallback test_grabber_callback = { &test_grabber_callback_vtbl };
- IMFTopology *topology, *topology2, *full_topology;
+ IMFMediaSource test_media_source = { &test_media_source_vtbl };
+ IMFTopology *topology, *full_topology = NULL;
+ static WCHAR str[] = { 'c','o','n','v', 0 };
+ IMFMediaType *media_type, *mediatypes_pd[3];
IMFTopologyNode *src_node, *sink_node;
+ MFT_REGISTER_TYPE_INFO typeinfo;
IMFPresentationDescriptor *pd;
- IMFSourceResolver *resolver;
IMFActivate *sink_activate;
+ IMFStreamSink *stream_sink;
unsigned int count, value;
- IMFMediaType *media_type;
+ IMFMediaTypeHandler *mth;
IMFStreamDescriptor *sd;
- MF_OBJECT_TYPE obj_type;
- IMFMediaSource *source;
IMFTopoLoader *loader;
- IMFByteStream *stream;
- IMFAttributes *attr;
IMFMediaSink *sink;
- WCHAR *filename;
+ WORD node_count;
BOOL selected;
HRESULT hr;
GUID guid;
+ DWORD reg;
hr = MFStartup(MF_VERSION, MFSTARTUP_FULL);
ok(hr == S_OK, "Startup failure, hr %#x.\n", hr);
@@ -1342,35 +1655,38 @@ static void test_topology_loader(void)
todo_wine
ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#x.\n", hr);
- hr = MFCreateSourceResolver(&resolver);
- ok(hr == S_OK, "Failed to create source resolver, hr %#x.\n", hr);
-
- filename = load_resource(L"test.wav");
-
- hr = MFCreateFile(MF_ACCESSMODE_READ, MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NONE, filename, &stream);
- ok(hr == S_OK, "Failed to create file stream, hr %#x.\n", hr);
-
- IMFByteStream_QueryInterface(stream, &IID_IMFAttributes, (void **)&attr);
- IMFAttributes_SetString(attr, &MF_BYTESTREAM_CONTENT_TYPE, L"audio/wav");
- IMFAttributes_Release(attr);
-
- hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, NULL, MF_RESOLUTION_MEDIASOURCE, NULL,
- &obj_type, (IUnknown **)&source);
- ok(hr == S_OK || broken(FAILED(hr)) /* Vista */, "Failed to create source, hr %#x.\n", hr);
- if (FAILED(hr))
- return;
-
- hr = IMFMediaSource_CreatePresentationDescriptor(source, &pd);
- ok(hr == S_OK, "Failed to create descriptor, hr %#x.\n", hr);
-
- hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, 0, &selected, &sd);
- ok(hr == S_OK, "Failed to get stream descriptor, hr %#x.\n", hr);
+ hr = MFCreateMediaType(&mediatypes_pd[0]);
+ ok(hr == S_OK, "Failed to create media type, hr %#x.\n", hr);
+ hr = IMFMediaType_SetGUID(mediatypes_pd[0], &MF_MT_MAJOR_TYPE, &MFMediaType_Audio);
+ ok(hr == S_OK, "Failed to set GUID, hr %#x.\n", hr);
+ hr = IMFMediaType_SetGUID(mediatypes_pd[0], &MF_MT_SUBTYPE, &MFAudioFormat_ZZZ);
+ ok(hr == S_OK, "Failed to set GUID, hr %#x.\n", hr);
+ hr = IMFMediaType_SetUINT32(mediatypes_pd[0], &MF_MT_AUDIO_NUM_CHANNELS, 2);
+ ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr);
+ hr = IMFMediaType_SetUINT32(mediatypes_pd[0], &MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100);
+ ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr);
+ hr = MFCreateMediaType(&mediatypes_pd[1]);
+ ok(hr == S_OK, "Failed to create media type, hr %#x.\n", hr);
+ hr = IMFMediaType_SetGUID(mediatypes_pd[1], &MF_MT_MAJOR_TYPE, &MFMediaType_Audio);
+ ok(hr == S_OK, "Failed to set GUID, hr %#x.\n", hr);
+ hr = IMFMediaType_SetGUID(mediatypes_pd[1], &MF_MT_SUBTYPE, &MFAudioFormat_ZZZ);
+ ok(hr == S_OK, "Failed to set GUID, hr %#x.\n", hr);
+ hr = IMFMediaType_SetUINT32(mediatypes_pd[1], &MF_MT_AUDIO_NUM_CHANNELS, 1);
+ ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr);
+ hr = IMFMediaType_SetUINT32(mediatypes_pd[1], &MF_MT_AUDIO_SAMPLES_PER_SECOND, 32000);
+ ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr);
+ hr = MFCreateStreamDescriptor(0, 2, mediatypes_pd, &sd);
+ ok(hr == S_OK, "Failed to create stream descriptor, hr %#x.\n", hr);
+ hr = MFCreatePresentationDescriptor(1, &sd, &pd);
+ ok(hr == S_OK, "Failed to create presentation descriptor, hr %#x.\n", hr);
+ hr = IMFPresentationDescriptor_SelectStream(pd, 0);
+ ok(hr == S_OK, "Failed selecting stream.\n");
/* Add source node. */
hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &src_node);
ok(hr == S_OK, "Failed to create topology node, hr %#x.\n", hr);
- hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_SOURCE, (IUnknown *)source);
+ hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_SOURCE, (IUnknown *)&test_media_source);
ok(hr == S_OK, "Failed to set node source, hr %#x.\n", hr);
hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, (IUnknown *)pd);
@@ -1393,7 +1709,11 @@ todo_wine
hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio);
ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr);
- hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM);
+ hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_ZZZ);
+ ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr);
+ hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, 1);
+ ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr);
+ hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, 32000);
ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr);
hr = MFCreateSampleGrabberSinkActivate(media_type, &test_grabber_callback, &sink_activate);
@@ -1423,22 +1743,49 @@ todo_wine
hr = IMFActivate_ActivateObject(sink_activate, &IID_IMFMediaSink, (void **)&sink);
ok(hr == S_OK, "Failed to activate, hr %#x.\n", hr);
- hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)sink);
+ hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream_sink);
+ ok(hr == S_OK, "Failed to get stream sink, hr %#x.\n", hr);
+
+ hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)stream_sink);
ok(hr == S_OK, "Failed to set object, hr %#x.\n", hr);
hr = IMFTopology_GetCount(topology, &count);
ok(hr == S_OK, "Failed to get attribute count, hr %#x.\n", hr);
ok(count == 0, "Unexpected count %u.\n", count);
+ /* if no current media type set, loader uses first index exclusively */
hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
todo_wine
+ ok(hr == MF_E_TOPO_CODEC_NOT_FOUND, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &mth);
+ ok(hr == S_OK, "Failed to get media type handler, hr %#x.\n", hr);
+
+ hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth, 0, &media_type);
+ ok(hr == S_OK, "Failed getting media type, hr %#x.\n", hr);
+
+ /* setting current media type overrides previous behavior; tries with it, and only with it */
+ hr = IMFMediaTypeHandler_SetCurrentMediaType(mth, media_type);
+ ok(hr == S_OK, "Failed setting current media type, hr %#x.\n", hr);
+
+ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
+todo_wine
+ ok(hr == MF_E_TOPO_CODEC_NOT_FOUND, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth, 1, &media_type);
+ ok(hr == S_OK, "Failed getting media type, hr %#x.\n", hr);
+
+ hr = IMFMediaTypeHandler_SetCurrentMediaType(mth, media_type);
+ ok(hr == S_OK, "Failed setting current media type, hr %#x.\n", hr);
+
+ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr);
- ok(full_topology != topology, "Unexpected instance.\n");
hr = IMFTopology_GetCount(topology, &count);
ok(hr == S_OK, "Failed to get attribute count, hr %#x.\n", hr);
ok(count == 0, "Unexpected count %u.\n", count);
+ hr = E_FAIL;
hr = IMFTopology_GetCount(full_topology, &count);
ok(hr == S_OK, "Failed to get attribute count, hr %#x.\n", hr);
todo_wine
@@ -1455,16 +1802,101 @@ todo_wine {
ok(hr == S_OK, "Failed to get attribute, hr %#x.\n", hr);
ok(value == MF_TOPOLOGY_RESOLUTION_SUCCEEDED, "Unexpected value %#x.\n", value);
}
- hr = IMFTopoLoader_Load(loader, full_topology, &topology2, NULL);
+
+ IMFTopology_Release(full_topology);
+
+ /* test with stream deselected */
+ hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, 0, &selected, &sd);
+ ok(hr == S_OK, "Failed getting stream descriptor, hr %#x.\n", hr);
+
+ hr = IMFPresentationDescriptor_DeselectStream(pd, 0);
+ ok(hr == S_OK, "Failed deselecting stream, hr %#x.\n", hr);
+
+ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr);
- ok(full_topology != topology2, "Unexpected instance.\n");
+
+ IMFPresentationDescriptor_Release(pd);
+ IMFStreamDescriptor_Release(sd);
+ IMFTopologyNode_Release(src_node);
+
+ hr = IMFTopology_GetNode(full_topology, 0, &src_node);
+ ok(hr == S_OK, "Failed to get source node, hr %#x.\n", hr);
+ hr = IMFTopologyNode_GetUnknown(src_node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, &IID_IMFPresentationDescriptor, (void **)&pd);
+ ok(hr == S_OK, "Failed to get presentation descriptor, hr %#x.\n", hr);
+ hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, 0, &selected, &sd);
+ ok(hr == S_OK, "Failed to get stream descriptor, hr %#x.\n", hr);
+ ok(!selected, "Stream should not be selected.\n");
+
+ IMFStreamDescriptor_Release(sd);
+ IMFTopologyNode_Release(src_node);
+ IMFPresentationDescriptor_Release(pd);
+ IMFTopology_Release(full_topology);
+
+ /* register a converter to test source -> mft -> sink */
+ hr = CoRegisterClassObject(&test_conv_clsid, (IUnknown*)&ClassFactoryConv, CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, ®);
+ ok(hr == S_OK, "Failed to register class object, hr %#x.\n");
+
+ typeinfo.guidMajorType = MFMediaType_Audio;
+ typeinfo.guidSubtype = MFAudioFormat_ZZZ;
+ hr = MFTRegisterLocalByCLSID(&test_conv_clsid, &MFT_CATEGORY_AUDIO_DECODER, str, MFT_ENUM_FLAG_ASYNCMFT, 1, &typeinfo, 1, &typeinfo);
+ ok(hr == S_OK, "Failed to register mft, hr %#x.\n");
+
+ hr = IMFTopology_GetNode(topology, 0, &src_node);
+ ok(hr == S_OK, "Failed to get source node, hr %#x.\n", hr);
- IMFTopology_Release(topology2);
+ hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth, 0, &media_type);
+ ok(hr == S_OK, "Failed getting media type, hr %#x.\n", hr);
+
+ hr = IMFMediaTypeHandler_SetCurrentMediaType(mth, media_type);
+ ok(hr == S_OK, "Failed setting current media type, hr %#x.\n", hr);
+
+ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
+ ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr);
+ hr = IMFTopology_GetNodeCount(full_topology, &node_count);
+ ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr);
+todo_wine
+ ok(node_count == 3, "Unexpected node count %d.\n", node_count);
IMFTopology_Release(full_topology);
- IMFMediaSource_Release(source);
- IMFSourceResolver_Release(resolver);
- IMFByteStream_Release(stream);
+ /* test when MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES attribute is set on topology */
+ hr = IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, 1);
+ ok(hr == S_OK, "Failed to set attribute.\n");
+
+ /* test with MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES set on source */
+ hr = IMFTopologyNode_SetUINT32(src_node, &MF_TOPONODE_CONNECT_METHOD, MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES);
+ ok(hr == S_OK, "Failed to set attribute.\n");
+
+ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
+ ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr);
+
+ hr = IMFTopology_GetNodeCount(full_topology, &node_count);
+ ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr);
+todo_wine
+ ok(node_count == 3, "Unexpected node count %d.\n", node_count);
+
+ /* now test without MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES on source */
+ hr = IMFTopologyNode_SetUINT32(src_node, &MF_TOPONODE_CONNECT_METHOD, ~MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES);
+ ok(hr == S_OK, "Failed to set attribute.\n");
+
+ IMFTopology_Release(full_topology);
+ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
+ ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr);
+ hr = IMFTopology_GetNodeCount(full_topology, &node_count);
+ ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr);
+ ok(node_count == 2, "Unexpected node count %d.\n", node_count);
+ IMFTopology_Release(full_topology);
+
+ IMFMediaType_Release(mediatypes_pd[0]);
+ IMFMediaType_Release(mediatypes_pd[1]);
+ IMFStreamDescriptor_Release(sd);
+ IMFPresentationDescriptor_Release(pd);
+ IMFTopology_RemoveNode(topology, src_node);
+
+ hr = MFTUnregister(test_conv_clsid);
+ ok(hr == S_OK, "Failed to unregister mft, hr %#x.\n");
+ hr = CoRevokeClassObject(reg);
+ ok(hr == S_OK, "Failed to unregister class object, hr %#x.\n");
+
IMFTopoLoader_Release(loader);
hr = MFShutdown();
--
2.17.1
3
12
24 Apr '20
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/msvcrt/cpp.c | 8 ++------
dlls/msvcrt/scheduler.c | 8 ++------
2 files changed, 4 insertions(+), 12 deletions(-)
2
1