From 347f68539b0884f6adfc5d986b2cb8c07c8df4bb Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Fri, 12 Mar 2010 23:00:18 +0000 Subject: [PATCH 01/61] - Handle ACPI_RESOURCE_TYPE_ADDRESS16, ACPI_RESOURCE_TYPE_ADDRESS32, ACPI_RESOURCE_TYPE_ADDRESS64, ACPI_RESOURCE_TYPE_MEMORY24, and ACPI_RESOURCE_TYPE_MEMORY32 for IRP_MN_QUERY_RESOURCES and IRP_MN_QUERY_RESOURCE_REQUIREMENTS svn path=/trunk/; revision=46154 --- reactos/drivers/bus/acpi/buspdo.c | 349 +++++++++++++++++++++++++++++- 1 file changed, 345 insertions(+), 4 deletions(-) diff --git a/reactos/drivers/bus/acpi/buspdo.c b/reactos/drivers/bus/acpi/buspdo.c index eb8f6686086..4b44ecadd94 100644 --- a/reactos/drivers/bus/acpi/buspdo.c +++ b/reactos/drivers/bus/acpi/buspdo.c @@ -633,6 +633,11 @@ Bus_PDO_QueryResources( NumberOfResources += dma_data->ChannelCount; break; } + case ACPI_RESOURCE_TYPE_ADDRESS16: + case ACPI_RESOURCE_TYPE_ADDRESS32: + case ACPI_RESOURCE_TYPE_ADDRESS64: + case ACPI_RESOURCE_TYPE_MEMORY24: + case ACPI_RESOURCE_TYPE_MEMORY32: case ACPI_RESOURCE_TYPE_IO: { NumberOfResources++; @@ -725,13 +730,171 @@ Bus_PDO_QueryResources( ResourceDescriptor->Flags |= CM_RESOURCE_PORT_16_BIT_DECODE; else ResourceDescriptor->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE; - ResourceDescriptor->u.Port.Start.u.HighPart = 0; - ResourceDescriptor->u.Port.Start.u.LowPart = io_data->Minimum; + ResourceDescriptor->u.Port.Start.QuadPart = io_data->Minimum; ResourceDescriptor->u.Port.Length = io_data->AddressLength; ResourceDescriptor++; break; } + case ACPI_RESOURCE_TYPE_ADDRESS16: + { + ACPI_RESOURCE_ADDRESS16 *addr16_data = (ACPI_RESOURCE_ADDRESS16*) &resource->Data; + if (addr16_data->ResourceType == ACPI_BUS_NUMBER_RANGE) + { + ResourceDescriptor->Type = CmResourceTypeBusNumber; + ResourceDescriptor->ShareDisposition = CmResourceShareShared; + ResourceDescriptor->Flags = 0; + ResourceDescriptor->u.BusNumber.Start = addr16_data->Minimum; + ResourceDescriptor->u.BusNumber.Length = addr16_data->AddressLength; + } + else if (addr16_data->ResourceType == ACPI_IO_RANGE) + { + ResourceDescriptor->Type = CmResourceTypePort; + ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO; + if (addr16_data->Decode == ACPI_POS_DECODE) + ResourceDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE; + ResourceDescriptor->u.Port.Start.QuadPart = addr16_data->Minimum; + ResourceDescriptor->u.Port.Length = addr16_data->AddressLength; + } + else + { + ResourceDescriptor->Type = CmResourceTypeMemory; + ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + ResourceDescriptor->Flags = 0; + if (addr16_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY) + ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + switch (addr16_data->Info.Mem.Caching) + { + case ACPI_CACHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break; + case ACPI_WRITE_COMBINING_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break; + case ACPI_PREFETCHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break; + } + ResourceDescriptor->u.Memory.Start.QuadPart = addr16_data->Minimum; + ResourceDescriptor->u.Memory.Length = addr16_data->AddressLength; + } + ResourceDescriptor++; + break; + } + case ACPI_RESOURCE_TYPE_ADDRESS32: + { + ACPI_RESOURCE_ADDRESS32 *addr32_data = (ACPI_RESOURCE_ADDRESS32*) &resource->Data; + if (addr32_data->ResourceType == ACPI_BUS_NUMBER_RANGE) + { + ResourceDescriptor->Type = CmResourceTypeBusNumber; + ResourceDescriptor->ShareDisposition = CmResourceShareShared; + ResourceDescriptor->Flags = 0; + ResourceDescriptor->u.BusNumber.Start = addr32_data->Minimum; + ResourceDescriptor->u.BusNumber.Length = addr32_data->AddressLength; + } + else if (addr32_data->ResourceType == ACPI_IO_RANGE) + { + ResourceDescriptor->Type = CmResourceTypePort; + ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO; + if (addr32_data->Decode == ACPI_POS_DECODE) + ResourceDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE; + ResourceDescriptor->u.Port.Start.QuadPart = addr32_data->Minimum; + ResourceDescriptor->u.Port.Length = addr32_data->AddressLength; + } + else + { + ResourceDescriptor->Type = CmResourceTypeMemory; + ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + ResourceDescriptor->Flags = 0; + if (addr32_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY) + ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + switch (addr32_data->Info.Mem.Caching) + { + case ACPI_CACHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break; + case ACPI_WRITE_COMBINING_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break; + case ACPI_PREFETCHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break; + } + ResourceDescriptor->u.Memory.Start.QuadPart = addr32_data->Minimum; + ResourceDescriptor->u.Memory.Length = addr32_data->AddressLength; + } + ResourceDescriptor++; + break; + } + case ACPI_RESOURCE_TYPE_ADDRESS64: + { + ACPI_RESOURCE_ADDRESS64 *addr64_data = (ACPI_RESOURCE_ADDRESS64*) &resource->Data; + if (addr64_data->ResourceType == ACPI_BUS_NUMBER_RANGE) + { + DPRINT1("64-bit bus address is not supported!\n"); + ResourceDescriptor->Type = CmResourceTypeBusNumber; + ResourceDescriptor->ShareDisposition = CmResourceShareShared; + ResourceDescriptor->Flags = 0; + ResourceDescriptor->u.BusNumber.Start = (ULONG)addr64_data->Minimum; + ResourceDescriptor->u.BusNumber.Length = addr64_data->AddressLength; + } + else if (addr64_data->ResourceType == ACPI_IO_RANGE) + { + ResourceDescriptor->Type = CmResourceTypePort; + ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO; + if (addr64_data->Decode == ACPI_POS_DECODE) + ResourceDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE; + ResourceDescriptor->u.Port.Start.QuadPart = addr64_data->Minimum; + ResourceDescriptor->u.Port.Length = addr64_data->AddressLength; + } + else + { + ResourceDescriptor->Type = CmResourceTypeMemory; + ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + ResourceDescriptor->Flags = 0; + if (addr64_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY) + ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + switch (addr64_data->Info.Mem.Caching) + { + case ACPI_CACHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break; + case ACPI_WRITE_COMBINING_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break; + case ACPI_PREFETCHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break; + } + ResourceDescriptor->u.Memory.Start.QuadPart = addr64_data->Minimum; + ResourceDescriptor->u.Memory.Length = addr64_data->AddressLength; + } + ResourceDescriptor++; + break; + } + case ACPI_RESOURCE_TYPE_MEMORY24: + { + ACPI_RESOURCE_MEMORY24 *mem24_data = (ACPI_RESOURCE_MEMORY24*) &resource->Data; + ResourceDescriptor->Type = CmResourceTypeMemory; + ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + ResourceDescriptor->Flags = CM_RESOURCE_MEMORY_24; + if (mem24_data->WriteProtect == ACPI_READ_ONLY_MEMORY) + ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + ResourceDescriptor->u.Memory.Start.QuadPart = mem24_data->Minimum; + ResourceDescriptor->u.Memory.Length = mem24_data->AddressLength; + + ResourceDescriptor++; + break; + } + case ACPI_RESOURCE_TYPE_MEMORY32: + { + ACPI_RESOURCE_MEMORY32 *mem32_data = (ACPI_RESOURCE_MEMORY32*) &resource->Data; + ResourceDescriptor->Type = CmResourceTypeMemory; + ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + ResourceDescriptor->Flags = 0; + if (mem32_data->WriteProtect == ACPI_READ_ONLY_MEMORY) + ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + ResourceDescriptor->u.Memory.Start.QuadPart = mem32_data->Minimum; + ResourceDescriptor->u.Memory.Length = mem32_data->AddressLength; + + ResourceDescriptor++; + break; + } default: { break; @@ -815,6 +978,11 @@ Bus_PDO_QueryResourceRequirements( NumberOfResources += dma_data->ChannelCount; break; } + case ACPI_RESOURCE_TYPE_ADDRESS16: + case ACPI_RESOURCE_TYPE_ADDRESS32: + case ACPI_RESOURCE_TYPE_ADDRESS64: + case ACPI_RESOURCE_TYPE_MEMORY24: + case ACPI_RESOURCE_TYPE_MEMORY32: case ACPI_RESOURCE_TYPE_IO: { NumberOfResources++; @@ -905,9 +1073,7 @@ Bus_PDO_QueryResourceRequirements( RequirementDescriptor->Flags |= CM_RESOURCE_PORT_16_BIT_DECODE; else RequirementDescriptor->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE; - RequirementDescriptor->u.Port.Length = io_data->AddressLength; - RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED; RequirementDescriptor->Type = CmResourceTypePort; RequirementDescriptor->ShareDisposition = CmResourceShareDriverExclusive; @@ -918,6 +1084,181 @@ Bus_PDO_QueryResourceRequirements( RequirementDescriptor++; break; } + case ACPI_RESOURCE_TYPE_ADDRESS16: + { + ACPI_RESOURCE_ADDRESS16 *addr16_data = (ACPI_RESOURCE_ADDRESS16*) &resource->Data; + RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED; + if (addr16_data->ResourceType == ACPI_BUS_NUMBER_RANGE) + { + RequirementDescriptor->Type = CmResourceTypeBusNumber; + RequirementDescriptor->ShareDisposition = CmResourceShareShared; + RequirementDescriptor->Flags = 0; + RequirementDescriptor->u.BusNumber.MinBusNumber = addr16_data->Minimum; + RequirementDescriptor->u.BusNumber.MaxBusNumber = addr16_data->Maximum; + RequirementDescriptor->u.BusNumber.Length = addr16_data->AddressLength; + } + else if (addr16_data->ResourceType == ACPI_IO_RANGE) + { + RequirementDescriptor->Type = CmResourceTypePort; + RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + RequirementDescriptor->Flags = CM_RESOURCE_PORT_IO; + if (addr16_data->Decode == ACPI_POS_DECODE) + RequirementDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE; + RequirementDescriptor->u.Port.MinimumAddress.QuadPart = addr16_data->Minimum; + RequirementDescriptor->u.Port.MaximumAddress.QuadPart = addr16_data->Maximum; + RequirementDescriptor->u.Port.Length = addr16_data->AddressLength; + } + else + { + RequirementDescriptor->Type = CmResourceTypeMemory; + RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + RequirementDescriptor->Flags = 0; + if (addr16_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY) + RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + switch (addr16_data->Info.Mem.Caching) + { + case ACPI_CACHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break; + case ACPI_WRITE_COMBINING_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break; + case ACPI_PREFETCHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break; + } + RequirementDescriptor->u.Memory.MinimumAddress.QuadPart = addr16_data->Minimum; + RequirementDescriptor->u.Memory.MaximumAddress.QuadPart = addr16_data->Maximum; + RequirementDescriptor->u.Memory.Length = addr16_data->AddressLength; + } + RequirementDescriptor++; + break; + } + case ACPI_RESOURCE_TYPE_ADDRESS32: + { + ACPI_RESOURCE_ADDRESS32 *addr32_data = (ACPI_RESOURCE_ADDRESS32*) &resource->Data; + RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED; + if (addr32_data->ResourceType == ACPI_BUS_NUMBER_RANGE) + { + RequirementDescriptor->Type = CmResourceTypeBusNumber; + RequirementDescriptor->ShareDisposition = CmResourceShareShared; + RequirementDescriptor->Flags = 0; + RequirementDescriptor->u.BusNumber.MinBusNumber = addr32_data->Minimum; + RequirementDescriptor->u.BusNumber.MaxBusNumber = addr32_data->Maximum; + RequirementDescriptor->u.BusNumber.Length = addr32_data->AddressLength; + } + else if (addr32_data->ResourceType == ACPI_IO_RANGE) + { + RequirementDescriptor->Type = CmResourceTypePort; + RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + RequirementDescriptor->Flags = CM_RESOURCE_PORT_IO; + if (addr32_data->Decode == ACPI_POS_DECODE) + RequirementDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE; + RequirementDescriptor->u.Port.MinimumAddress.QuadPart = addr32_data->Minimum; + RequirementDescriptor->u.Port.MaximumAddress.QuadPart = addr32_data->Maximum; + RequirementDescriptor->u.Port.Length = addr32_data->AddressLength; + } + else + { + RequirementDescriptor->Type = CmResourceTypeMemory; + RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + RequirementDescriptor->Flags = 0; + if (addr32_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY) + RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + switch (addr32_data->Info.Mem.Caching) + { + case ACPI_CACHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break; + case ACPI_WRITE_COMBINING_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break; + case ACPI_PREFETCHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break; + } + RequirementDescriptor->u.Memory.MinimumAddress.QuadPart = addr32_data->Minimum; + RequirementDescriptor->u.Memory.MaximumAddress.QuadPart = addr32_data->Maximum; + RequirementDescriptor->u.Memory.Length = addr32_data->AddressLength; + } + RequirementDescriptor++; + break; + } + case ACPI_RESOURCE_TYPE_ADDRESS64: + { + ACPI_RESOURCE_ADDRESS64 *addr64_data = (ACPI_RESOURCE_ADDRESS64*) &resource->Data; + RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED; + if (addr64_data->ResourceType == ACPI_BUS_NUMBER_RANGE) + { + DPRINT1("64-bit bus address is not supported!\n"); + RequirementDescriptor->Type = CmResourceTypeBusNumber; + RequirementDescriptor->ShareDisposition = CmResourceShareShared; + RequirementDescriptor->Flags = 0; + RequirementDescriptor->u.BusNumber.MinBusNumber = (ULONG)addr64_data->Minimum; + RequirementDescriptor->u.BusNumber.MaxBusNumber = (ULONG)addr64_data->Maximum; + RequirementDescriptor->u.BusNumber.Length = addr64_data->AddressLength; + } + else if (addr64_data->ResourceType == ACPI_IO_RANGE) + { + RequirementDescriptor->Type = CmResourceTypePort; + RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + RequirementDescriptor->Flags = CM_RESOURCE_PORT_IO; + if (addr64_data->Decode == ACPI_POS_DECODE) + RequirementDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE; + RequirementDescriptor->u.Port.MinimumAddress.QuadPart = addr64_data->Minimum; + RequirementDescriptor->u.Port.MaximumAddress.QuadPart = addr64_data->Maximum; + RequirementDescriptor->u.Port.Length = addr64_data->AddressLength; + } + else + { + RequirementDescriptor->Type = CmResourceTypeMemory; + RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + RequirementDescriptor->Flags = 0; + if (addr64_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY) + RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + switch (addr64_data->Info.Mem.Caching) + { + case ACPI_CACHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break; + case ACPI_WRITE_COMBINING_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break; + case ACPI_PREFETCHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break; + } + RequirementDescriptor->u.Memory.MinimumAddress.QuadPart = addr64_data->Minimum; + RequirementDescriptor->u.Memory.MaximumAddress.QuadPart = addr64_data->Maximum; + RequirementDescriptor->u.Memory.Length = addr64_data->AddressLength; + } + RequirementDescriptor++; + break; + } + case ACPI_RESOURCE_TYPE_MEMORY24: + { + ACPI_RESOURCE_MEMORY24 *mem24_data = (ACPI_RESOURCE_MEMORY24*) &resource->Data; + RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED; + RequirementDescriptor->Type = CmResourceTypeMemory; + RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + RequirementDescriptor->Flags = CM_RESOURCE_MEMORY_24; + if (mem24_data->WriteProtect == ACPI_READ_ONLY_MEMORY) + RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + RequirementDescriptor->u.Memory.MinimumAddress.QuadPart = mem24_data->Minimum; + RequirementDescriptor->u.Memory.MaximumAddress.QuadPart = mem24_data->Maximum; + RequirementDescriptor->u.Memory.Length = mem24_data->AddressLength; + + RequirementDescriptor++; + break; + } + case ACPI_RESOURCE_TYPE_MEMORY32: + { + ACPI_RESOURCE_MEMORY32 *mem32_data = (ACPI_RESOURCE_MEMORY32*) &resource->Data; + RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED; + RequirementDescriptor->Type = CmResourceTypeMemory; + RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + RequirementDescriptor->Flags = 0; + if (mem32_data->WriteProtect == ACPI_READ_ONLY_MEMORY) + RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + RequirementDescriptor->u.Memory.MinimumAddress.QuadPart = mem32_data->Minimum; + RequirementDescriptor->u.Memory.MaximumAddress.QuadPart = mem32_data->Maximum; + RequirementDescriptor->u.Memory.Length = mem32_data->AddressLength; + + RequirementDescriptor++; + break; + } default: { break; From 5efb575dfbf8279e112c136164136c0e7494d3a3 Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Sat, 13 Mar 2010 00:01:01 +0000 Subject: [PATCH 02/61] [KMTEST] Try to fix rostests build svn path=/trunk/; revision=46156 --- rostests/drivers/kmtest/deviface_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rostests/drivers/kmtest/deviface_test.c b/rostests/drivers/kmtest/deviface_test.c index 4d92e06df24..0fbd91ea23e 100644 --- a/rostests/drivers/kmtest/deviface_test.c +++ b/rostests/drivers/kmtest/deviface_test.c @@ -22,7 +22,7 @@ /* INCLUDES *******************************************************************/ -#include +#include #include #include "kmtest.h" From c8974c66517ec4dcac232a925260dca90d261b6c Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Sat, 13 Mar 2010 10:36:46 +0000 Subject: [PATCH 03/61] [PSDK] - Add missing function declarations svn path=/trunk/; revision=46159 --- reactos/include/psdk/ks.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/reactos/include/psdk/ks.h b/reactos/include/psdk/ks.h index a86d4a87c1a..c23f4cec012 100644 --- a/reactos/include/psdk/ks.h +++ b/reactos/include/psdk/ks.h @@ -3867,6 +3867,26 @@ KsPinGetConnectedPinFileObject( #else +#if !defined( KS_NO_CREATE_FUNCTIONS ) + +KSDDKAPI +DWORD +WINAPI +KsCreateAllocator( + IN HANDLE ConnectionHandle, + IN PKSALLOCATOR_FRAMING AllocatorFraming, + OUT PHANDLE AllocatorHandle + ); + +KSDDKAPI +DWORD +NTAPI +KsCreateClock( + IN HANDLE ConnectionHandle, + IN PKSCLOCK_CREATE ClockCreate, + OUT PHANDLE ClockHandle + ); + KSDDKAPI DWORD WINAPI @@ -3877,6 +3897,17 @@ KsCreatePin( OUT PHANDLE ConnectionHandle ); +KSDDKAPI +DWORD +WINAPI +KsCreateTopologyNode( + IN HANDLE ParentHandle, + IN PKSNODE_CREATE NodeCreate, + IN ACCESS_MASK DesiredAccess, + OUT PHANDLE NodeHandle + ); + +#endif #endif From 3218673a8ed3459799703ff9c8fe0a1e195fc349 Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Sat, 13 Mar 2010 12:09:24 +0000 Subject: [PATCH 04/61] [PSDK] - A few more types for ks.h needed for ksproxy svn path=/trunk/; revision=46160 --- reactos/include/psdk/ks.h | 41 +++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/reactos/include/psdk/ks.h b/reactos/include/psdk/ks.h index c23f4cec012..37c79981c88 100644 --- a/reactos/include/psdk/ks.h +++ b/reactos/include/psdk/ks.h @@ -336,22 +336,28 @@ DEFINE_GUIDSTRUCT("4747B320-62CE-11CF-A5D6-28DB04C10000", KSMEDIUMSETID_Standard Clock Properties/Methods/Events */ -#define KSPROPSETID_Clock \ +#define STATIC_KSPROPSETID_Clock \ 0xDF12A4C0L, 0xAC17, 0x11CF, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00 +DEFINE_GUIDSTRUCT("DF12A4C0-AC17-11CF-A5D6-28DB04C10000", KSPROPSETID_Clock); +#define KSPROPSETID_Clock DEFINE_GUIDNAMED(KSPROPSETID_Clock) typedef enum { KSPROPERTY_CLOCK_TIME, KSPROPERTY_CLOCK_PHYSICALTIME, - KSPROPERTY_CORRELATEDTIME, - KSPROPERTY_CORRELATEDPHYSICALTIME, + KSPROPERTY_CLOCK_CORRELATEDTIME, + KSPROPERTY_CLOCK_CORRELATEDPHYSICALTIME, KSPROPERTY_CLOCK_RESOLUTION, KSPROPERTY_CLOCK_STATE, +#if defined(_NTDDK_) KSPROPERTY_CLOCK_FUNCTIONTABLE +#endif // defined(_NTDDK_) } KSPROPERTY_CLOCK; -#define KSEVENTSETID_Clock \ +#define STATIC_KSEVENTSETID_Clock \ 0x364D8E20L, 0x62C7, 0x11CF, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00 +DEFINE_GUIDSTRUCT("364D8E20-62C7-11CF-A5D6-28DB04C10000", KSEVENTSETID_Clock); +#define KSEVENTSETID_Clock DEFINE_GUIDNAMED(KSEVENTSETID_Clock) typedef enum { @@ -1838,11 +1844,32 @@ typedef struct KSEVENTDATA EventData; } KSRELATIVEEVENT, *PKSRELATIVEEVENT; +#define KSRELATIVEEVENT_FLAG_HANDLE 0x00000001 +#define KSRELATIVEEVENT_FLAG_POINTER 0x00000002 /* =============================================================== Timing */ + +typedef struct { + KSEVENTDATA EventData; + LONGLONG MarkTime; +} KSEVENT_TIME_MARK, *PKSEVENT_TIME_MARK; + +typedef struct { + KSEVENTDATA EventData; + LONGLONG TimeBase; + LONGLONG Interval; +} KSEVENT_TIME_INTERVAL, *PKSEVENT_TIME_INTERVAL; + +typedef struct { + LONGLONG TimeBase; + LONGLONG Interval; +} KSINTERVAL, *PKSINTERVAL; + + + typedef struct { LONGLONG Time; @@ -1856,12 +1883,6 @@ typedef struct LONGLONG SystemTime; } KSCORRELATED_TIME, *PKSCORRELATED_TIME; -typedef struct -{ - LONGLONG TimeBase; - LONGLONG Interval; -} KSINTERVAL, *PKSINTERVAL; - typedef struct { LONGLONG Duration; From 4ac83b10d10f4293a3f5607b6796978929c595b5 Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Sat, 13 Mar 2010 14:15:56 +0000 Subject: [PATCH 05/61] [KSUSER] - Fix KsCreateAllocator, KsCreateClock, KsCreateTopologyNode function type svn path=/trunk/; revision=46166 --- reactos/dll/directx/ksuser/ksuser.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/reactos/dll/directx/ksuser/ksuser.c b/reactos/dll/directx/ksuser/ksuser.c index 8d565231c70..8f62abf950d 100644 --- a/reactos/dll/directx/ksuser/ksuser.c +++ b/reactos/dll/directx/ksuser/ksuser.c @@ -92,7 +92,7 @@ KsiCreateObjectType( HANDLE hHandle, * *--*/ KSDDKAPI -NTSTATUS +DWORD NTAPI KsCreateAllocator(HANDLE ConnectionHandle, PKSALLOCATOR_FRAMING AllocatorFraming, @@ -130,7 +130,7 @@ KsCreateAllocator(HANDLE ConnectionHandle, * *--*/ KSDDKAPI -NTSTATUS +DWORD NTAPI KsCreateClock(HANDLE ConnectionHandle, PKSCLOCK_CREATE ClockCreate, @@ -225,7 +225,7 @@ KsCreatePin(HANDLE FilterHandle, * *--*/ KSDDKAPI -NTSTATUS +DWORD NTAPI KsCreateTopologyNode(HANDLE ParentHandle, PKSNODE_CREATE NodeCreate, From 268cdeec5fe49b8ec51b51a4f4a36ab58e268db9 Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Sat, 13 Mar 2010 14:56:52 +0000 Subject: [PATCH 06/61] [PSDK] - Fix build #2 svn path=/trunk/; revision=46167 --- reactos/include/psdk/ks.h | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/reactos/include/psdk/ks.h b/reactos/include/psdk/ks.h index 37c79981c88..09b09b8cc4f 100644 --- a/reactos/include/psdk/ks.h +++ b/reactos/include/psdk/ks.h @@ -2091,18 +2091,6 @@ typedef struct { typedef struct _KSEVENT_ENTRY KSEVENT_ENTRY, *PKSEVENT_ENTRY; #if defined(_NTDDK_) -typedef struct -{ - KSEVENTDATA EventData; - LONGLONG MarkTime; -} KSEVENT_TIME_MARK, *PKSEVENT_TIME_MARK; - -typedef struct -{ - KSEVENTDATA EventData; - LONGLONG TimeBase; - LONGLONG Interval; -} KSEVENT_TIME_INTERVAL, *PKSEVENT_TIME_INTERVAL; typedef NTSTATUS (NTAPI *PFNKSADDEVENT)( IN PIRP Irp, From 422b4331509981bb0266981fe3026c27af3cc40a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Sat, 13 Mar 2010 15:59:12 +0000 Subject: [PATCH 07/61] [csrss] Don't expect ReactOS to always boot from C:\ReactOS (that's not the case for LiveCD) svn path=/trunk/; revision=46170 --- reactos/subsystems/win32/csrss/csrsrv/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reactos/subsystems/win32/csrss/csrsrv/init.c b/reactos/subsystems/win32/csrss/csrsrv/init.c index c6fa69b42de..51adb2cacca 100644 --- a/reactos/subsystems/win32/csrss/csrsrv/init.c +++ b/reactos/subsystems/win32/csrss/csrsrv/init.c @@ -622,7 +622,7 @@ CsrpLoadKernelModeDriver (int argc, char ** argv, char ** envp) WCHAR ImagePath [MAX_PATH + 1] = {0}; UNICODE_STRING ModuleName; - wcscpy (ImagePath, L"\\??\\c:\\reactos\\system32\\win32k.sys"); + wcscpy (ImagePath, L"\\SYSTEMROOT\\system32\\win32k.sys"); // wcscat (ImagePath, Data); RtlInitUnicodeString (& ModuleName, ImagePath); Status = NtSetSystemInformation(/* FIXME: SystemLoadAndCallImage */ From 38f7f2fe0530928aed04532b83e863b34c3cff76 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 13 Mar 2010 16:31:53 +0000 Subject: [PATCH 08/61] - Don't enumerate the ACPI root device svn path=/trunk/; revision=46171 --- reactos/drivers/bus/acpi/acpienum.c | 4 ++++ reactos/drivers/bus/acpi/buspdo.c | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/reactos/drivers/bus/acpi/acpienum.c b/reactos/drivers/bus/acpi/acpienum.c index 50ab9eeee4b..13e72ddb9f4 100644 --- a/reactos/drivers/bus/acpi/acpienum.c +++ b/reactos/drivers/bus/acpi/acpienum.c @@ -37,6 +37,10 @@ Bus_PlugInDevice ( PAGED_CODE (); + //Don't enumerate the root device + if (Device->handle == ACPI_ROOT_OBJECT) + return STATUS_SUCCESS; + /* Check we didnt add this already */ for (entry = FdoData->ListOfPDOs.Flink; entry != &FdoData->ListOfPDOs; entry = entry->Flink) diff --git a/reactos/drivers/bus/acpi/buspdo.c b/reactos/drivers/bus/acpi/buspdo.c index 4b44ecadd94..07ab1d445b6 100644 --- a/reactos/drivers/bus/acpi/buspdo.c +++ b/reactos/drivers/bus/acpi/buspdo.c @@ -548,8 +548,6 @@ Bus_PDO_QueryDeviceText( Buffer = L"ACPI Power Resource"; else if (wcsstr(DeviceData->HardwareIDs, L"Processor") != 0) Buffer = L"Processor"; - else if (wcsstr(DeviceData->HardwareIDs, L"ACPI_SYS") != 0) - Buffer = L"ACPI System"; else if (wcsstr(DeviceData->HardwareIDs, L"ThermalZone") != 0) Buffer = L"ACPI Thermal Zone"; else if (wcsstr(DeviceData->HardwareIDs, L"ACPI0002") != 0) From 3e3e531b538609fae92bbd8912ebff15881d9cd4 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 13 Mar 2010 17:07:00 +0000 Subject: [PATCH 09/61] - Let the ACPI driver handle fixed feature buttons svn path=/trunk/; revision=46174 --- reactos/drivers/bus/acpi/buspdo.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/reactos/drivers/bus/acpi/buspdo.c b/reactos/drivers/bus/acpi/buspdo.c index 07ab1d445b6..47a350cda56 100644 --- a/reactos/drivers/bus/acpi/buspdo.c +++ b/reactos/drivers/bus/acpi/buspdo.c @@ -325,6 +325,7 @@ Bus_PDO_QueryDeviceCaps( deviceCapabilities->UniqueID = device->flags.unique_id; deviceCapabilities->NoDisplayInUI = !device->status.show_in_ui; deviceCapabilities->Address = device->pnp.bus_address; + deviceCapabilities->RawDeviceOK = FALSE; } else { @@ -335,6 +336,9 @@ Bus_PDO_QueryDeviceCaps( deviceCapabilities->UniqueID = FALSE; deviceCapabilities->NoDisplayInUI = FALSE; deviceCapabilities->Address = 0; + + /* The ACPI driver will run fixed buttons */ + deviceCapabilities->RawDeviceOK = TRUE; } deviceCapabilities->SilentInstall = FALSE; From 472db0e74d7d31b7d140b2fb2ca3f4763a1008cd Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Sat, 13 Mar 2010 17:36:30 +0000 Subject: [PATCH 10/61] [PSDK] - Fix KSPROPSETID_Stream definition [KSPROXY] - Implement IKsClockPropertySet, IReferenceClock, IMediaSeeking, IKsTopology interface for CKsProxy - Implement more of IBaseFilter::SetSyncSource for CKsProxy - Add missing AddRef to IBaseFilter::QueryFilterInfo for CKsProxy svn path=/trunk/; revision=46176 --- reactos/dll/directx/ksproxy/input_pin.cpp | 2 +- reactos/dll/directx/ksproxy/ksproxy.rbuild | 1 + reactos/dll/directx/ksproxy/node.cpp | 157 +++ reactos/dll/directx/ksproxy/output_pin.cpp | 2 +- reactos/dll/directx/ksproxy/precomp.h | 25 + reactos/dll/directx/ksproxy/proxy.cpp | 1091 ++++++++++++++++++-- reactos/include/psdk/ks.h | 6 +- 7 files changed, 1200 insertions(+), 84 deletions(-) create mode 100644 reactos/dll/directx/ksproxy/node.cpp diff --git a/reactos/dll/directx/ksproxy/input_pin.cpp b/reactos/dll/directx/ksproxy/input_pin.cpp index ce2cef4600d..857b3cc687e 100644 --- a/reactos/dll/directx/ksproxy/input_pin.cpp +++ b/reactos/dll/directx/ksproxy/input_pin.cpp @@ -140,7 +140,7 @@ public: HRESULT STDMETHODCALLTYPE CheckFormat(const AM_MEDIA_TYPE *pmt); HRESULT STDMETHODCALLTYPE CreatePin(const AM_MEDIA_TYPE *pmt); HRESULT STDMETHODCALLTYPE CreatePinHandle(PKSPIN_MEDIUM Medium, PKSPIN_INTERFACE Interface, const AM_MEDIA_TYPE *pmt); - CInputPin(IBaseFilter * ParentFilter, LPCWSTR PinName, HANDLE hFilter, ULONG PinId, KSPIN_COMMUNICATION Communication) : m_Ref(0), m_ParentFilter(ParentFilter), m_PinName(PinName), m_hFilter(hFilter), m_hPin(0), m_PinId(PinId), m_MemAllocator(0), m_IoCount(0), m_Communication(Communication), m_Pin(0), m_ReadOnly(0){}; + CInputPin(IBaseFilter * ParentFilter, LPCWSTR PinName, HANDLE hFilter, ULONG PinId, KSPIN_COMMUNICATION Communication) : m_Ref(0), m_ParentFilter(ParentFilter), m_PinName(PinName), m_hFilter(hFilter), m_hPin(INVALID_HANDLE_VALUE), m_PinId(PinId), m_MemAllocator(0), m_IoCount(0), m_Communication(Communication), m_Pin(0), m_ReadOnly(0){}; virtual ~CInputPin(){}; protected: diff --git a/reactos/dll/directx/ksproxy/ksproxy.rbuild b/reactos/dll/directx/ksproxy/ksproxy.rbuild index 440e279e86a..e5bc87e9b4a 100644 --- a/reactos/dll/directx/ksproxy/ksproxy.rbuild +++ b/reactos/dll/directx/ksproxy/ksproxy.rbuild @@ -33,6 +33,7 @@ interface.cpp ksproxy.cpp ksproxy.rc + node.cpp output_pin.cpp proxy.cpp qualityforward.cpp diff --git a/reactos/dll/directx/ksproxy/node.cpp b/reactos/dll/directx/ksproxy/node.cpp new file mode 100644 index 00000000000..d2686bb96a4 --- /dev/null +++ b/reactos/dll/directx/ksproxy/node.cpp @@ -0,0 +1,157 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS WDM Streaming ActiveMovie Proxy + * FILE: dll/directx/ksproxy/node.cpp + * PURPOSE: Control Node + * + * PROGRAMMERS: Johannes Anderwald (janderwald@reactos.org) + */ +#include "precomp.h" + +class CKsNode : public IKsControl +{ +public: + STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface); + + STDMETHODIMP_(ULONG) AddRef() + { + InterlockedIncrement(&m_Ref); + return m_Ref; + } + STDMETHODIMP_(ULONG) Release() + { + InterlockedDecrement(&m_Ref); + + if (!m_Ref) + { + delete this; + return 0; + } + return m_Ref; + } + + //IKsControl + HRESULT STDMETHODCALLTYPE KsProperty(PKSPROPERTY Property, ULONG PropertyLength, LPVOID PropertyData, ULONG DataLength, ULONG* BytesReturned); + HRESULT STDMETHODCALLTYPE KsMethod(PKSMETHOD Method, ULONG MethodLength, LPVOID MethodData, ULONG DataLength, ULONG* BytesReturned); + HRESULT STDMETHODCALLTYPE KsEvent(PKSEVENT Event, ULONG EventLength, LPVOID EventData, ULONG DataLength, ULONG* BytesReturned); + + CKsNode(IUnknown * pUnkOuter, HANDLE Handle) : m_Ref(0), m_pUnkOuter(pUnkOuter), m_Handle(Handle){}; + virtual ~CKsNode() + { + CloseHandle(m_Handle); + }; + +protected: + LONG m_Ref; + IUnknown * m_pUnkOuter; + HANDLE m_Handle; +}; + +HRESULT +STDMETHODCALLTYPE +CKsNode::QueryInterface( + IN REFIID refiid, + OUT PVOID* Output) +{ + if (IsEqualGUID(refiid, IID_IUnknown) || + IsEqualGUID(refiid, IID_IKsControl)) + { + *Output = PVOID(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } + + return E_NOINTERFACE; +} + +//------------------------------------------------------------------- +// IKsControl +// +HRESULT +STDMETHODCALLTYPE +CKsNode::KsProperty( + PKSPROPERTY Property, + ULONG PropertyLength, + LPVOID PropertyData, + ULONG DataLength, + ULONG* BytesReturned) +{ + assert(m_Handle != 0); + return KsSynchronousDeviceControl(m_Handle, IOCTL_KS_PROPERTY, (PVOID)Property, PropertyLength, (PVOID)PropertyData, DataLength, BytesReturned); +} + +HRESULT +STDMETHODCALLTYPE +CKsNode::KsMethod( + PKSMETHOD Method, + ULONG MethodLength, + LPVOID MethodData, + ULONG DataLength, + ULONG* BytesReturned) +{ + assert(m_Handle != 0); + return KsSynchronousDeviceControl(m_Handle, IOCTL_KS_METHOD, (PVOID)Method, MethodLength, (PVOID)MethodData, DataLength, BytesReturned); +} + +HRESULT +STDMETHODCALLTYPE +CKsNode::KsEvent( + PKSEVENT Event, + ULONG EventLength, + LPVOID EventData, + ULONG DataLength, + ULONG* BytesReturned) +{ + assert(m_Handle != 0); + + if (EventLength) + return KsSynchronousDeviceControl(m_Handle, IOCTL_KS_ENABLE_EVENT, (PVOID)Event, EventLength, (PVOID)EventData, DataLength, BytesReturned); + else + return KsSynchronousDeviceControl(m_Handle, IOCTL_KS_DISABLE_EVENT, (PVOID)Event, EventLength, NULL, 0, BytesReturned); +} + +HRESULT +WINAPI +CKsNode_Constructor( + IUnknown * pUnkOuter, + HANDLE ParentHandle, + ULONG NodeId, + ACCESS_MASK DesiredAccess, + REFIID riid, + LPVOID * ppv) +{ + HRESULT hr; + HANDLE handle; + KSNODE_CREATE NodeCreate; + + OutputDebugStringW(L"CKsNode_Constructor\n"); + + //setup request + NodeCreate.CreateFlags = 0; + NodeCreate.Node = NodeId; + + hr = KsCreateTopologyNode(ParentHandle, &NodeCreate, DesiredAccess, &handle); + if (hr != NOERROR) + { + OutputDebugString("CKsNode_Constructor failed to open device\n"); + return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, hr); + } + + CKsNode * quality = new CKsNode(pUnkOuter, handle); + + if (!quality) + { + // free clock handle + CloseHandle(handle); + return E_OUTOFMEMORY; + } + + if (FAILED(quality->QueryInterface(riid, ppv))) + { + /* not supported */ + delete quality; + return E_NOINTERFACE; + } + + return NOERROR; +} diff --git a/reactos/dll/directx/ksproxy/output_pin.cpp b/reactos/dll/directx/ksproxy/output_pin.cpp index d21f3832f15..98b2f63c0df 100644 --- a/reactos/dll/directx/ksproxy/output_pin.cpp +++ b/reactos/dll/directx/ksproxy/output_pin.cpp @@ -123,7 +123,7 @@ COutputPin::~COutputPin() COutputPin::COutputPin( IBaseFilter * ParentFilter, LPCWSTR PinName, - ULONG PinId) : m_Ref(0), m_ParentFilter(ParentFilter), m_PinName(PinName), m_hPin(0), m_PinId(PinId), m_KsObjectParent(0), m_Pin(0) + ULONG PinId) : m_Ref(0), m_ParentFilter(ParentFilter), m_PinName(PinName), m_hPin(INVALID_HANDLE_VALUE), m_PinId(PinId), m_KsObjectParent(0), m_Pin(0) { HRESULT hr; diff --git a/reactos/dll/directx/ksproxy/precomp.h b/reactos/dll/directx/ksproxy/precomp.h index 5078daef9a9..59e2b23779b 100644 --- a/reactos/dll/directx/ksproxy/precomp.h +++ b/reactos/dll/directx/ksproxy/precomp.h @@ -21,6 +21,20 @@ #include //#include + +interface DECLSPEC_UUID("877E4351-6FEA-11D0-B863-00AA00A216A1") IKsClock; + +#undef INTERFACE +#define INTERFACE IKsClock + +DECLARE_INTERFACE_(IKsClock, IUnknown) +{ + STDMETHOD_(HANDLE, KsGetClockHandle)( + THIS + ) PURE; +}; + + typedef HRESULT (CALLBACK *LPFNCREATEINSTANCE)(IUnknown* pUnkOuter, REFIID riid, LPVOID* ppvObject); typedef struct { @@ -139,4 +153,15 @@ CEnumMediaTypes_fnConstructor( REFIID riid, LPVOID * ppv); +/* node.cpp */ +HRESULT +WINAPI +CKsNode_Constructor( + IUnknown * pUnkOuter, + HANDLE ParentHandle, + ULONG NodeId, + ACCESS_MASK DesiredAccess, + REFIID riid, + LPVOID * ppv); + extern const GUID IID_IKsObject; diff --git a/reactos/dll/directx/ksproxy/proxy.cpp b/reactos/dll/directx/ksproxy/proxy.cpp index f74f22ba9f7..9faeb930ee0 100644 --- a/reactos/dll/directx/ksproxy/proxy.cpp +++ b/reactos/dll/directx/ksproxy/proxy.cpp @@ -14,13 +14,16 @@ const GUID GUID_NULL = {0x00000000L, 0x0000, 0x0000, {0x00, const GUID IID_ISpecifyPropertyPages = {0xB196B28B, 0xBAB4, 0x101A, {0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07}}; const GUID IID_IPersistStream = {0x00000109, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}; const GUID KSPROPSETID_MediaSeeking = {0xEE904F0CL, 0xD09B, 0x11D0, {0xAB, 0xE9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}}; +const GUID KSPROPSETID_Clock = {0xDF12A4C0L, 0xAC17, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}}; +const GUID KSEVENTSETID_Clock = {0x364D8E20L, 0x62C7, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}}; +const GUID KSPROPSETID_Stream = {0x65aaba60L, 0x98ae, 0x11cf, {0xa1, 0x0d, 0x00, 0x20, 0xaf, 0xd1, 0x56, 0xe4}}; #endif const GUID IID_IBDA_DeviceControl = {0xFD0A5AF3, 0xB41D, 0x11d2, {0x9C, 0x95, 0x00, 0xC0, 0x4F, 0x79, 0x71, 0xE0}}; const GUID IID_IKsAggregateControl = {0x7F40EAC0, 0x3947, 0x11D2, {0x87, 0x4E, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}}; const GUID IID_IKsClockPropertySet = {0x5C5CBD84, 0xE755, 0x11D0, {0xAC, 0x18, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}}; const GUID IID_IKsTopology = {0x28F54683, 0x06FD, 0x11D2, {0xB2, 0x7A, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}}; - +const GUID IID_IKsClock = {0x877E4351, 0x6FEA, 0x11D0, {0xB8, 0x63, 0x00, 0xAA, 0x00, 0xA2, 0x16, 0xA1}}; /* Needs IKsClock, IKsNotifyEvent */ @@ -35,6 +38,7 @@ class CKsProxy : public IBaseFilter, public IReferenceClock, public IMediaSeeking, public IKsPropertySet, + public IKsClock, public IKsClockPropertySet, public IAMFilterMiscFlags, public IKsControl, @@ -148,6 +152,9 @@ public: // IKsObject HANDLE STDMETHODCALLTYPE KsGetObjectHandle(); + // IKsClock + HANDLE STDMETHODCALLTYPE KsGetClockHandle(); + //IAMDeviceRemoval HRESULT STDMETHODCALLTYPE DeviceInfo(CLSID *pclsidInterfaceClass, LPWSTR *pwszSymbolicLink); HRESULT STDMETHODCALLTYPE Reassociate(void); @@ -163,7 +170,7 @@ public: HRESULT STDMETHODCALLTYPE GetPages(CAUUID *pPages); - CKsProxy() : m_Ref(0), m_pGraph(0), m_ReferenceClock(0), m_FilterState(State_Stopped), m_hDevice(0), m_Plugins(), m_Pins(), m_DevicePath(0) {}; + CKsProxy() : m_Ref(0), m_pGraph(0), m_ReferenceClock(0), m_FilterState(State_Stopped), m_hDevice(0), m_Plugins(), m_Pins(), m_DevicePath(0), m_hClock(0) {}; ~CKsProxy() { if (m_hDevice) @@ -178,6 +185,9 @@ public: HRESULT STDMETHODCALLTYPE GetPinName(ULONG PinId, KSPIN_DATAFLOW DataFlow, ULONG PinCount, LPWSTR * OutPinName); HRESULT STDMETHODCALLTYPE GetPinCommunication(ULONG PinId, KSPIN_COMMUNICATION * Communication); HRESULT STDMETHODCALLTYPE CreatePins(); + HRESULT STDMETHODCALLTYPE GetMediaSeekingFormats(PKSMULTIPLE_ITEM *FormatList); + HRESULT STDMETHODCALLTYPE CreateClockInstance(); + HRESULT STDMETHODCALLTYPE PerformClockProperty(ULONG PropertyId, ULONG PropertyFlags, PVOID OutputBuffer, ULONG OutputBufferSize); protected: LONG m_Ref; IFilterGraph *m_pGraph; @@ -188,6 +198,7 @@ protected: PinVector m_Pins; LPWSTR m_DevicePath; CLSID m_DeviceInterfaceGUID; + HANDLE m_hClock; }; HRESULT @@ -196,7 +207,7 @@ CKsProxy::QueryInterface( IN REFIID refiid, OUT PVOID* Output) { - *Output = (PVOID)0xDEADDEAD;//NULL; + *Output = NULL; if (IsEqualGUID(refiid, IID_IUnknown) || IsEqualGUID(refiid, IID_IBaseFilter)) @@ -229,6 +240,12 @@ CKsProxy::QueryInterface( reinterpret_cast(*Output)->AddRef(); return NOERROR; } + else if (IsEqualGUID(refiid, IID_IKsClock)) + { + *Output = (IKsClock*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } else if (IsEqualGUID(refiid, IID_IReferenceClock)) { *Output = (IReferenceClock*)(this); @@ -335,13 +352,110 @@ CKsProxy::GetPages(CAUUID *pPages) //------------------------------------------------------------------- // IKsClockPropertySet interface // + +HRESULT +STDMETHODCALLTYPE +CKsProxy::CreateClockInstance() +{ + HRESULT hr; + HANDLE hPin = INVALID_HANDLE_VALUE; + ULONG Index; + PIN_DIRECTION PinDir; + IKsObject *pObject; + KSCLOCK_CREATE ClockCreate; + + // find output pin and handle + for(Index = 0; Index < m_Pins.size(); Index++) + { + //get pin + IPin * pin = m_Pins[Index]; + if (!pin) + continue; + + // get direction + hr = pin->QueryDirection(&PinDir); + if (FAILED(hr)) + continue; + + // query IKsObject interface + hr = pin->QueryInterface(IID_IKsObject, (void**)&pObject); + if (FAILED(hr)) + continue; + + + // get pin handle + hPin = pObject->KsGetObjectHandle(); + + //release IKsObject + pObject->Release(); + + if (hPin != INVALID_HANDLE_VALUE) + break; + } + + if (hPin == INVALID_HANDLE_VALUE) + { + // clock can only be instantiated on a pin handle + return E_NOTIMPL; + } + + if (m_hClock) + { + // release clock handle + CloseHandle(m_hClock); + } + + //setup clock create request + ClockCreate.CreateFlags = 0; + + // setup clock create request + hr = KsCreateClock(hPin, &ClockCreate, &m_hClock); // FIXME KsCreateClock returns NTSTATUS + if (SUCCEEDED(hr)) + { + // failed to create clock + return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError()); + } + + return S_OK; +} + +HRESULT +STDMETHODCALLTYPE +CKsProxy::PerformClockProperty( + ULONG PropertyId, + ULONG PropertyFlags, + PVOID OutputBuffer, + ULONG OutputBufferSize) +{ + KSPROPERTY Property; + HRESULT hr; + ULONG BytesReturned; + + if (!m_hClock) + { + // create clock + hr = CreateClockInstance(); + if (FAILED(hr)) + return hr; + } + + // setup request + Property.Set = KSPROPSETID_Clock; + Property.Id = PropertyId; + Property.Flags = PropertyFlags; + + hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)OutputBuffer, OutputBufferSize, &BytesReturned); + + return hr; +} + HRESULT STDMETHODCALLTYPE CKsProxy::KsGetTime( LONGLONG* Time) { - OutputDebugStringW(L"CKsProxy::KsGetTime NotImplemented\n"); - return E_NOTIMPL; + OutputDebugStringW(L"CKsProxy::KsGetTime\n"); + return PerformClockProperty(KSPROPERTY_CLOCK_TIME, KSPROPERTY_TYPE_GET, (PVOID)Time, sizeof(LONGLONG)); } HRESULT @@ -349,8 +463,8 @@ STDMETHODCALLTYPE CKsProxy::KsSetTime( LONGLONG Time) { - OutputDebugStringW(L"CKsProxy::KsSetTime NotImplemented\n"); - return E_NOTIMPL; + OutputDebugStringW(L"CKsProxy::KsSetTime\n"); + return PerformClockProperty(KSPROPERTY_CLOCK_TIME, KSPROPERTY_TYPE_SET, (PVOID)&Time, sizeof(LONGLONG)); } HRESULT @@ -358,8 +472,8 @@ STDMETHODCALLTYPE CKsProxy::KsGetPhysicalTime( LONGLONG* Time) { - OutputDebugStringW(L"CKsProxy::KsGetPhysicalTime NotImplemented\n"); - return E_NOTIMPL; + OutputDebugStringW(L"CKsProxy::KsGetPhysicalTime\n"); + return PerformClockProperty(KSPROPERTY_CLOCK_PHYSICALTIME, KSPROPERTY_TYPE_GET, (PVOID)Time, sizeof(LONGLONG)); } HRESULT @@ -368,7 +482,7 @@ CKsProxy::KsSetPhysicalTime( LONGLONG Time) { OutputDebugStringW(L"CKsProxy::KsSetPhysicalTime NotImplemented\n"); - return E_NOTIMPL; + return PerformClockProperty(KSPROPERTY_CLOCK_PHYSICALTIME, KSPROPERTY_TYPE_SET, (PVOID)&Time, sizeof(LONGLONG)); } HRESULT @@ -376,8 +490,8 @@ STDMETHODCALLTYPE CKsProxy::KsGetCorrelatedTime( KSCORRELATED_TIME* CorrelatedTime) { - OutputDebugStringW(L"CKsProxy::KsGetCorrelatedTime NotImplemented\n"); - return E_NOTIMPL; + OutputDebugStringW(L"CKsProxy::KsGetCorrelatedTime\n"); + return PerformClockProperty(KSPROPERTY_CLOCK_CORRELATEDTIME, KSPROPERTY_TYPE_GET, (PVOID)CorrelatedTime, sizeof(KSCORRELATED_TIME)); } HRESULT @@ -385,8 +499,8 @@ STDMETHODCALLTYPE CKsProxy::KsSetCorrelatedTime( KSCORRELATED_TIME* CorrelatedTime) { - OutputDebugStringW(L"CKsProxy::KsSetCorrelatedTime NotImplemented\n"); - return E_NOTIMPL; + OutputDebugStringW(L"CKsProxy::KsSetCorrelatedTime\n"); + return PerformClockProperty(KSPROPERTY_CLOCK_CORRELATEDTIME, KSPROPERTY_TYPE_SET, (PVOID)CorrelatedTime, sizeof(KSCORRELATED_TIME)); } HRESULT @@ -394,8 +508,8 @@ STDMETHODCALLTYPE CKsProxy::KsGetCorrelatedPhysicalTime( KSCORRELATED_TIME* CorrelatedTime) { - OutputDebugStringW(L"CKsProxy::KsGetCorrelatedPhysicalTime NotImplemented\n"); - return E_NOTIMPL; + OutputDebugStringW(L"CKsProxy::KsGetCorrelatedPhysicalTime\n"); + return PerformClockProperty(KSPROPERTY_CLOCK_CORRELATEDPHYSICALTIME, KSPROPERTY_TYPE_GET, (PVOID)CorrelatedTime, sizeof(KSCORRELATED_TIME)); } HRESULT @@ -403,8 +517,8 @@ STDMETHODCALLTYPE CKsProxy::KsSetCorrelatedPhysicalTime( KSCORRELATED_TIME* CorrelatedTime) { - OutputDebugStringW(L"CKsProxy::KsSetCorrelatedPhysicalTime NotImplemented\n"); - return E_NOTIMPL; + OutputDebugStringW(L"CKsProxy::KsSetCorrelatedPhysicalTime\n"); + return PerformClockProperty(KSPROPERTY_CLOCK_CORRELATEDPHYSICALTIME, KSPROPERTY_TYPE_SET, (PVOID)CorrelatedTime, sizeof(KSCORRELATED_TIME)); } HRESULT @@ -412,8 +526,8 @@ STDMETHODCALLTYPE CKsProxy::KsGetResolution( KSRESOLUTION* Resolution) { - OutputDebugStringW(L"CKsProxy::KsGetResolution NotImplemented\n"); - return E_NOTIMPL; + OutputDebugStringW(L"CKsProxy::KsGetResolution\n"); + return PerformClockProperty(KSPROPERTY_CLOCK_RESOLUTION, KSPROPERTY_TYPE_GET, (PVOID)Resolution, sizeof(KSRESOLUTION)); } HRESULT @@ -421,8 +535,8 @@ STDMETHODCALLTYPE CKsProxy::KsGetState( KSSTATE* State) { - OutputDebugStringW(L"CKsProxy::KsGetState NotImplemented\n"); - return E_NOTIMPL; + OutputDebugStringW(L"CKsProxy::KsGetState\n"); + return PerformClockProperty(KSPROPERTY_CLOCK_STATE, KSPROPERTY_TYPE_GET, (PVOID)State, sizeof(KSSTATE)); } //------------------------------------------------------------------- @@ -433,8 +547,40 @@ STDMETHODCALLTYPE CKsProxy::GetTime( REFERENCE_TIME *pTime) { - OutputDebugStringW(L"CKsProxy::GetTime NotImplemented\n"); - return E_NOTIMPL; + HRESULT hr; + KSPROPERTY Property; + ULONG BytesReturned; + + OutputDebugStringW(L"CKsProxy::GetTime\n"); + + if (!pTime) + return E_POINTER; + + // + //FIXME locks + // + + if (!m_hClock) + { + // create clock + hr = CreateClockInstance(); + if (FAILED(hr)) + return hr; + } + + // setup request + Property.Set = KSPROPSETID_Clock; + Property.Id = KSPROPERTY_CLOCK_TIME; + Property.Flags = KSPROPERTY_TYPE_GET; + + // perform request + hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pTime, sizeof(REFERENCE_TIME), &BytesReturned); + + // TODO + // increment value + // + + return hr; } HRESULT @@ -445,8 +591,62 @@ CKsProxy::AdviseTime( HEVENT hEvent, DWORD_PTR *pdwAdviseCookie) { - OutputDebugStringW(L"CKsProxy::AdviseTime NotImplemented\n"); - return E_NOTIMPL; + HRESULT hr; + KSEVENT Property; + ULONG BytesReturned; + PKSEVENT_TIME_MARK Event; + + OutputDebugStringW(L"CKsProxy::AdviseTime\n"); + + // + //FIXME locks + // + + if (!pdwAdviseCookie) + return E_POINTER; + + if (!m_hClock) + { + // create clock + hr = CreateClockInstance(); + if (FAILED(hr)) + return hr; + } + + // allocate event entry + Event = (PKSEVENT_TIME_MARK)CoTaskMemAlloc(sizeof(KSEVENT_TIME_MARK)); + if (Event) + { + // setup request + Property.Set = KSEVENTSETID_Clock; + Property.Id = KSEVENT_CLOCK_POSITION_MARK; + Property.Flags = KSEVENT_TYPE_ENABLE; + + Event->EventData.NotificationType = KSEVENTF_EVENT_HANDLE; + Event->EventData.EventHandle.Event = (HANDLE)hEvent; + Event->EventData.Alignment.Alignment[0] = 0; + Event->EventData.Alignment.Alignment[1] = 0; + Event->MarkTime = baseTime + streamTime; + + // perform request + hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSEVENT), (PVOID)Event, sizeof(KSEVENT_TIME_MARK), &BytesReturned); + if (SUCCEEDED(hr)) + { + // store event handle + *pdwAdviseCookie = (DWORD_PTR)Event; + } + else + { + // failed to enable event + CoTaskMemFree(Event); + } + } + else + { + hr = E_OUTOFMEMORY; + } + + return hr; } HRESULT @@ -457,8 +657,63 @@ CKsProxy::AdvisePeriodic( HSEMAPHORE hSemaphore, DWORD_PTR *pdwAdviseCookie) { - OutputDebugStringW(L"CKsProxy::AdvisePeriodic NotImplemented\n"); - return E_NOTIMPL; + HRESULT hr; + KSEVENT Property; + ULONG BytesReturned; + PKSEVENT_TIME_INTERVAL Event; + + OutputDebugStringW(L"CKsProxy::AdvisePeriodic\n"); + + // + //FIXME locks + // + + if (!pdwAdviseCookie) + return E_POINTER; + + if (!m_hClock) + { + // create clock + hr = CreateClockInstance(); + if (FAILED(hr)) + return hr; + } + + // allocate event entry + Event = (PKSEVENT_TIME_INTERVAL)CoTaskMemAlloc(sizeof(KSEVENT_TIME_INTERVAL)); + if (Event) + { + // setup request + Property.Set = KSEVENTSETID_Clock; + Property.Id = KSEVENT_CLOCK_INTERVAL_MARK; + Property.Flags = KSEVENT_TYPE_ENABLE; + + Event->EventData.NotificationType = KSEVENTF_SEMAPHORE_HANDLE; + Event->EventData.SemaphoreHandle.Semaphore = (HANDLE)hSemaphore; + Event->EventData.SemaphoreHandle.Reserved = 0; + Event->EventData.SemaphoreHandle.Adjustment = 1; + Event->TimeBase = startTime; + Event->Interval = periodTime; + + // perform request + hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSEVENT), (PVOID)Event, sizeof(KSEVENT_TIME_INTERVAL), &BytesReturned); + if (SUCCEEDED(hr)) + { + // store event handle + *pdwAdviseCookie = (DWORD_PTR)Event; + } + else + { + // failed to enable event + CoTaskMemFree(Event); + } + } + else + { + hr = E_OUTOFMEMORY; + } + + return hr; } HRESULT @@ -466,8 +721,28 @@ STDMETHODCALLTYPE CKsProxy::Unadvise( DWORD_PTR dwAdviseCookie) { - OutputDebugStringW(L"CKsProxy::Unadvise NotImplemented\n"); - return E_NOTIMPL; + HRESULT hr; + ULONG BytesReturned; + + OutputDebugStringW(L"CKsProxy::Unadvise\n"); + + if (m_hClock) + { + //lets disable the event + hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_DISABLE_EVENT, (PVOID)dwAdviseCookie, sizeof(KSEVENTDATA), 0, 0, &BytesReturned); + if (SUCCEEDED(hr)) + { + // lets free event data + CoTaskMemFree((LPVOID)dwAdviseCookie); + } + } + else + { + // no clock available + hr = E_FAIL; + } + + return hr; } //------------------------------------------------------------------- @@ -478,8 +753,55 @@ STDMETHODCALLTYPE CKsProxy::GetCapabilities( DWORD *pCapabilities) { - OutputDebugStringW(L"CKsProxy::GetCapabilities NotImplemented\n"); - return E_NOTIMPL; + KSPROPERTY Property; + ULONG BytesReturned, Index; + HRESULT hr = S_OK; + DWORD TempCaps; + + Property.Set = KSPROPSETID_MediaSeeking; + Property.Id = KSPROPERTY_MEDIASEEKING_CAPABILITIES; + Property.Flags = KSPROPERTY_TYPE_GET; + + OutputDebugStringW(L"CKsProxy::GetCapabilities\n"); + + if (!pCapabilities) + return E_POINTER; + + + *pCapabilities = (KS_SEEKING_CanSeekAbsolute | KS_SEEKING_CanSeekForwards | KS_SEEKING_CanSeekBackwards | KS_SEEKING_CanGetCurrentPos | + KS_SEEKING_CanGetStopPos | KS_SEEKING_CanGetDuration | KS_SEEKING_CanPlayBackwards); + + KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&pCapabilities, sizeof(KS_SEEKING_CAPABILITIES), &BytesReturned); + // check if plugins support it + for(Index = 0; Index < m_Plugins.size(); Index++) + { + // get plugin + IUnknown * Plugin = m_Plugins[Index]; + + if (!Plugin) + continue; + + // query for IMediaSeeking interface + IMediaSeeking *pSeek = NULL; + hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek); + if (FAILED(hr)) + { + *pCapabilities = 0; + return hr; + } + + TempCaps = 0; + // set time format + hr = pSeek->GetCapabilities(&TempCaps); + if (SUCCEEDED(hr)) + { + // and with supported flags + *pCapabilities = (*pCapabilities & TempCaps); + } + // release IMediaSeeking interface + pSeek->Release(); + } + return hr; } HRESULT @@ -487,27 +809,49 @@ STDMETHODCALLTYPE CKsProxy::CheckCapabilities( DWORD *pCapabilities) { - OutputDebugStringW(L"CKsProxy::CheckCapabilities NotImplemented\n"); - return E_NOTIMPL; + DWORD Capabilities; + HRESULT hr; + + OutputDebugStringW(L"CKsProxy::CheckCapabilities\n"); + + if (!pCapabilities) + return E_POINTER; + + if (!*pCapabilities) + return E_FAIL; + + hr = GetCapabilities(&Capabilities); + if (SUCCEEDED(hr)) + { + if ((Capabilities | *pCapabilities) == Capabilities) + { + // all present + return S_OK; + } + + Capabilities = (Capabilities & *pCapabilities); + if (Capabilities) + { + // not all present + *pCapabilities = Capabilities; + return S_FALSE; + } + // no capabilities are present + return E_FAIL; + } + + return hr; } HRESULT STDMETHODCALLTYPE -CKsProxy::IsFormatSupported( - const GUID *pFormat) +CKsProxy::GetMediaSeekingFormats( + PKSMULTIPLE_ITEM *FormatList) { KSPROPERTY Property; - PKSMULTIPLE_ITEM FormatList; - LPGUID pGuid; - ULONG Index; - HRESULT hr = S_FALSE; + HRESULT hr; ULONG BytesReturned; - OutputDebugStringW(L"CKsProxy::IsFormatSupported\n"); - - if (!pFormat) - return E_POINTER; - Property.Set = KSPROPSETID_MediaSeeking; Property.Id = KSPROPERTY_MEDIASEEKING_FORMATS; Property.Flags = KSPROPERTY_TYPE_GET; @@ -518,36 +862,54 @@ CKsProxy::IsFormatSupported( if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_MORE_DATA)) { // allocate format list - FormatList = (PKSMULTIPLE_ITEM)CoTaskMemAlloc(BytesReturned); - if (!FormatList) + *FormatList = (PKSMULTIPLE_ITEM)CoTaskMemAlloc(BytesReturned); + if (!*FormatList) { // not enough memory return E_OUTOFMEMORY; } // get format list - hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)FormatList, BytesReturned, &BytesReturned); + hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)*FormatList, BytesReturned, &BytesReturned); if (FAILED(hr)) { // failed to query format list CoTaskMemFree(FormatList); - return hr; } + } + return hr; +} +HRESULT +STDMETHODCALLTYPE +CKsProxy::IsFormatSupported( + const GUID *pFormat) +{ + PKSMULTIPLE_ITEM FormatList; + LPGUID pGuid; + ULONG Index; + HRESULT hr = S_FALSE; + + OutputDebugStringW(L"CKsProxy::IsFormatSupported\n"); + + if (!pFormat) + return E_POINTER; + + // get media formats + hr = GetMediaSeekingFormats(&FormatList); + if (SUCCEEDED(hr)) + { //iterate through format list pGuid = (LPGUID)(FormatList + 1); for(Index = 0; Index < FormatList->Count; Index++) { if (IsEqualGUID(*pGuid, *pFormat)) { - OutputDebugStringW(L"CKsProxy::IsFormatSupported found format\n"); CoTaskMemFree(FormatList); return S_OK; } pGuid++; } - - OutputDebugStringW(L"CKsProxy::IsFormatSupported FormatNotFound\n"); // free format list CoTaskMemFree(FormatList); } @@ -589,8 +951,55 @@ STDMETHODCALLTYPE CKsProxy::QueryPreferredFormat( GUID *pFormat) { - OutputDebugStringW(L"CKsProxy::QueryPreferredFormat NotImplemented\n"); - return E_NOTIMPL; + PKSMULTIPLE_ITEM FormatList; + HRESULT hr; + ULONG Index; + + OutputDebugStringW(L"CKsProxy::QueryPreferredFormat\n"); + + if (!pFormat) + return E_POINTER; + + hr = GetMediaSeekingFormats(&FormatList); + if (SUCCEEDED(hr)) + { + if (FormatList->Count) + { + CopyMemory(pFormat, (FormatList + 1), sizeof(GUID)); + CoTaskMemFree(FormatList); + return S_OK; + } + CoTaskMemFree(FormatList); + } + if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND)) + { + // check if plugins support it + for(Index = 0; Index < m_Plugins.size(); Index++) + { + // get plugin + IUnknown * Plugin = m_Plugins[Index]; + + if (!Plugin) + continue; + + // query for IMediaSeeking interface + IMediaSeeking *pSeek = NULL; + hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek); + if (SUCCEEDED(hr)) + { + // get preferred time format + hr = pSeek->QueryPreferredFormat(pFormat); + // release IMediaSeeking interface + pSeek->Release(); + + if (hr != S_FALSE) + return hr; + } + } + hr = S_FALSE; + } + + return hr; } HRESULT @@ -598,8 +1007,45 @@ STDMETHODCALLTYPE CKsProxy::GetTimeFormat( GUID *pFormat) { - OutputDebugStringW(L"CKsProxy::GetTimeFormat NotImplemented\n"); - return E_NOTIMPL; + KSPROPERTY Property; + ULONG BytesReturned, Index; + HRESULT hr; + + Property.Set = KSPROPSETID_MediaSeeking; + Property.Id = KSPROPERTY_MEDIASEEKING_TIMEFORMAT; + Property.Flags = KSPROPERTY_TYPE_GET; + + OutputDebugStringW(L"CKsProxy::GetTimeFormat\n"); + + hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pFormat, sizeof(GUID), &BytesReturned); + if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND)) + { + // check if plugins support it + for(Index = 0; Index < m_Plugins.size(); Index++) + { + hr = E_NOTIMPL; + // get plugin + IUnknown * Plugin = m_Plugins[Index]; + + if (!Plugin) + continue; + + // query for IMediaSeeking interface + IMediaSeeking *pSeek = NULL; + hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek); + if (SUCCEEDED(hr)) + { + // set time format + hr = pSeek->GetTimeFormat(pFormat); + // release IMediaSeeking interface + pSeek->Release(); + + if (hr != S_FALSE) + break; + } + } + } + return hr; } HRESULT @@ -607,8 +1053,17 @@ STDMETHODCALLTYPE CKsProxy::IsUsingTimeFormat( const GUID *pFormat) { - OutputDebugStringW(L"CKsProxy::IsUsingTimeFormat NotImplemented\n"); - return E_NOTIMPL; + GUID Format; + + OutputDebugStringW(L"CKsProxy::IsUsingTimeFormat\n"); + + if (FAILED(QueryPreferredFormat(&Format))) + return S_FALSE; + + if (IsEqualGUID(Format, *pFormat)) + return S_OK; + else + return S_FALSE; } HRESULT @@ -616,8 +1071,47 @@ STDMETHODCALLTYPE CKsProxy::SetTimeFormat( const GUID *pFormat) { - OutputDebugStringW(L"CKsProxy::SetTimeFormat NotImplemented\n"); - return E_NOTIMPL; + KSPROPERTY Property; + ULONG BytesReturned, Index; + HRESULT hr; + + Property.Set = KSPROPSETID_MediaSeeking; + Property.Id = KSPROPERTY_MEDIASEEKING_TIMEFORMAT; + Property.Flags = KSPROPERTY_TYPE_SET; + + OutputDebugStringW(L"CKsProxy::SetTimeFormat\n"); + + hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pFormat, sizeof(GUID), &BytesReturned); + if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND)) + { + // check if plugins support it + for(Index = 0; Index < m_Plugins.size(); Index++) + { + hr = E_NOTIMPL; + // get plugin + IUnknown * Plugin = m_Plugins[Index]; + + if (!Plugin) + continue; + + // query for IMediaSeeking interface + IMediaSeeking *pSeek = NULL; + hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek); + if (FAILED(hr)) + { + //not supported + break; + } + // set time format + hr = pSeek->SetTimeFormat(pFormat); + // release IMediaSeeking interface + pSeek->Release(); + + if (FAILED(hr)) + break; + } + } + return hr; } HRESULT @@ -625,8 +1119,45 @@ STDMETHODCALLTYPE CKsProxy::GetDuration( LONGLONG *pDuration) { - OutputDebugStringW(L"CKsProxy::GetDuration NotImplemented\n"); - return E_NOTIMPL; + KSPROPERTY Property; + ULONG BytesReturned, Index; + HRESULT hr; + + Property.Set = KSPROPSETID_MediaSeeking; + Property.Id = KSPROPERTY_MEDIASEEKING_DURATION; + Property.Flags = KSPROPERTY_TYPE_GET; + + OutputDebugStringW(L"CKsProxy::GetDuration\n"); + + hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pDuration, sizeof(LONGLONG), &BytesReturned); + if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND)) + { + // check if plugins support it + for(Index = 0; Index < m_Plugins.size(); Index++) + { + hr = E_NOTIMPL; + // get plugin + IUnknown * Plugin = m_Plugins[Index]; + + if (!Plugin) + continue; + + // query for IMediaSeeking interface + IMediaSeeking *pSeek = NULL; + hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek); + if (SUCCEEDED(hr)) + { + // get duration + hr = pSeek->GetStopPosition(pDuration); + // release IMediaSeeking interface + pSeek->Release(); + + if (hr != S_FALSE) // plugin implements it + break; + } + } + } + return hr; } HRESULT @@ -634,8 +1165,45 @@ STDMETHODCALLTYPE CKsProxy::GetStopPosition( LONGLONG *pStop) { - OutputDebugStringW(L"CKsProxy::GetStopPosition NotImplemented\n"); - return E_NOTIMPL; + KSPROPERTY Property; + ULONG BytesReturned, Index; + HRESULT hr; + + Property.Set = KSPROPSETID_MediaSeeking; + Property.Id = KSPROPERTY_MEDIASEEKING_STOPPOSITION; + Property.Flags = KSPROPERTY_TYPE_GET; + + OutputDebugStringW(L"CKsProxy::GetStopPosition\n"); + + hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pStop, sizeof(LONGLONG), &BytesReturned); + if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND)) + { + // check if plugins support it + for(Index = 0; Index < m_Plugins.size(); Index++) + { + hr = E_NOTIMPL; + // get plugin + IUnknown * Plugin = m_Plugins[Index]; + + if (!Plugin) + continue; + + // query for IMediaSeeking interface + IMediaSeeking *pSeek = NULL; + hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek); + if (SUCCEEDED(hr)) + { + // get stop position + hr = pSeek->GetStopPosition(pStop); + // release IMediaSeeking interface + pSeek->Release(); + + if (hr != S_FALSE) // plugin implements it + break; + } + } + } + return hr; } HRESULT @@ -643,8 +1211,45 @@ STDMETHODCALLTYPE CKsProxy::GetCurrentPosition( LONGLONG *pCurrent) { - OutputDebugStringW(L"CKsProxy::GetCurrentPosition NotImplemented\n"); - return E_NOTIMPL; + KSPROPERTY Property; + ULONG BytesReturned, Index; + HRESULT hr; + + Property.Set = KSPROPSETID_MediaSeeking; + Property.Id = KSPROPERTY_MEDIASEEKING_POSITION; + Property.Flags = KSPROPERTY_TYPE_GET; + + OutputDebugStringW(L"CKsProxy::GetCurrentPosition\n"); + + hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pCurrent, sizeof(LONGLONG), &BytesReturned); + if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND)) + { + // check if plugins support it + for(Index = 0; Index < m_Plugins.size(); Index++) + { + hr = E_NOTIMPL; + // get plugin + IUnknown * Plugin = m_Plugins[Index]; + + if (!Plugin) + continue; + + // query for IMediaSeeking interface + IMediaSeeking *pSeek = NULL; + hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek); + if (SUCCEEDED(hr)) + { + // get current position + hr = pSeek->GetCurrentPosition(pCurrent); + // release IMediaSeeking interface + pSeek->Release(); + + if (hr != S_FALSE) // plugin implements it + break; + } + } + } + return hr; } HRESULT @@ -655,8 +1260,74 @@ CKsProxy::ConvertTimeFormat( LONGLONG Source, const GUID *pSourceFormat) { - OutputDebugStringW(L"CKsProxy::ConvertTimeFormat NotImplemented\n"); - return E_NOTIMPL; + KSP_TIMEFORMAT Property; + ULONG BytesReturned, Index; + GUID SourceFormat, TargetFormat; + HRESULT hr; + + Property.Property.Set = KSPROPSETID_MediaSeeking; + Property.Property.Id = KSPROPERTY_MEDIASEEKING_CONVERTTIMEFORMAT; + Property.Property.Flags = KSPROPERTY_TYPE_GET; + + OutputDebugStringW(L"CKsProxy::ConvertTimeFormat\n"); + + if (!pTargetFormat) + { + // get current format + hr = GetTimeFormat(&TargetFormat); + if (FAILED(hr)) + return hr; + + pTargetFormat = &TargetFormat; + } + + if (!pSourceFormat) + { + // get current format + hr = GetTimeFormat(&SourceFormat); + if (FAILED(hr)) + return hr; + + pSourceFormat = &SourceFormat; + } + + Property.SourceFormat = *pSourceFormat; + Property.TargetFormat = *pTargetFormat; + Property.Time = Source; + + + hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_TIMEFORMAT), (PVOID)pTarget, sizeof(LONGLONG), &BytesReturned); + if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND)) + { + //default error + hr = E_NOTIMPL; + + // check if plugins support it + for(Index = 0; Index < m_Plugins.size(); Index++) + { + // get plugin + IUnknown * Plugin = m_Plugins[Index]; + + if (!Plugin) + continue; + + // query for IMediaSeeking interface + IMediaSeeking *pSeek = NULL; + hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek); + if (SUCCEEDED(hr)) + { + // convert time format + hr = pSeek->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat); + // release IMediaSeeking interface + pSeek->Release(); + + if (hr != S_FALSE) // plugin implements it + break; + } + } + } + + return hr; } HRESULT @@ -667,8 +1338,71 @@ CKsProxy::SetPositions( LONGLONG *pStop, DWORD dwStopFlags) { - OutputDebugStringW(L"CKsProxy::SetPositions NotImplemented\n"); - return E_NOTIMPL; + KSPROPERTY Property; + KSPROPERTY_POSITIONS Positions; + ULONG BytesReturned, Index; + HRESULT hr; + + Property.Set = KSPROPSETID_MediaSeeking; + Property.Id = KSPROPERTY_MEDIASEEKING_POSITIONS; + Property.Flags = KSPROPERTY_TYPE_SET; + + Positions.Current = *pCurrent; + Positions.CurrentFlags = (KS_SEEKING_FLAGS)dwCurrentFlags; + Positions.Stop = *pStop; + Positions.StopFlags = (KS_SEEKING_FLAGS)dwStopFlags; + + OutputDebugStringW(L"CKsProxy::SetPositions\n"); + + hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&Positions, sizeof(KSPROPERTY_POSITIONS), &BytesReturned); + if (SUCCEEDED(hr)) + { + if (dwCurrentFlags & AM_SEEKING_ReturnTime) + { + // retrieve current position + hr = GetCurrentPosition(pCurrent); + } + + if (SUCCEEDED(hr)) + { + if (dwStopFlags & AM_SEEKING_ReturnTime) + { + // retrieve current position + hr = GetStopPosition(pStop); + } + } + return hr; + } + if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND)) + { + hr = E_NOTIMPL; + + // check if plugins support it + for(Index = 0; Index < m_Plugins.size(); Index++) + { + // get plugin + IUnknown * Plugin = m_Plugins[Index]; + + if (!Plugin) + continue; + + // query for IMediaSeeking interface + IMediaSeeking *pSeek = NULL; + hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek); + if (SUCCEEDED(hr)) + { + // set positions + hr = pSeek->SetPositions(pCurrent, dwCurrentFlags, pStop, dwStopFlags); + // release IMediaSeeking interface + pSeek->Release(); + + if (FAILED(hr)) + break; + } + } + } + + return hr; } HRESULT @@ -677,8 +1411,15 @@ CKsProxy::GetPositions( LONGLONG *pCurrent, LONGLONG *pStop) { - OutputDebugStringW(L"CKsProxy::GetPositions NotImplemented\n"); - return E_NOTIMPL; + HRESULT hr; + + OutputDebugStringW(L"CKsProxy::GetPositions\n"); + + hr = GetCurrentPosition(pCurrent); + if (SUCCEEDED(hr)) + hr = GetStopPosition(pStop); + + return hr; } HRESULT @@ -687,8 +1428,52 @@ CKsProxy::GetAvailable( LONGLONG *pEarliest, LONGLONG *pLatest) { - OutputDebugStringW(L"CKsProxy::GetAvailable NotImplemented\n"); - return E_NOTIMPL; + KSPROPERTY Property; + KSPROPERTY_MEDIAAVAILABLE Media; + ULONG BytesReturned, Index; + HRESULT hr; + + Property.Set = KSPROPSETID_MediaSeeking; + Property.Id = KSPROPERTY_MEDIASEEKING_AVAILABLE; + Property.Flags = KSPROPERTY_TYPE_GET; + + OutputDebugStringW(L"CKsProxy::GetAvailable\n"); + + hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&Media, sizeof(KSPROPERTY_MEDIAAVAILABLE), &BytesReturned); + if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND)) + { + // check if plugins support it + for(Index = 0; Index < m_Plugins.size(); Index++) + { + hr = E_NOTIMPL; + // get plugin + IUnknown * Plugin = m_Plugins[Index]; + + if (!Plugin) + continue; + + // query for IMediaSeeking interface + IMediaSeeking *pSeek = NULL; + hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek); + if (SUCCEEDED(hr)) + { + // delegate call + hr = pSeek->GetAvailable(pEarliest, pLatest); + // release IMediaSeeking interface + pSeek->Release(); + + if (hr != S_FALSE) // plugin implements it + break; + } + } + } + else if (SUCCEEDED(hr)) + { + *pEarliest = Media.Earliest; + *pLatest = Media.Latest; + } + + return hr; } HRESULT @@ -696,7 +1481,6 @@ STDMETHODCALLTYPE CKsProxy::SetRate( double dRate) { - OutputDebugStringW(L"CKsProxy::SetRate NotImplemented\n"); return E_NOTIMPL; } @@ -705,7 +1489,6 @@ STDMETHODCALLTYPE CKsProxy::GetRate( double *pdRate) { - OutputDebugStringW(L"CKsProxy::GetRate NotImplemented\n"); return E_NOTIMPL; } @@ -714,8 +1497,45 @@ STDMETHODCALLTYPE CKsProxy::GetPreroll( LONGLONG *pllPreroll) { - OutputDebugStringW(L"CKsProxy::GetPreroll NotImplemented\n"); - return E_NOTIMPL; + KSPROPERTY Property; + ULONG BytesReturned, Index; + HRESULT hr; + + Property.Set = KSPROPSETID_MediaSeeking; + Property.Id = KSPROPERTY_MEDIASEEKING_PREROLL; + Property.Flags = KSPROPERTY_TYPE_GET; + + OutputDebugStringW(L"CKsProxy::GetPreroll\n"); + + hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pllPreroll, sizeof(LONGLONG), &BytesReturned); + if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND)) + { + // check if all plugins support it + for(Index = 0; Index < m_Plugins.size(); Index++) + { + // get plugin + IUnknown * Plugin = m_Plugins[Index]; + + if (!Plugin) + continue; + + // query for IMediaSeeking interface + IMediaSeeking *pSeek = NULL; + hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek); + if (SUCCEEDED(hr)) + { + // get preroll + hr = pSeek->GetPreroll(pllPreroll); + // release IMediaSeeking interface + pSeek->Release(); + + if (hr != S_FALSE) // plugin implements it + break; + } + } + hr = E_NOTIMPL; + } + return hr; } //------------------------------------------------------------------- @@ -922,8 +1742,23 @@ CKsProxy::CreateNodeInstance( REFGUID InterfaceId, LPVOID* Interface) { - OutputDebugStringW(L"CKsProxy::CreateNodeInstance NotImplemented\n"); - return E_NOTIMPL; + HRESULT hr; + + OutputDebugStringW(L"CKsProxy::CreateNodeInstance\n"); + + *Interface = NULL; + + if (IsEqualIID(IID_IUnknown, InterfaceId) || !UnkOuter) + { + hr = CKsNode_Constructor(UnkOuter, m_hDevice, NodeId, DesiredAccess, InterfaceId, Interface); + } + else + { + // interface not supported + hr = E_NOINTERFACE; + } + + return hr; } //------------------------------------------------------------------- @@ -1119,7 +1954,16 @@ CKsProxy::Disassociate(void) return NOERROR; } +//------------------------------------------------------------------- +// IKsClock interface +// +HANDLE +STDMETHODCALLTYPE +CKsProxy::KsGetClockHandle() +{ + return m_hClock; +} //------------------------------------------------------------------- @@ -1647,6 +2491,90 @@ STDMETHODCALLTYPE CKsProxy::SetSyncSource( IReferenceClock *pClock) { + HRESULT hr; + IKsClock *pKsClock; + HANDLE hClock, hPin; + ULONG Index; + IPin * pin; + IKsObject * pObject; + KSPROPERTY Property; + ULONG BytesReturned; + PIN_DIRECTION PinDir; + +// Plug In Distributor: IKsClock + + + // FIXME + // need locks + + if (!pClock) + return E_POINTER; + + hr = pClock->QueryInterface(IID_IKsClock, (void**)&pKsClock); + if (FAILED(hr)) + return hr; + + // get clock handle + hClock = pKsClock->KsGetClockHandle(); + if (!hClock || hClock == INVALID_HANDLE_VALUE) + { + // failed + pKsClock->Release(); + return E_FAIL; + } + + // distribute clock to all pins + for(Index = 0; Index < m_Pins.size(); Index++) + { + // get current pin + pin = m_Pins[Index]; + if (!pin) + continue; + + // get IKsObject interface + hr = pin->QueryInterface(IID_IKsObject, (void **)&pObject); + if (SUCCEEDED(hr)) + { + // get pin handle + hPin = pObject->KsGetObjectHandle(); + if (hPin != INVALID_HANDLE_VALUE && hPin) + { + // set clock + Property.Set = KSPROPSETID_Stream; + Property.Id = KSPROPERTY_STREAM_MASTERCLOCK; + Property.Flags = KSPROPERTY_TYPE_SET; + + // set master clock + hr = KsSynchronousDeviceControl(hPin, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)hClock, sizeof(HANDLE), &BytesReturned); + + if (FAILED(hr)) + { + if (hr != MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND) && + hr != MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND)) + { + // failed to set master clock + pKsClock->Release(); + pObject->Release(); + return hr; + } + } + } + // release IKsObject + pObject->Release(); + } + + // now get the direction + hr = pin->QueryDirection(&PinDir); + if (SUCCEEDED(hr)) + { + if (PinDir == PINDIR_OUTPUT) + { + // notify pin via + //CBaseStreamControl::SetSyncSource(pClock) + } + } + } + if (pClock) { pClock->AddRef(); @@ -1728,6 +2656,9 @@ CKsProxy::QueryFilterInfo( pInfo->achName[0] = L'\0'; pInfo->pGraph = m_pGraph; + if (m_pGraph) + m_pGraph->AddRef(); + return S_OK; } diff --git a/reactos/include/psdk/ks.h b/reactos/include/psdk/ks.h index 09b09b8cc4f..2249af3711a 100644 --- a/reactos/include/psdk/ks.h +++ b/reactos/include/psdk/ks.h @@ -724,8 +724,10 @@ typedef enum Properties/Methods/Events */ -#define KSPROPSETID_Stream \ +#define STATIC_KSPROPSETID_Stream\ 0x65aaba60L, 0x98ae, 0x11cf, 0xa1, 0x0d, 0x00, 0x20, 0xaf, 0xd1, 0x56, 0xe4 +DEFINE_GUIDSTRUCT("65aaba60-98ae-11cf-a10d-0020afd156e4", KSPROPSETID_Stream); +#define KSPROPSETID_Stream DEFINE_GUIDNAMED(KSPROPSETID_Stream) typedef enum { @@ -2091,7 +2093,7 @@ typedef struct { typedef struct _KSEVENT_ENTRY KSEVENT_ENTRY, *PKSEVENT_ENTRY; #if defined(_NTDDK_) - + typedef NTSTATUS (NTAPI *PFNKSADDEVENT)( IN PIRP Irp, IN PKSEVENTDATA EventData, From 347927735dcea4ec54b6010e6d9e05f2bf915999 Mon Sep 17 00:00:00 2001 From: Sylvain Petreolle Date: Sat, 13 Mar 2010 18:07:56 +0000 Subject: [PATCH 11/61] [ROSAPPS] Fix green build. svn path=/trunk/; revision=46177 --- rosapps/drivers/green/green.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rosapps/drivers/green/green.h b/rosapps/drivers/green/green.h index 9124081c453..4e32131ab35 100644 --- a/rosapps/drivers/green/green.h +++ b/rosapps/drivers/green/green.h @@ -1,6 +1,7 @@ #include -#include +#include #include +#include #include #define WINBASEAPI typedef struct _SECURITY_ATTRIBUTES SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES; From aaea6f034c35bb5f5acab590c1b870fafe5cdba1 Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Sat, 13 Mar 2010 18:45:51 +0000 Subject: [PATCH 12/61] [KSPROXY] - Add support for IPersist interface - Create clock handle when request for IKsClockPropertySet / IReferenceClock arrives - Print out requested format - Implement IPersist::GetClassID, IBaseFilter::QueryVendorInfo for CKsProxy svn path=/trunk/; revision=46180 --- reactos/dll/directx/ksproxy/proxy.cpp | 39 +++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/reactos/dll/directx/ksproxy/proxy.cpp b/reactos/dll/directx/ksproxy/proxy.cpp index 9faeb930ee0..5acea85a036 100644 --- a/reactos/dll/directx/ksproxy/proxy.cpp +++ b/reactos/dll/directx/ksproxy/proxy.cpp @@ -17,6 +17,7 @@ const GUID KSPROPSETID_MediaSeeking = {0xEE904F0CL, 0xD09B, 0x11D0, {0xAB, 0xE9, const GUID KSPROPSETID_Clock = {0xDF12A4C0L, 0xAC17, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}}; const GUID KSEVENTSETID_Clock = {0x364D8E20L, 0x62C7, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}}; const GUID KSPROPSETID_Stream = {0x65aaba60L, 0x98ae, 0x11cf, {0xa1, 0x0d, 0x00, 0x20, 0xaf, 0xd1, 0x56, 0xe4}}; +const GUID IID_IPersist = {0x0000010c, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}; #endif const GUID IID_IBDA_DeviceControl = {0xFD0A5AF3, 0xB41D, 0x11d2, {0x9C, 0x95, 0x00, 0xC0, 0x4F, 0x79, 0x71, 0xE0}}; @@ -234,6 +235,12 @@ CKsProxy::QueryInterface( reinterpret_cast(*Output)->AddRef(); return NOERROR; } + else if (IsEqualGUID(refiid, IID_IPersist)) + { + *Output = (IPersistStream*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } else if (IsEqualGUID(refiid, IID_IKsObject)) { *Output = (IKsObject*)(this); @@ -248,6 +255,13 @@ CKsProxy::QueryInterface( } else if (IsEqualGUID(refiid, IID_IReferenceClock)) { + if (!m_hClock) + { + HRESULT hr = CreateClockInstance(); + if (FAILED(hr)) + return hr; + } + *Output = (IReferenceClock*)(this); reinterpret_cast(*Output)->AddRef(); return NOERROR; @@ -290,6 +304,13 @@ CKsProxy::QueryInterface( } else if (IsEqualGUID(refiid, IID_IKsClockPropertySet)) { + if (!m_hClock) + { + HRESULT hr = CreateClockInstance(); + if (FAILED(hr)) + return hr; + } + *Output = (IKsClockPropertySet*)(this); reinterpret_cast(*Output)->AddRef(); return NOERROR; @@ -890,7 +911,11 @@ CKsProxy::IsFormatSupported( ULONG Index; HRESULT hr = S_FALSE; - OutputDebugStringW(L"CKsProxy::IsFormatSupported\n"); + WCHAR Buffer[100]; + LPOLESTR pstr; + StringFromCLSID(*pFormat, &pstr); + swprintf(Buffer, L"CKsProxy::IsFormatSupported %s\n",pstr); + OutputDebugStringW(Buffer); if (!pFormat) return E_POINTER; @@ -899,6 +924,9 @@ CKsProxy::IsFormatSupported( hr = GetMediaSeekingFormats(&FormatList); if (SUCCEEDED(hr)) { + swprintf(Buffer, L"CKsProxy::IsFormatSupported NumFormat %lu\n",FormatList->Count); + OutputDebugStringW(Buffer); + //iterate through format list pGuid = (LPGUID)(FormatList + 1); for(Index = 0; Index < FormatList->Count; Index++) @@ -2447,8 +2475,10 @@ STDMETHODCALLTYPE CKsProxy::GetClassID( CLSID *pClassID) { - OutputDebugStringW(L"CKsProxy::GetClassID : NotImplemented\n"); - return E_NOTIMPL; + OutputDebugStringW(L"CKsProxy::GetClassID\n"); + CopyMemory(pClassID, &CLSID_Proxy, sizeof(GUID)); + + return S_OK; } HRESULT @@ -2688,8 +2718,7 @@ STDMETHODCALLTYPE CKsProxy::QueryVendorInfo( LPWSTR *pVendorInfo) { - OutputDebugStringW(L"CKsProxy::QueryVendorInfo : NotImplemented\n"); - return E_NOTIMPL; + return StringFromCLSID(CLSID_Proxy, pVendorInfo); } //------------------------------------------------------------------- From 9b5054f453ea7df8b53436074901c98ef8223a04 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 13 Mar 2010 19:19:24 +0000 Subject: [PATCH 13/61] - Handle ACPI_RESOURCE_TYPE_EXTENDED_IRQ and ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64 svn path=/trunk/; revision=46181 --- reactos/drivers/bus/acpi/buspdo.c | 139 ++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/reactos/drivers/bus/acpi/buspdo.c b/reactos/drivers/bus/acpi/buspdo.c index 47a350cda56..6fe0f864ef3 100644 --- a/reactos/drivers/bus/acpi/buspdo.c +++ b/reactos/drivers/bus/acpi/buspdo.c @@ -623,6 +623,12 @@ Bus_PDO_QueryResources( { switch (resource->Type) { + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + { + ACPI_RESOURCE_EXTENDED_IRQ *irq_data = (ACPI_RESOURCE_EXTENDED_IRQ*) &resource->Data; + NumberOfResources += irq_data->InterruptCount; + break; + } case ACPI_RESOURCE_TYPE_IRQ: { ACPI_RESOURCE_IRQ *irq_data = (ACPI_RESOURCE_IRQ*) &resource->Data; @@ -638,6 +644,7 @@ Bus_PDO_QueryResources( case ACPI_RESOURCE_TYPE_ADDRESS16: case ACPI_RESOURCE_TYPE_ADDRESS32: case ACPI_RESOURCE_TYPE_ADDRESS64: + case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: case ACPI_RESOURCE_TYPE_MEMORY24: case ACPI_RESOURCE_TYPE_MEMORY32: case ACPI_RESOURCE_TYPE_IO: @@ -676,6 +683,25 @@ Bus_PDO_QueryResources( { switch (resource->Type) { + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + { + ACPI_RESOURCE_EXTENDED_IRQ *irq_data = (ACPI_RESOURCE_EXTENDED_IRQ*) &resource->Data; + for (i = 0; i < irq_data->InterruptCount; i++) + { + ResourceDescriptor->Type = CmResourceTypeInterrupt; + + ResourceDescriptor->ShareDisposition = + (irq_data->Sharable == ACPI_SHARED ? CmResourceShareShared : CmResourceShareDeviceExclusive); + ResourceDescriptor->Flags = + (irq_data->Triggering == ACPI_LEVEL_SENSITIVE ? CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE : CM_RESOURCE_INTERRUPT_LATCHED); + ResourceDescriptor->u.Interrupt.Level = irq_data->Interrupts[i]; + ResourceDescriptor->u.Interrupt.Vector = 0; + ResourceDescriptor->u.Interrupt.Affinity = (KAFFINITY)(-1); + + ResourceDescriptor++; + } + break; + } case ACPI_RESOURCE_TYPE_IRQ: { ACPI_RESOURCE_IRQ *irq_data = (ACPI_RESOURCE_IRQ*) &resource->Data; @@ -865,6 +891,49 @@ Bus_PDO_QueryResources( ResourceDescriptor++; break; } + case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: + { + ACPI_RESOURCE_EXTENDED_ADDRESS64 *addr64_data = (ACPI_RESOURCE_EXTENDED_ADDRESS64*) &resource->Data; + if (addr64_data->ResourceType == ACPI_BUS_NUMBER_RANGE) + { + DPRINT1("64-bit bus address is not supported!\n"); + ResourceDescriptor->Type = CmResourceTypeBusNumber; + ResourceDescriptor->ShareDisposition = CmResourceShareShared; + ResourceDescriptor->Flags = 0; + ResourceDescriptor->u.BusNumber.Start = (ULONG)addr64_data->Minimum; + ResourceDescriptor->u.BusNumber.Length = addr64_data->AddressLength; + } + else if (addr64_data->ResourceType == ACPI_IO_RANGE) + { + ResourceDescriptor->Type = CmResourceTypePort; + ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO; + if (addr64_data->Decode == ACPI_POS_DECODE) + ResourceDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE; + ResourceDescriptor->u.Port.Start.QuadPart = addr64_data->Minimum; + ResourceDescriptor->u.Port.Length = addr64_data->AddressLength; + } + else + { + ResourceDescriptor->Type = CmResourceTypeMemory; + ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + ResourceDescriptor->Flags = 0; + if (addr64_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY) + ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + switch (addr64_data->Info.Mem.Caching) + { + case ACPI_CACHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break; + case ACPI_WRITE_COMBINING_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break; + case ACPI_PREFETCHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break; + } + ResourceDescriptor->u.Memory.Start.QuadPart = addr64_data->Minimum; + ResourceDescriptor->u.Memory.Length = addr64_data->AddressLength; + } + ResourceDescriptor++; + break; + } case ACPI_RESOURCE_TYPE_MEMORY24: { ACPI_RESOURCE_MEMORY24 *mem24_data = (ACPI_RESOURCE_MEMORY24*) &resource->Data; @@ -968,6 +1037,12 @@ Bus_PDO_QueryResourceRequirements( { switch (resource->Type) { + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + { + ACPI_RESOURCE_EXTENDED_IRQ *irq_data = (ACPI_RESOURCE_EXTENDED_IRQ*) &resource->Data; + NumberOfResources += irq_data->InterruptCount; + break; + } case ACPI_RESOURCE_TYPE_IRQ: { ACPI_RESOURCE_IRQ *irq_data = (ACPI_RESOURCE_IRQ*) &resource->Data; @@ -983,6 +1058,7 @@ Bus_PDO_QueryResourceRequirements( case ACPI_RESOURCE_TYPE_ADDRESS16: case ACPI_RESOURCE_TYPE_ADDRESS32: case ACPI_RESOURCE_TYPE_ADDRESS64: + case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: case ACPI_RESOURCE_TYPE_MEMORY24: case ACPI_RESOURCE_TYPE_MEMORY32: case ACPI_RESOURCE_TYPE_IO: @@ -1021,6 +1097,22 @@ Bus_PDO_QueryResourceRequirements( { switch (resource->Type) { + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + { + ACPI_RESOURCE_EXTENDED_IRQ *irq_data = (ACPI_RESOURCE_EXTENDED_IRQ*) &resource->Data; + for (i = 0; i < irq_data->InterruptCount; i++) + { + RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED; + RequirementDescriptor->Type = CmResourceTypeInterrupt; + RequirementDescriptor->ShareDisposition = (irq_data->Sharable == ACPI_SHARED ? CmResourceShareShared : CmResourceShareDeviceExclusive); + RequirementDescriptor->Flags =(irq_data->Triggering == ACPI_LEVEL_SENSITIVE ? CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE : CM_RESOURCE_INTERRUPT_LATCHED); + RequirementDescriptor->u.Interrupt.MinimumVector = + RequirementDescriptor->u.Interrupt.MaximumVector = irq_data->Interrupts[i]; + + RequirementDescriptor++; + } + break; + } case ACPI_RESOURCE_TYPE_IRQ: { ACPI_RESOURCE_IRQ *irq_data = (ACPI_RESOURCE_IRQ*) &resource->Data; @@ -1225,6 +1317,53 @@ Bus_PDO_QueryResourceRequirements( RequirementDescriptor++; break; } + case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: + { + ACPI_RESOURCE_EXTENDED_ADDRESS64 *addr64_data = (ACPI_RESOURCE_EXTENDED_ADDRESS64*) &resource->Data; + RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED; + if (addr64_data->ResourceType == ACPI_BUS_NUMBER_RANGE) + { + DPRINT1("64-bit bus address is not supported!\n"); + RequirementDescriptor->Type = CmResourceTypeBusNumber; + RequirementDescriptor->ShareDisposition = CmResourceShareShared; + RequirementDescriptor->Flags = 0; + RequirementDescriptor->u.BusNumber.MinBusNumber = (ULONG)addr64_data->Minimum; + RequirementDescriptor->u.BusNumber.MaxBusNumber = (ULONG)addr64_data->Maximum; + RequirementDescriptor->u.BusNumber.Length = addr64_data->AddressLength; + } + else if (addr64_data->ResourceType == ACPI_IO_RANGE) + { + RequirementDescriptor->Type = CmResourceTypePort; + RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + RequirementDescriptor->Flags = CM_RESOURCE_PORT_IO; + if (addr64_data->Decode == ACPI_POS_DECODE) + RequirementDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE; + RequirementDescriptor->u.Port.MinimumAddress.QuadPart = addr64_data->Minimum; + RequirementDescriptor->u.Port.MaximumAddress.QuadPart = addr64_data->Maximum; + RequirementDescriptor->u.Port.Length = addr64_data->AddressLength; + } + else + { + RequirementDescriptor->Type = CmResourceTypeMemory; + RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + RequirementDescriptor->Flags = 0; + if (addr64_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY) + RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + switch (addr64_data->Info.Mem.Caching) + { + case ACPI_CACHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break; + case ACPI_WRITE_COMBINING_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break; + case ACPI_PREFETCHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break; + } + RequirementDescriptor->u.Memory.MinimumAddress.QuadPart = addr64_data->Minimum; + RequirementDescriptor->u.Memory.MaximumAddress.QuadPart = addr64_data->Maximum; + RequirementDescriptor->u.Memory.Length = addr64_data->AddressLength; + } + RequirementDescriptor++; + break; + } case ACPI_RESOURCE_TYPE_MEMORY24: { ACPI_RESOURCE_MEMORY24 *mem24_data = (ACPI_RESOURCE_MEMORY24*) &resource->Data; From 1c571af17a91de0f9d1f30e4595ad7d7c8de67c1 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 13 Mar 2010 19:38:49 +0000 Subject: [PATCH 14/61] [NTOSKRNL] - Don't set the RTL_QUERY_REGISTRY_REQUIRED flag for the Service key entry of the query table because it will cause RtlQueryRegistryValues to fail if the service key is absent which we don't want because we handle that case later svn path=/trunk/; revision=46182 --- reactos/ntoskrnl/io/pnpmgr/pnpmgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reactos/ntoskrnl/io/pnpmgr/pnpmgr.c b/reactos/ntoskrnl/io/pnpmgr/pnpmgr.c index 890fd60d12a..e8418893452 100644 --- a/reactos/ntoskrnl/io/pnpmgr/pnpmgr.c +++ b/reactos/ntoskrnl/io/pnpmgr/pnpmgr.c @@ -1893,7 +1893,7 @@ IopActionConfigureChildServices(PDEVICE_NODE DeviceNode, RtlInitUnicodeString(&ClassGUID, NULL); QueryTable[0].Name = L"Service"; - QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; + QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; QueryTable[0].EntryContext = Service; QueryTable[1].Name = L"ClassGUID"; From a7ed29ec5af175678692e52b83a595aaaec5f1fd Mon Sep 17 00:00:00 2001 From: Sir Richard Date: Sat, 13 Mar 2010 20:42:53 +0000 Subject: [PATCH 15/61] [DDK]: Fix Wmilib.h. svn path=/trunk/; revision=46185 --- reactos/include/ddk/wmilib.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/reactos/include/ddk/wmilib.h b/reactos/include/ddk/wmilib.h index 18d63aded76..22bb087a2a7 100644 --- a/reactos/include/ddk/wmilib.h +++ b/reactos/include/ddk/wmilib.h @@ -22,17 +22,6 @@ typedef struct _WMIGUIDREGINFO { ULONG Flags; } WMIGUIDREGINFO, *PWMIGUIDREGINFO; -typedef struct _WMILIB_CONTEXT { - ULONG GuidCount; - PWMIGUIDREGINFO GuidList; - PWMI_QUERY_REGINFO QueryWmiRegInfo; - PWMI_QUERY_DATABLOCK QueryWmiDataBlock; - PWMI_SET_DATABLOCK SetWmiDataBlock; - PWMI_SET_DATAITEM SetWmiDataItem; - PWMI_EXECUTE_METHOD ExecuteWmiMethod; - PWMI_FUNCTION_CONTROL WmiFunctionControl; -} WMILIB_CONTEXT, *PWMILIB_CONTEXT; - typedef NTSTATUS (NTAPI *PWMI_QUERY_REGINFO) ( IN OUT PDEVICE_OBJECT DeviceObject, @@ -91,6 +80,17 @@ typedef NTSTATUS IN WMIENABLEDISABLECONTROL Function, IN BOOLEAN Enable); +typedef struct _WMILIB_CONTEXT { + ULONG GuidCount; + PWMIGUIDREGINFO GuidList; + PWMI_QUERY_REGINFO QueryWmiRegInfo; + PWMI_QUERY_DATABLOCK QueryWmiDataBlock; + PWMI_SET_DATABLOCK SetWmiDataBlock; + PWMI_SET_DATAITEM SetWmiDataItem; + PWMI_EXECUTE_METHOD ExecuteWmiMethod; + PWMI_FUNCTION_CONTROL WmiFunctionControl; +} WMILIB_CONTEXT, *PWMILIB_CONTEXT; + #if (NTDDI_VERSION >= NTDDI_WIN2K) NTSTATUS From 08213e98d463b92f1561fcfdff311f41d07b6eb9 Mon Sep 17 00:00:00 2001 From: Sir Richard Date: Sat, 13 Mar 2010 20:49:13 +0000 Subject: [PATCH 16/61] [DDK]: Add ACPI_INTERFACE_STANDARD2. ACPI_INTERFACE_STANDARD is left as an excercise to the reader. svn path=/trunk/; revision=46187 --- reactos/include/ddk/wdm.h | 84 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/reactos/include/ddk/wdm.h b/reactos/include/ddk/wdm.h index 759cd447376..319e62dd35f 100644 --- a/reactos/include/ddk/wdm.h +++ b/reactos/include/ddk/wdm.h @@ -3395,6 +3395,90 @@ typedef struct _PCI_DEVICE_PRESENT_INTERFACE { PPCI_IS_DEVICE_PRESENT_EX IsDevicePresentEx; } PCI_DEVICE_PRESENT_INTERFACE, *PPCI_DEVICE_PRESENT_INTERFACE; +typedef +BOOLEAN +(*PGPE_SERVICE_ROUTINE2)( + PVOID ObjectContext, + PVOID ServiceContext +); + +typedef +NTSTATUS +(*PGPE_CONNECT_VECTOR2)( + PVOID Context, + ULONG GpeNumber, + KINTERRUPT_MODE Mode, + BOOLEAN Shareable, + PGPE_SERVICE_ROUTINE2 ServiceRoutine, + PVOID ServiceContext, + PVOID *ObjectContext +); + +typedef +NTSTATUS +(*PGPE_DISCONNECT_VECTOR2)( + PVOID Context, + PVOID ObjectContext +); + +typedef +NTSTATUS +(*PGPE_ENABLE_EVENT2)( + PVOID Context, + PVOID ObjectContext +); + +typedef +NTSTATUS +(*PGPE_DISABLE_EVENT2)( + PVOID Context, + PVOID ObjectContext +); + +typedef +NTSTATUS +(*PGPE_CLEAR_STATUS2)( + PVOID Context, + PVOID ObjectContext +); + +typedef +VOID +(*PDEVICE_NOTIFY_CALLBACK2)( + PVOID NotificationContext, + ULONG NotifyCode +); + +typedef +NTSTATUS +(*PREGISTER_FOR_DEVICE_NOTIFICATIONS2)( + PVOID Context, + PDEVICE_NOTIFY_CALLBACK2 NotificationHandler, + PVOID NotificationContext +); + +typedef +VOID +(*PUNREGISTER_FOR_DEVICE_NOTIFICATIONS2)( + PVOID Context +); + +typedef struct +{ + USHORT Size; + USHORT Version; + PVOID Context; + PINTERFACE_REFERENCE InterfaceReference; + PINTERFACE_DEREFERENCE InterfaceDereference; + PGPE_CONNECT_VECTOR2 GpeConnectVector; + PGPE_DISCONNECT_VECTOR2 GpeDisconnectVector; + PGPE_ENABLE_EVENT2 GpeEnableEvent; + PGPE_DISABLE_EVENT2 GpeDisableEvent; + PGPE_CLEAR_STATUS2 GpeClearStatus; + PREGISTER_FOR_DEVICE_NOTIFICATIONS2 RegisterForDeviceNotifications; + PUNREGISTER_FOR_DEVICE_NOTIFICATIONS2 UnregisterForDeviceNotifications; +} ACPI_INTERFACE_STANDARD2, *PACPI_INTERFACE_STANDARD2; + typedef struct _DEVICE_CAPABILITIES { USHORT Size; USHORT Version; From 78f8948c0f8b0675cf6b29ffb06b7bd3eb404d5b Mon Sep 17 00:00:00 2001 From: Sir Richard Date: Sat, 13 Mar 2010 21:06:22 +0000 Subject: [PATCH 17/61] [CMBATT]: ACPI-compliant. WMI-managed Control Method Battery Driver. Step 1: Define the interface and ACPI/PnP structures. The rest of the code is in my WC but needs ACPI Eval IOCTL support in ReactOS before it'll work. svn path=/trunk/; revision=46188 --- reactos/drivers/bus/acpi/acpi.rbuild | 3 + reactos/drivers/bus/acpi/cmbatt/cmbatt.c | 149 ++++++++++++++++++ reactos/drivers/bus/acpi/cmbatt/cmbatt.h | 105 ++++++++++++ reactos/drivers/bus/acpi/cmbatt/cmbatt.rbuild | 13 ++ reactos/drivers/bus/acpi/cmbatt/cmbatt.rc | 5 + reactos/drivers/bus/acpi/cmbatt/cmbpnp.c | 104 ++++++++++++ reactos/drivers/bus/acpi/cmbatt/cmbwmi.c | 94 +++++++++++ reactos/drivers/bus/acpi/cmbatt/cmexec.c | 100 ++++++++++++ 8 files changed, 573 insertions(+) create mode 100644 reactos/drivers/bus/acpi/cmbatt/cmbatt.c create mode 100644 reactos/drivers/bus/acpi/cmbatt/cmbatt.h create mode 100644 reactos/drivers/bus/acpi/cmbatt/cmbatt.rbuild create mode 100644 reactos/drivers/bus/acpi/cmbatt/cmbatt.rc create mode 100644 reactos/drivers/bus/acpi/cmbatt/cmbpnp.c create mode 100644 reactos/drivers/bus/acpi/cmbatt/cmbwmi.c create mode 100644 reactos/drivers/bus/acpi/cmbatt/cmexec.c diff --git a/reactos/drivers/bus/acpi/acpi.rbuild b/reactos/drivers/bus/acpi/acpi.rbuild index f2b6a13cbca..cbc124a26f5 100644 --- a/reactos/drivers/bus/acpi/acpi.rbuild +++ b/reactos/drivers/bus/acpi/acpi.rbuild @@ -4,6 +4,9 @@ + + + diff --git a/reactos/drivers/bus/acpi/cmbatt/cmbatt.c b/reactos/drivers/bus/acpi/cmbatt/cmbatt.c new file mode 100644 index 00000000000..1957597a678 --- /dev/null +++ b/reactos/drivers/bus/acpi/cmbatt/cmbatt.c @@ -0,0 +1,149 @@ +/* + * PROJECT: ReactOS ACPI-Compliant Control Method Battery + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: boot/drivers/bus/acpi/cmbatt/cmbatt.c + * PURPOSE: Main Initialization Code and IRP Handling + * PROGRAMMERS: ReactOS Portable Systems Group + */ + +/* INCLUDES *******************************************************************/ + +#include "cmbatt.h" + +/* GLOBALS ********************************************************************/ + +ULONG CmBattDebug; + +/* FUNCTIONS ******************************************************************/ + +VOID +NTAPI +CmBattPowerCallBack(PCMBATT_DEVICE_EXTENSION DeviceExtension, + PVOID Argument1, + PVOID Argument2) +{ + UNIMPLEMENTED; +} + +VOID +NTAPI +CmBattWakeDpc(PKDPC Dpc, + PCMBATT_DEVICE_EXTENSION FdoExtension, + PVOID SystemArgument1, + PVOID SystemArgument2) +{ + UNIMPLEMENTED; +} + +VOID +NTAPI +CmBattNotifyHandler(PCMBATT_DEVICE_EXTENSION DeviceExtension, + ULONG NotifyValue) +{ + UNIMPLEMENTED; +} + +VOID +NTAPI +CmBattUnload(PDEVICE_OBJECT DeviceObject) +{ + UNIMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattVerifyStaticInfo(ULONG StaData, + ULONG BatteryTag) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattOpenClose(PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattIoctl(PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattQueryTag(PCMBATT_DEVICE_EXTENSION DeviceExtension, + PULONG BatteryTag) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattDisableStatusNotify(PCMBATT_DEVICE_EXTENSION DeviceExtension) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattSetStatusNotify(PCMBATT_DEVICE_EXTENSION DeviceExtension, + ULONG BatteryTag, + PBATTERY_NOTIFY BatteryNotify) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattGetBatteryStatus(PCMBATT_DEVICE_EXTENSION DeviceExtension, + ULONG BatteryTag) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattQueryInformation(PCMBATT_DEVICE_EXTENSION DeviceExtension, + ULONG BatteryTag, + BATTERY_QUERY_INFORMATION_LEVEL Level, + OPTIONAL LONG AtRate, + PVOID Buffer, + ULONG BufferLength, + PULONG ReturnedLength) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattQueryStatus(PCMBATT_DEVICE_EXTENSION DeviceExtension, + ULONG BatteryTag, + PBATTERY_STATUS BatteryStatus) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +DriverEntry(PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +/* EOF */ diff --git a/reactos/drivers/bus/acpi/cmbatt/cmbatt.h b/reactos/drivers/bus/acpi/cmbatt/cmbatt.h new file mode 100644 index 00000000000..0443c4c86bb --- /dev/null +++ b/reactos/drivers/bus/acpi/cmbatt/cmbatt.h @@ -0,0 +1,105 @@ +/* + * PROJECT: ReactOS ACPI-Compliant Control Method Battery + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: boot/drivers/bus/acpi/cmbatt/cmbatt.h + * PURPOSE: Main Header File + * PROGRAMMERS: ReactOS Portable Systems Group + */ + +#include +#include +#include +#include +#include +#include + +#define CMBATT_GENERIC_STATUS 0x01 +#define CMBATT_GENERIC_INFO 0x02 +#define CMBATT_GENERIC_WARNING 0x04 +#define CMBATT_ACPI_WARNING 0x08 +#define CMBATT_POWER_INFO 0x10 +#define CMBATT_PNP_INFO 0x20 +#define CMBATT_ACPI_ENTRY_EXIT 0x40 +#define CMBATT_PNP_ENTRY_EXIT 0x200 +#define CMBATT_ACPI_ASSERT 0x400 + +typedef enum _CMBATT_EXTENSION_TYPE +{ + CmBattAcAdapter, + CmBattBattery +} CMBATT_EXTENSION_TYPE; + +typedef struct _ACPI_BST_DATA +{ + ULONG State; + ULONG PresentRate; + ULONG RemainingCapacity; + ULONG PresentVoltage; +} ACPI_BST_DATA, *PACPI_BST_DATA; + +typedef struct _ACPI_BIF_DATA +{ + ULONG PowerUnit; + ULONG DesignCapacity; + ULONG LastFullCapacity; + ULONG BatteryTechnology; + ULONG DesignVoltage; + ULONG DesignCapacityWarning; + ULONG DesignCapacityLow; + ULONG BatteryCapacityGranularity1; + ULONG BatteryCapacityGranularity2; + CHAR ModelNumber[256]; + CHAR SerialNubmer[256]; + CHAR BatteryType[256]; + CHAR OemInfo[256]; +} ACPI_BIF_DATA, *PACPI_BIF_DATA; + +typedef struct _CMBATT_DEVICE_EXTENSION +{ + CMBATT_EXTENSION_TYPE FdoType; + PDEVICE_OBJECT DeviceObject; + PDEVICE_OBJECT FdoDeviceObject; + PDEVICE_OBJECT PdoDeviceObject; + PDEVICE_OBJECT AttachedDevice; + FAST_MUTEX FastMutex; + ULONG HandleCount; + PIRP PowerIrp; + POWER_STATE PowerState; + WMILIB_CONTEXT WmiLibInfo; + ULONG WaitWakeEnable; + ULONG WmiCount; + KEVENT WmiEvent; + ULONG DeviceId; + PUNICODE_STRING DeviceName; + ACPI_INTERFACE_STANDARD2 AcpiInterface; + BOOLEAN DelayAr; + BOOLEAN DelayedArFlag; + PVOID ClassData; + BOOLEAN Started; + BOOLEAN NotifySent; + ULONG ArLock; + ULONG TagData; + ULONG Tag; + ULONG ModelNumberLength; + PCHAR ModelNumber; + ULONG SerialNumberLength; + PCHAR SerialNumber; + ULONG OemInfoLength; + PCHAR OemInfo; + ACPI_BST_DATA BstData; + ACPI_BIF_DATA BifData; + ULONG Id; + ULONG State; + ULONG RemainingCapacity; + ULONG PresentVoltage; + ULONG Rate; + BATTERY_INFORMATION StaticBatteryInformation; + ULONG BatteryCapacityGranularity1; + ULONG BatteryCapacityGranularity2; + BOOLEAN TripPointSet; + ULONG TripPointValue; + ULONG TripPointOld; + ULONGLONG InterruptTime; +} CMBATT_DEVICE_EXTENSION, *PCMBATT_DEVICE_EXTENSION; + +/* EOF */ diff --git a/reactos/drivers/bus/acpi/cmbatt/cmbatt.rbuild b/reactos/drivers/bus/acpi/cmbatt/cmbatt.rbuild new file mode 100644 index 00000000000..c8a09e31b44 --- /dev/null +++ b/reactos/drivers/bus/acpi/cmbatt/cmbatt.rbuild @@ -0,0 +1,13 @@ + + + + ntoskrnl + hal + battc + . + cmbatt.c + cmexec.c + cmbpnp.c + cmbwmi.c + cmbatt.rc + diff --git a/reactos/drivers/bus/acpi/cmbatt/cmbatt.rc b/reactos/drivers/bus/acpi/cmbatt/cmbatt.rc new file mode 100644 index 00000000000..d1542f9019e --- /dev/null +++ b/reactos/drivers/bus/acpi/cmbatt/cmbatt.rc @@ -0,0 +1,5 @@ +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "Control Method Battery Miniclass Driver\0" +#define REACTOS_STR_INTERNAL_NAME "cmbatt\0" +#define REACTOS_STR_ORIGINAL_FILENAME "cmbatt.sys\0" +#include diff --git a/reactos/drivers/bus/acpi/cmbatt/cmbpnp.c b/reactos/drivers/bus/acpi/cmbatt/cmbpnp.c new file mode 100644 index 00000000000..fee3ec80b47 --- /dev/null +++ b/reactos/drivers/bus/acpi/cmbatt/cmbpnp.c @@ -0,0 +1,104 @@ +/* + * PROJECT: ReactOS ACPI-Compliant Control Method Battery + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: boot/drivers/bus/acpi/cmbatt/cmbpnp.c + * PURPOSE: Plug-and-Play IOCTL/IRP Handling + * PROGRAMMERS: ReactOS Portable Systems Group + */ + +/* INCLUDES *******************************************************************/ + +#include "cmbatt.h" + +/* FUNCTIONS ******************************************************************/ + +NTSTATUS +NTAPI +CmBattIoCompletion(PDEVICE_OBJECT DeviceObject, + PIRP Irp, + PKEVENT Event) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattGetAcpiInterfaces(PDEVICE_OBJECT DeviceObject, + PACPI_INTERFACE_STANDARD2 *AcpiInterface) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +VOID +NTAPI +CmBattDestroyFdo(PDEVICE_OBJECT DeviceObject) +{ + UNIMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattRemoveDevice(PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattPowerDispatch(PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattCreateFdo(PDRIVER_OBJECT DriverObject, + PDEVICE_OBJECT DeviceObject, + ULONG DeviceExtensionSize, + PDEVICE_OBJECT *NewDeviceObject) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattPnpDispatch(PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattAddBattery(PDRIVER_OBJECT DriverObject, + PDEVICE_OBJECT DeviceObject) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattAddAcAdapter(PDRIVER_OBJECT DriverObject, + PDEVICE_OBJECT DeviceObject) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS NTAPI CmBattAddDevice(PDRIVER_OBJECT DriverObject, + PDEVICE_OBJECT DeviceObject) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +/* EOF */ diff --git a/reactos/drivers/bus/acpi/cmbatt/cmbwmi.c b/reactos/drivers/bus/acpi/cmbatt/cmbwmi.c new file mode 100644 index 00000000000..848c920dd0b --- /dev/null +++ b/reactos/drivers/bus/acpi/cmbatt/cmbwmi.c @@ -0,0 +1,94 @@ +/* + * PROJECT: ReactOS ACPI-Compliant Control Method Battery + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: boot/drivers/bus/acpi/cmbatt/cmbwmi.c + * PURPOSE: WMI Interface + * PROGRAMMERS: ReactOS Portable Systems Group + */ + +/* INCLUDES *******************************************************************/ + +#include "cmbatt.h" + +/* FUNCTIONS ******************************************************************/ + +NTSTATUS +NTAPI +CmBattQueryWmiRegInfo(PDEVICE_OBJECT DeviceObject, + PULONG RegFlags, + PUNICODE_STRING InstanceName, + PUNICODE_STRING *RegistryPath, + PUNICODE_STRING MofResourceName, + PDEVICE_OBJECT *Pdo) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattQueryWmiDataBlock(PDEVICE_OBJECT DeviceObject, + PIRP Irp, + ULONG GuidIndex, + ULONG InstanceIndex, + ULONG InstanceCount, + PULONG InstanceLengthArray, + ULONG BufferAvail, + PUCHAR Buffer) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattSetWmiDataBlock(PDEVICE_OBJECT DeviceObject, + PIRP Irp, + ULONG GuidIndex, + ULONG InstanceIndex, + ULONG BufferSize, + PUCHAR Buffer) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattSetWmiDataItem(PDEVICE_OBJECT DeviceObject, + PIRP Irp, + ULONG GuidIndex, + ULONG InstanceIndex, + ULONG DataItemId, + ULONG BufferSize, + PUCHAR Buffer) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattWmiDeRegistration(PCMBATT_DEVICE_EXTENSION DeviceExtension) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattWmiRegistration(PCMBATT_DEVICE_EXTENSION DeviceExtension) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattSystemControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +/* EOF */ diff --git a/reactos/drivers/bus/acpi/cmbatt/cmexec.c b/reactos/drivers/bus/acpi/cmbatt/cmexec.c new file mode 100644 index 00000000000..a41865c5e4c --- /dev/null +++ b/reactos/drivers/bus/acpi/cmbatt/cmexec.c @@ -0,0 +1,100 @@ +/* + * PROJECT: ReactOS ACPI-Compliant Control Method Battery + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: boot/drivers/bus/acpi/cmbatt/cmexec.c + * PURPOSE: ACPI Method Execution/Evaluation Glue + * PROGRAMMERS: ReactOS Portable Systems Group + */ + +/* INCLUDES *******************************************************************/ + +#include "cmbatt.h" + +/* FUNCTIONS ******************************************************************/ + +NTSTATUS +NTAPI +GetDwordElement(PACPI_METHOD_ARGUMENT Argument, + PULONG Value) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +GetStringElement(PACPI_METHOD_ARGUMENT Argument, + PCHAR Value) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattGetPsrData(PDEVICE_OBJECT DeviceObject, + PULONG PsrData) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattGetBifData(PCMBATT_DEVICE_EXTENSION DeviceExtension, + PACPI_BIF_DATA BifData) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattGetBstData(PCMBATT_DEVICE_EXTENSION DeviceExtension, + PACPI_BST_DATA BstData) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattGetStaData(PDEVICE_OBJECT DeviceObject, + PULONG StaData) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattGetUniqueId(PDEVICE_OBJECT DeviceObject, + PULONG UniqueId) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattSetTripPpoint(PCMBATT_DEVICE_EXTENSION DeviceExtension, + ULONG AlarmValue) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CmBattSendDownStreamIrp(PDEVICE_OBJECT DeviceObject, + ULONG IoControlCode, + PVOID InputBuffer, + ULONG InputBufferLength, + PACPI_EVAL_OUTPUT_BUFFER OutputBuffer, + ULONG OutputBufferLength) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +/* EOF */ From 9a46a4601184cbd1312674dde8bedddd34c0678e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Sat, 13 Mar 2010 22:56:41 +0000 Subject: [PATCH 18/61] [freeldr] Never suppose that buffer in UNICODE_STRING is null terminated. Fixes some random failures when loading drivers svn path=/trunk/; revision=46190 --- reactos/boot/freeldr/freeldr/windows/winldr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reactos/boot/freeldr/freeldr/windows/winldr.c b/reactos/boot/freeldr/freeldr/windows/winldr.c index 4ba7b1bcb29..f3f7cd199b7 100644 --- a/reactos/boot/freeldr/freeldr/windows/winldr.c +++ b/reactos/boot/freeldr/freeldr/windows/winldr.c @@ -232,7 +232,7 @@ WinLdrLoadDeviceDriver(PLOADER_PARAMETER_BLOCK LoaderBlock, PVOID DriverBase; // Separate the path to file name and directory path - sprintf(DriverPath, "%S", FilePath->Buffer); + snprintf(DriverPath, sizeof(DriverPath), "%wZ", FilePath); DriverNamePos = strrchr(DriverPath, '\\'); if (DriverNamePos != NULL) { @@ -261,7 +261,7 @@ WinLdrLoadDeviceDriver(PLOADER_PARAMETER_BLOCK LoaderBlock, } // It's not loaded, we have to load it - sprintf(FullPath,"%s%S", BootPath, FilePath->Buffer); + snprintf(FullPath, sizeof(FullPath), "%s%wZ", BootPath, FilePath); Status = WinLdrLoadImage(FullPath, LoaderBootDriver, &DriverBase); if (!Status) return FALSE; From c709d2abc9d73a52e7157a2694eb0fb22a14bdd5 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 13 Mar 2010 23:01:58 +0000 Subject: [PATCH 19/61] - Fix a typo in AcpiOsReadPciConfiguration and AcpiOsWritePciConfiguration - May fix ACPI on VMware svn path=/trunk/; revision=46192 --- reactos/drivers/bus/acpi/osl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reactos/drivers/bus/acpi/osl.c b/reactos/drivers/bus/acpi/osl.c index be26a0811f9..760c9cb83ad 100644 --- a/reactos/drivers/bus/acpi/osl.c +++ b/reactos/drivers/bus/acpi/osl.c @@ -470,7 +470,7 @@ AcpiOsReadPciConfiguration ( return AE_ERROR; slot.u.AsULONG = 0; - slot.u.bits.DeviceNumber = PciId->Bus; + slot.u.bits.DeviceNumber = PciId->Device; slot.u.bits.FunctionNumber = PciId->Function; DPRINT("AcpiOsReadPciConfiguration, slot=0x%X, func=0x%X\n", slot.u.AsULONG, Register); @@ -502,7 +502,7 @@ AcpiOsWritePciConfiguration ( return AE_ERROR; slot.u.AsULONG = 0; - slot.u.bits.DeviceNumber = PciId->Bus; + slot.u.bits.DeviceNumber = PciId->Device; slot.u.bits.FunctionNumber = PciId->Function; DPRINT("AcpiOsWritePciConfiguration, slot=0x%x\n", slot.u.AsULONG); From c39812d1b6af53ba29949bc0de37d81e8b9d587f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Sat, 13 Mar 2010 23:19:05 +0000 Subject: [PATCH 20/61] [ntoskrnl] Never suppose that buffer in UNICODE_STRING is null terminated. Fixes display artifacts on list of loaded drivers svn path=/trunk/; revision=46193 --- reactos/ntoskrnl/io/iomgr/driver.c | 37 +++++++++------------------- reactos/ntoskrnl/io/iomgr/drvrlist.c | 5 ++-- 2 files changed, 14 insertions(+), 28 deletions(-) diff --git a/reactos/ntoskrnl/io/iomgr/driver.c b/reactos/ntoskrnl/io/iomgr/driver.c index c9925d5eb28..a81c25ed371 100644 --- a/reactos/ntoskrnl/io/iomgr/driver.c +++ b/reactos/ntoskrnl/io/iomgr/driver.c @@ -158,35 +158,22 @@ IopGetDriverObject( VOID FASTCALL INIT_FUNCTION -IopDisplayLoadingMessage(PVOID ServiceName, - BOOLEAN Unicode) +IopDisplayLoadingMessage(PUNICODE_STRING ServiceName) { CHAR TextBuffer[256]; - PCHAR Extra = ".sys"; if (ExpInTextModeSetup) return; - if (Unicode) - { - if (wcsstr(_wcsupr(ServiceName), L".SYS")) Extra = ""; - sprintf(TextBuffer, - "%s%s%s\\%S%s\n", - KeLoaderBlock->ArcBootDeviceName, - KeLoaderBlock->NtBootPathName, - "System32\\Drivers", - (PWCHAR)ServiceName, - Extra); - } + RtlUpcaseUnicodeString(ServiceName, ServiceName, FALSE); + snprintf(TextBuffer, sizeof(TextBuffer), + "%s%s%s\\%wZ", + KeLoaderBlock->ArcBootDeviceName, + KeLoaderBlock->NtBootPathName, + "System32\\Drivers", + ServiceName); + if (!strstr(TextBuffer, ".sys")) + strcat(TextBuffer, ".sys\n"); else - { - if (strstr(_strupr(ServiceName), ".SYS")) Extra = ""; - sprintf(TextBuffer, - "%s%s%s\\%s%s\n", - KeLoaderBlock->ArcBootDeviceName, - KeLoaderBlock->NtBootPathName, - "System32\\Drivers", - (PCHAR)ServiceName, - Extra); - } + strcat(TextBuffer, "\n"); HalDisplayString(TextBuffer); } @@ -788,7 +775,7 @@ IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry) /* * Display 'Loading XXX...' message */ - IopDisplayLoadingMessage(ModuleName->Buffer, TRUE); + IopDisplayLoadingMessage(ModuleName); InbvIndicateProgress(); /* diff --git a/reactos/ntoskrnl/io/iomgr/drvrlist.c b/reactos/ntoskrnl/io/iomgr/drvrlist.c index 42b69c6e2bd..ecc9980db46 100644 --- a/reactos/ntoskrnl/io/iomgr/drvrlist.c +++ b/reactos/ntoskrnl/io/iomgr/drvrlist.c @@ -48,8 +48,7 @@ extern BOOLEAN NoGuiBoot; VOID FASTCALL INIT_FUNCTION -IopDisplayLoadingMessage(PVOID ServiceName, - BOOLEAN Unicode); +IopDisplayLoadingMessage(PUNICODE_STRING ServiceName); /* PRIVATE FUNCTIONS **********************************************************/ @@ -416,7 +415,7 @@ IopLoadDriver(PSERVICE Service) { NTSTATUS Status = STATUS_UNSUCCESSFUL; - IopDisplayLoadingMessage(Service->ServiceName.Buffer, TRUE); + IopDisplayLoadingMessage(&Service->ServiceName); Status = ZwLoadDriver(&Service->RegistryPath); IopBootLog(&Service->ImagePath, NT_SUCCESS(Status) ? TRUE : FALSE); if (!NT_SUCCESS(Status)) From ee46cddad7bc95b50c17ac7bc432f48c58965aca Mon Sep 17 00:00:00 2001 From: Eric Kohl Date: Sun, 14 Mar 2010 12:26:49 +0000 Subject: [PATCH 21/61] [EVENTLOG] - Set the current service status from the service control handler. - Fix type declarations. - ElfrOpenELA/ElfrRegisterEventSourceA: Do not call the Unicode functions because in this case it is easier to do things yourself. - Implement ElfrGetLogInformation partially. - Bind client to the EventLog Pipe. - Use RtlInitAnsiString and RtlInitUnicodeString instead of building strings manually. - GetEventLogInformation: Check for valid dwInfoLevel. svn path=/trunk/; revision=46199 --- reactos/base/services/eventlog/eventlog.c | 85 ++++++++++++----- reactos/base/services/eventlog/eventlog.h | 10 +- reactos/base/services/eventlog/rpc.c | 91 +++++++++---------- reactos/dll/win32/advapi32/service/eventlog.c | 62 +++++-------- 4 files changed, 138 insertions(+), 110 deletions(-) diff --git a/reactos/base/services/eventlog/eventlog.c b/reactos/base/services/eventlog/eventlog.c index 4f0120a662d..70663351ab5 100644 --- a/reactos/base/services/eventlog/eventlog.c +++ b/reactos/base/services/eventlog/eventlog.c @@ -21,20 +21,76 @@ static SERVICE_TABLE_ENTRYW ServiceTable[2] = { NULL, NULL } }; +SERVICE_STATUS ServiceStatus; +SERVICE_STATUS_HANDLE ServiceStatusHandle; + BOOL onLiveCD = FALSE; // On livecd events will go to debug output only HANDLE MyHeap = NULL; /* FUNCTIONS ****************************************************************/ +static VOID +UpdateServiceStatus(DWORD dwState) +{ + ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + ServiceStatus.dwCurrentState = dwState; + ServiceStatus.dwControlsAccepted = 0; + ServiceStatus.dwWin32ExitCode = 0; + ServiceStatus.dwServiceSpecificExitCode = 0; + ServiceStatus.dwCheckPoint = 0; + + if (dwState == SERVICE_START_PENDING || + dwState == SERVICE_STOP_PENDING || + dwState == SERVICE_PAUSE_PENDING || + dwState == SERVICE_CONTINUE_PENDING) + ServiceStatus.dwWaitHint = 10000; + else + ServiceStatus.dwWaitHint = 0; + + SetServiceStatus(ServiceStatusHandle, + &ServiceStatus); +} + static DWORD WINAPI ServiceControlHandler(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext) { - /* FIXME */ - DPRINT1("ServiceControlHandler() called (control code %lu)\n", dwControl); - return ERROR_SUCCESS; + DPRINT("ServiceControlHandler() called\n"); + + switch (dwControl) + { + case SERVICE_CONTROL_STOP: + DPRINT(" SERVICE_CONTROL_STOP received\n"); + UpdateServiceStatus(SERVICE_STOPPED); + return ERROR_SUCCESS; + + case SERVICE_CONTROL_PAUSE: + DPRINT(" SERVICE_CONTROL_PAUSE received\n"); + UpdateServiceStatus(SERVICE_PAUSED); + return ERROR_SUCCESS; + + case SERVICE_CONTROL_CONTINUE: + DPRINT(" SERVICE_CONTROL_CONTINUE received\n"); + UpdateServiceStatus(SERVICE_RUNNING); + return ERROR_SUCCESS; + + case SERVICE_CONTROL_INTERROGATE: + DPRINT(" SERVICE_CONTROL_INTERROGATE received\n"); + SetServiceStatus(ServiceStatusHandle, + &ServiceStatus); + return ERROR_SUCCESS; + + case SERVICE_CONTROL_SHUTDOWN: + DPRINT(" SERVICE_CONTROL_SHUTDOWN received\n"); + UpdateServiceStatus(SERVICE_STOPPED); + return ERROR_SUCCESS; + + default : + DPRINT1(" Control %lu received\n"); + return ERROR_CALL_NOT_IMPLEMENTED; + } } @@ -83,8 +139,6 @@ static VOID CALLBACK ServiceMain(DWORD argc, LPWSTR *argv) { - SERVICE_STATUS ServiceStatus; - SERVICE_STATUS_HANDLE ServiceStatusHandle; DWORD dwError; UNREFERENCED_PARAMETER(argc); @@ -102,31 +156,20 @@ ServiceMain(DWORD argc, return; } - ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; - ServiceStatus.dwCurrentState = SERVICE_START_PENDING; - ServiceStatus.dwControlsAccepted = 0; - ServiceStatus.dwWin32ExitCode = NO_ERROR; - ServiceStatus.dwServiceSpecificExitCode = 0; - ServiceStatus.dwCheckPoint = 0; - ServiceStatus.dwWaitHint = 2000; - - SetServiceStatus(ServiceStatusHandle, - &ServiceStatus); + UpdateServiceStatus(SERVICE_START_PENDING); dwError = ServiceInit(); if (dwError != ERROR_SUCCESS) { - DPRINT1("Service stopped\n"); - ServiceStatus.dwCurrentState = SERVICE_STOPPED; + DPRINT("Service stopped (dwError: %lu\n", dwError); + UpdateServiceStatus(SERVICE_START_PENDING); } else { - ServiceStatus.dwCurrentState = SERVICE_RUNNING; + DPRINT("Service started\n"); + UpdateServiceStatus(SERVICE_RUNNING); } - SetServiceStatus(ServiceStatusHandle, - &ServiceStatus); - DPRINT("ServiceMain() done\n"); } diff --git a/reactos/base/services/eventlog/eventlog.h b/reactos/base/services/eventlog/eventlog.h index 4b9c6a8c341..df0ab151c41 100644 --- a/reactos/base/services/eventlog/eventlog.h +++ b/reactos/base/services/eventlog/eventlog.h @@ -44,7 +44,8 @@ typedef struct _IO_ERROR_LPC #define ELF_LOGFILE_ARCHIVE_SET 8 /* FIXME: MSDN reads that the following two structs are in winnt.h. Are they? */ -typedef struct _EVENTLOGHEADER { +typedef struct _EVENTLOGHEADER +{ ULONG HeaderSize; ULONG Signature; ULONG MajorVersion; @@ -59,7 +60,8 @@ typedef struct _EVENTLOGHEADER { ULONG EndHeaderSize; } EVENTLOGHEADER, *PEVENTLOGHEADER; -typedef struct _EVENTLOGEOF { +typedef struct _EVENTLOGEOF +{ ULONG RecordSizeBeginning; ULONG Ones; ULONG Twos; @@ -72,13 +74,13 @@ typedef struct _EVENTLOGEOF { ULONG RecordSizeEnd; } EVENTLOGEOF, *PEVENTLOGEOF; -typedef struct +typedef struct _EVENT_OFFSET_INFO { ULONG EventNumber; ULONG EventOffset; } EVENT_OFFSET_INFO, *PEVENT_OFFSET_INFO; -typedef struct +typedef struct _LOGFILE { HANDLE hFile; EVENTLOGHEADER Header; diff --git a/reactos/base/services/eventlog/rpc.c b/reactos/base/services/eventlog/rpc.c index e3ef33d1611..d399d1e600f 100644 --- a/reactos/base/services/eventlog/rpc.c +++ b/reactos/base/services/eventlog/rpc.c @@ -480,45 +480,29 @@ NTSTATUS ElfrOpenELA( DWORD MinorVersion, IELF_HANDLE *LogHandle) { - UNICODE_STRING UNCServerNameW = { 0, 0, NULL }; - UNICODE_STRING ModuleNameW = { 0, 0, NULL }; - UNICODE_STRING RegModuleNameW = { 0, 0, NULL }; - NTSTATUS Status; + UNICODE_STRING ModuleNameW; - if (UNCServerName && - !RtlCreateUnicodeStringFromAsciiz(&UNCServerNameW, UNCServerName)) - { - return STATUS_NO_MEMORY; - } + if ((MajorVersion != 1) || (MinorVersion != 1)) + return STATUS_INVALID_PARAMETER; - if (ModuleName && - !RtlAnsiStringToUnicodeString(&ModuleNameW, (PANSI_STRING)ModuleName, TRUE)) - { - RtlFreeUnicodeString(&UNCServerNameW); - return STATUS_NO_MEMORY; - } + /* RegModuleName must be an empty string */ + if (RegModuleName->Length > 0) + return STATUS_INVALID_PARAMETER; - if (RegModuleName && - !RtlAnsiStringToUnicodeString(&RegModuleNameW, (PANSI_STRING)RegModuleName, TRUE)) - { - RtlFreeUnicodeString(&UNCServerNameW); - RtlFreeUnicodeString(&ModuleNameW); - return STATUS_NO_MEMORY; - } + RtlAnsiStringToUnicodeString(&ModuleNameW, (PANSI_STRING)ModuleName, TRUE); - Status = ElfrOpenELW( - UNCServerName ? UNCServerNameW.Buffer : NULL, - ModuleName ? (PRPC_UNICODE_STRING)&ModuleNameW : NULL, - RegModuleName ? (PRPC_UNICODE_STRING)&RegModuleNameW : NULL, - MajorVersion, - MinorVersion, - LogHandle); + /* FIXME: Must verify that caller has read access */ + + *LogHandle = ElfCreateEventLogHandle(ModuleNameW.Buffer, FALSE); - RtlFreeUnicodeString(&UNCServerNameW); RtlFreeUnicodeString(&ModuleNameW); - RtlFreeUnicodeString(&RegModuleNameW); - return Status; + if (*LogHandle == NULL) + { + return STATUS_INVALID_PARAMETER; + } + + return STATUS_SUCCESS; } @@ -531,45 +515,32 @@ NTSTATUS ElfrRegisterEventSourceA( DWORD MinorVersion, IELF_HANDLE *LogHandle) { - UNICODE_STRING UNCServerNameW = { 0, 0, NULL }; UNICODE_STRING ModuleNameW = { 0, 0, NULL }; - if (UNCServerName && - !RtlCreateUnicodeStringFromAsciiz(&UNCServerNameW, UNCServerName)) - { - return STATUS_NO_MEMORY; - } - if (ModuleName && !RtlAnsiStringToUnicodeString(&ModuleNameW, (PANSI_STRING)ModuleName, TRUE)) { - RtlFreeUnicodeString(&UNCServerNameW); return STATUS_NO_MEMORY; } /* RegModuleName must be an empty string */ if (RegModuleName->Length > 0) { - RtlFreeUnicodeString(&UNCServerNameW); RtlFreeUnicodeString(&ModuleNameW); return STATUS_INVALID_PARAMETER; } if ((MajorVersion != 1) || (MinorVersion != 1)) { - RtlFreeUnicodeString(&UNCServerNameW); RtlFreeUnicodeString(&ModuleNameW); return STATUS_INVALID_PARAMETER; } - /*FIXME: UNCServerName must specify the server or empty for local */ - - /*FIXME: Must verify that caller has write access */ + /* FIXME: Must verify that caller has write access */ *LogHandle = ElfCreateEventLogHandle(ModuleNameW.Buffer, TRUE); - RtlFreeUnicodeString(&UNCServerNameW); RtlFreeUnicodeString(&ModuleNameW); return STATUS_SUCCESS; @@ -661,8 +632,32 @@ NTSTATUS ElfrGetLogInformation( DWORD cbBufSize, DWORD *pcbBytesNeeded) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + NTSTATUS Status = STATUS_SUCCESS; + + /* FIXME: check handle first */ + + switch (InfoLevel) + { + case EVENTLOG_FULL_INFO: + { + LPEVENTLOG_FULL_INFORMATION efi = (LPEVENTLOG_FULL_INFORMATION)Buffer; + + *pcbBytesNeeded = sizeof(EVENTLOG_FULL_INFORMATION); + if (cbBufSize < sizeof(EVENTLOG_FULL_INFORMATION)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + efi->dwFull = 0; /* FIXME */ + } + break; + + default: + Status = STATUS_INVALID_LEVEL; + break; + } + + return Status; } diff --git a/reactos/dll/win32/advapi32/service/eventlog.c b/reactos/dll/win32/advapi32/service/eventlog.c index 7327532b74b..8cb4b22664e 100644 --- a/reactos/dll/win32/advapi32/service/eventlog.c +++ b/reactos/dll/win32/advapi32/service/eventlog.c @@ -42,7 +42,7 @@ EVENTLOG_HANDLE_A_bind(EVENTLOG_HANDLE_A UNCServerName) status = RpcStringBindingComposeA(NULL, (UCHAR *)"ncacn_np", (UCHAR *)UNCServerName, - (UCHAR *)"\\pipe\\ntsvcs", + (UCHAR *)"\\pipe\\EventLog", NULL, (UCHAR **)&pszStringBinding); if (status) @@ -147,20 +147,17 @@ BOOL WINAPI BackupEventLogA(IN HANDLE hEventLog, IN LPCSTR lpBackupFileName) { - RPC_STRING BackupFileName; + ANSI_STRING BackupFileName; NTSTATUS Status; TRACE("%p, %s\n", hEventLog, lpBackupFileName); - BackupFileName.Buffer = (LPSTR)lpBackupFileName; - BackupFileName.Length = BackupFileName.MaximumLength = - lpBackupFileName ? strlen(lpBackupFileName) : 0; - BackupFileName.MaximumLength += sizeof(CHAR); + RtlInitAnsiString(&BackupFileName, lpBackupFileName); RpcTryExcept { Status = ElfrBackupELFA(hEventLog, - &BackupFileName); + (PRPC_STRING)&BackupFileName); } RpcExcept(EXCEPTION_EXECUTE_HANDLER) { @@ -188,20 +185,17 @@ BOOL WINAPI BackupEventLogW(IN HANDLE hEventLog, IN LPCWSTR lpBackupFileName) { - RPC_UNICODE_STRING BackupFileName; + UNICODE_STRING BackupFileName; NTSTATUS Status; TRACE("%p, %s\n", hEventLog, debugstr_w(lpBackupFileName)); - BackupFileName.Buffer = (LPWSTR)lpBackupFileName; - BackupFileName.Length = BackupFileName.MaximumLength = - lpBackupFileName ? wcslen(lpBackupFileName) * sizeof(WCHAR) : 0; - BackupFileName.MaximumLength += sizeof(WCHAR); + RtlInitUnicodeString(&BackupFileName, lpBackupFileName); RpcTryExcept { Status = ElfrBackupELFW(hEventLog, - &BackupFileName); + (PRPC_UNICODE_STRING)&BackupFileName); } RpcExcept(EXCEPTION_EXECUTE_HANDLER) { @@ -226,20 +220,17 @@ BOOL WINAPI ClearEventLogA(IN HANDLE hEventLog, IN LPCSTR lpBackupFileName) { - RPC_STRING BackupFileName; + ANSI_STRING BackupFileName; NTSTATUS Status; TRACE("%p, %s\n", hEventLog, lpBackupFileName); - BackupFileName.Buffer = (LPSTR)lpBackupFileName; - BackupFileName.Length = BackupFileName.MaximumLength = - lpBackupFileName ? strlen(lpBackupFileName) : 0; - BackupFileName.MaximumLength += sizeof(CHAR); + RtlInitAnsiString(&BackupFileName, lpBackupFileName); RpcTryExcept { Status = ElfrClearELFA(hEventLog, - &BackupFileName); + (PRPC_STRING)&BackupFileName); } RpcExcept(EXCEPTION_EXECUTE_HANDLER) { @@ -264,20 +255,17 @@ BOOL WINAPI ClearEventLogW(IN HANDLE hEventLog, IN LPCWSTR lpBackupFileName) { - RPC_UNICODE_STRING BackupFileName; + UNICODE_STRING BackupFileName; NTSTATUS Status; TRACE("%p, %s\n", hEventLog, debugstr_w(lpBackupFileName)); - BackupFileName.Buffer = (LPWSTR)lpBackupFileName; - BackupFileName.Length = BackupFileName.MaximumLength = - lpBackupFileName ? wcslen(lpBackupFileName) * sizeof(WCHAR) : 0; - BackupFileName.MaximumLength += sizeof(WCHAR); + RtlInitUnicodeString(&BackupFileName,lpBackupFileName); RpcTryExcept { Status = ElfrClearELFW(hEventLog, - &BackupFileName); + (PRPC_UNICODE_STRING)&BackupFileName); } RpcExcept(EXCEPTION_EXECUTE_HANDLER) { @@ -380,6 +368,12 @@ GetEventLogInformation(IN HANDLE hEventLog, { NTSTATUS Status; + if (dwInfoLevel != EVENTLOG_FULL_INFO) + { + SetLastError(ERROR_INVALID_LEVEL); + return FALSE; + } + RpcTryExcept { Status = ElfrGetLogInformation(hEventLog, @@ -562,21 +556,18 @@ HANDLE WINAPI OpenBackupEventLogW(IN LPCWSTR lpUNCServerName, IN LPCWSTR lpFileName) { - RPC_UNICODE_STRING FileName; + UNICODE_STRING FileName; IELF_HANDLE LogHandle; NTSTATUS Status; TRACE("%s, %s\n", debugstr_w(lpUNCServerName), debugstr_w(lpFileName)); - FileName.Buffer = (LPWSTR)lpFileName; - FileName.Length = FileName.MaximumLength = - lpFileName ? wcslen(lpFileName) * sizeof(WCHAR) : 0; - FileName.MaximumLength += sizeof(WCHAR); + RtlInitUnicodeString(&FileName, lpFileName); RpcTryExcept { Status = ElfrOpenBELW((LPWSTR)lpUNCServerName, - &FileName, + (PRPC_UNICODE_STRING)&FileName, 1, 1, &LogHandle); @@ -903,21 +894,18 @@ HANDLE WINAPI RegisterEventSourceW(IN LPCWSTR lpUNCServerName, IN LPCWSTR lpSourceName) { - RPC_UNICODE_STRING SourceName; + UNICODE_STRING SourceName; IELF_HANDLE LogHandle; NTSTATUS Status; TRACE("%s, %s\n", debugstr_w(lpUNCServerName), debugstr_w(lpSourceName)); - SourceName.Buffer = (LPWSTR)lpSourceName; - SourceName.Length = SourceName.MaximumLength = - lpSourceName ? wcslen(lpSourceName) * sizeof(WCHAR) : 0; - SourceName.MaximumLength += sizeof(WCHAR); + RtlInitUnicodeString(&SourceName, lpSourceName); RpcTryExcept { Status = ElfrRegisterEventSourceW((LPWSTR)lpUNCServerName, - &SourceName, + (PRPC_UNICODE_STRING)&SourceName, &EmptyStringU, 1, 1, From f9d93024457a87da14e2ca2146ae51ec48d8e5b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Sun, 14 Mar 2010 19:21:38 +0000 Subject: [PATCH 22/61] [ntoskrnl] Better fix for correct display of loaded drivers svn path=/trunk/; revision=46200 --- reactos/ntoskrnl/io/iomgr/driver.c | 44 +++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/reactos/ntoskrnl/io/iomgr/driver.c b/reactos/ntoskrnl/io/iomgr/driver.c index a81c25ed371..ef1b78969fb 100644 --- a/reactos/ntoskrnl/io/iomgr/driver.c +++ b/reactos/ntoskrnl/io/iomgr/driver.c @@ -149,6 +149,39 @@ IopGetDriverObject( return STATUS_SUCCESS; } +/* + * RETURNS + * TRUE if String2 contains String1 as a suffix. + */ +BOOLEAN +NTAPI +IopSuffixUnicodeString( + IN PCUNICODE_STRING String1, + IN PCUNICODE_STRING String2) +{ + PWCHAR pc1; + PWCHAR pc2; + ULONG Length; + + if (String2->Length < String1->Length) + return FALSE; + + Length = String1->Length / 2; + pc1 = String1->Buffer; + pc2 = &String2->Buffer[String2->Length / sizeof(WCHAR) - Length]; + + if (pc1 && pc2) + { + while (Length--) + { + if( *pc1++ != *pc2++ ) + return FALSE; + } + return TRUE; + } + return FALSE; +} + /* * IopDisplayLoadingMessage * @@ -161,19 +194,16 @@ INIT_FUNCTION IopDisplayLoadingMessage(PUNICODE_STRING ServiceName) { CHAR TextBuffer[256]; + UNICODE_STRING DotSys = RTL_CONSTANT_STRING(L".SYS"); if (ExpInTextModeSetup) return; RtlUpcaseUnicodeString(ServiceName, ServiceName, FALSE); snprintf(TextBuffer, sizeof(TextBuffer), - "%s%s%s\\%wZ", + "%s%sSystem32\\Drivers\\%wZ%s\n", KeLoaderBlock->ArcBootDeviceName, KeLoaderBlock->NtBootPathName, - "System32\\Drivers", - ServiceName); - if (!strstr(TextBuffer, ".sys")) - strcat(TextBuffer, ".sys\n"); - else - strcat(TextBuffer, "\n"); + ServiceName, + IopSuffixUnicodeString(&DotSys, ServiceName) ? "" : ".SYS"); HalDisplayString(TextBuffer); } From 3e4b8ea4f14df0fe879a2524a28d33a18c37d396 Mon Sep 17 00:00:00 2001 From: Christoph von Wittich Date: Mon, 15 Mar 2010 11:35:51 +0000 Subject: [PATCH 23/61] [WININET] sync wininet with wine 1.1.40 svn path=/trunk/; revision=46202 --- reactos/dll/win32/wininet/cookie.c | 295 +- reactos/dll/win32/wininet/dialogs.c | 254 +- reactos/dll/win32/wininet/ftp.c | 1043 ++++--- reactos/dll/win32/wininet/http.c | 3447 +++++++++++++-------- reactos/dll/win32/wininet/internet.c | 864 ++++-- reactos/dll/win32/wininet/internet.h | 191 +- reactos/dll/win32/wininet/netconnection.c | 653 ++-- reactos/dll/win32/wininet/resource.h | 5 + reactos/dll/win32/wininet/rsrc.rc | 18 +- reactos/dll/win32/wininet/urlcache.c | 192 +- reactos/dll/win32/wininet/utility.c | 88 +- reactos/dll/win32/wininet/wininet.rbuild | 1 + reactos/dll/win32/wininet/wininet.spec | 16 +- reactos/dll/win32/wininet/wininet_Bg.rc | 2 + reactos/dll/win32/wininet/wininet_Cs.rc | 2 + reactos/dll/win32/wininet/wininet_Da.rc | 2 + reactos/dll/win32/wininet/wininet_De.rc | 29 +- reactos/dll/win32/wininet/wininet_En.rc | 22 + reactos/dll/win32/wininet/wininet_Eo.rc | 2 + reactos/dll/win32/wininet/wininet_Es.rc | 2 + reactos/dll/win32/wininet/wininet_Fi.rc | 2 + reactos/dll/win32/wininet/wininet_Fr.rc | 60 +- reactos/dll/win32/wininet/wininet_Hu.rc | 2 + reactos/dll/win32/wininet/wininet_It.rc | 22 + reactos/dll/win32/wininet/wininet_Ja.rc | 4 +- reactos/dll/win32/wininet/wininet_Ko.rc | 2 + reactos/dll/win32/wininet/wininet_Lt.rc | 69 + reactos/dll/win32/wininet/wininet_Nl.rc | 22 + reactos/dll/win32/wininet/wininet_No.rc | 28 +- reactos/dll/win32/wininet/wininet_Pl.rc | 2 + reactos/dll/win32/wininet/wininet_Pt.rc | 34 +- reactos/dll/win32/wininet/wininet_Ro.rc | 26 +- reactos/dll/win32/wininet/wininet_Ru.rc | 43 +- reactos/dll/win32/wininet/wininet_Si.rc | 4 +- reactos/dll/win32/wininet/wininet_Sv.rc | 2 + reactos/dll/win32/wininet/wininet_Tr.rc | 2 + reactos/dll/win32/wininet/wininet_Uk.rc | 2 + reactos/dll/win32/wininet/wininet_Zh.rc | 4 +- 38 files changed, 4740 insertions(+), 2718 deletions(-) create mode 100644 reactos/dll/win32/wininet/wininet_Lt.rc diff --git a/reactos/dll/win32/wininet/cookie.c b/reactos/dll/win32/wininet/cookie.c index 12d841bc7b9..75cf049308b 100644 --- a/reactos/dll/win32/wininet/cookie.c +++ b/reactos/dll/win32/wininet/cookie.c @@ -23,6 +23,10 @@ #include "config.h" #include "wine/port.h" +#if defined(__MINGW32__) || defined (_MSC_VER) +#include +#endif + #include #include #include @@ -48,7 +52,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(wininet); * Cookies are currently memory only. * Cookies are NOT THREAD SAFE * Cookies could use A LOT OF MEMORY. We need some kind of memory management here! - * Cookies should care about the expiry time */ typedef struct _cookie_domain cookie_domain; @@ -62,7 +65,7 @@ struct _cookie LPWSTR lpCookieName; LPWSTR lpCookieData; - time_t expiry; /* FIXME: not used */ + FILETIME expiry; }; struct _cookie_domain @@ -76,7 +79,7 @@ struct _cookie_domain static struct list domain_list = LIST_INIT(domain_list); -static cookie *COOKIE_addCookie(cookie_domain *domain, LPCWSTR name, LPCWSTR data); +static cookie *COOKIE_addCookie(cookie_domain *domain, LPCWSTR name, LPCWSTR data, FILETIME expiry); static cookie *COOKIE_findCookie(cookie_domain *domain, LPCWSTR lpszCookieName); static void COOKIE_deleteCookie(cookie *deadCookie, BOOL deleteDomain); static cookie_domain *COOKIE_addDomain(LPCWSTR domain, LPCWSTR path); @@ -84,24 +87,16 @@ static void COOKIE_deleteDomain(cookie_domain *deadDomain); /* adds a cookie to the domain */ -static cookie *COOKIE_addCookie(cookie_domain *domain, LPCWSTR name, LPCWSTR data) +static cookie *COOKIE_addCookie(cookie_domain *domain, LPCWSTR name, LPCWSTR data, FILETIME expiry) { cookie *newCookie = HeapAlloc(GetProcessHeap(), 0, sizeof(cookie)); list_init(&newCookie->entry); newCookie->lpCookieName = NULL; newCookie->lpCookieData = NULL; - - if (name) - { - newCookie->lpCookieName = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1)*sizeof(WCHAR)); - lstrcpyW(newCookie->lpCookieName, name); - } - if (data) - { - newCookie->lpCookieData = HeapAlloc(GetProcessHeap(), 0, (strlenW(data) + 1)*sizeof(WCHAR)); - lstrcpyW(newCookie->lpCookieData, data); - } + newCookie->expiry = expiry; + newCookie->lpCookieName = heap_strdupW(name); + newCookie->lpCookieData = heap_strdupW(data); TRACE("added cookie %p (data is %s)\n", newCookie, debugstr_w(data) ); @@ -156,17 +151,8 @@ static cookie_domain *COOKIE_addDomain(LPCWSTR domain, LPCWSTR path) list_init(&newDomain->cookie_list); newDomain->lpCookieDomain = NULL; newDomain->lpCookiePath = NULL; - - if (domain) - { - newDomain->lpCookieDomain = HeapAlloc(GetProcessHeap(), 0, (strlenW(domain) + 1)*sizeof(WCHAR)); - strcpyW(newDomain->lpCookieDomain, domain); - } - if (path) - { - newDomain->lpCookiePath = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1)*sizeof(WCHAR)); - lstrcpyW(newDomain->lpCookiePath, path); - } + newDomain->lpCookieDomain = heap_strdupW(domain); + newDomain->lpCookiePath = heap_strdupW(path); list_add_tail(&domain_list, &newDomain->entry); @@ -191,7 +177,28 @@ static BOOL COOKIE_crackUrlSimple(LPCWSTR lpszUrl, LPWSTR hostName, int hostName UrlComponents.dwHostNameLength = hostNameLen; UrlComponents.dwUrlPathLength = pathLen; - return InternetCrackUrlW(lpszUrl, 0, 0, &UrlComponents); + if (!InternetCrackUrlW(lpszUrl, 0, 0, &UrlComponents)) return FALSE; + + /* discard the webpage off the end of the path */ + if (UrlComponents.dwUrlPathLength) + { + if (path[UrlComponents.dwUrlPathLength - 1] != '/') + { + WCHAR *ptr; + if ((ptr = strrchrW(path, '/'))) *(++ptr) = 0; + else + { + path[0] = '/'; + path[1] = 0; + } + } + } + else if (pathLen >= 2) + { + path[0] = '/'; + path[1] = 0; + } + return TRUE; } /* match a domain. domain must match if the domain is not NULL. path must match if the path is not NULL */ @@ -215,11 +222,22 @@ static BOOL COOKIE_matchDomain(LPCWSTR lpszCookieDomain, LPCWSTR lpszCookiePath, } if (lpszCookiePath) { + INT len; TRACE("comparing paths: %s with %s\n", debugstr_w(lpszCookiePath), debugstr_w(searchDomain->lpCookiePath)); + /* paths match at the beginning. so a path of /foo would match + * /foobar and /foo/bar + */ if (!searchDomain->lpCookiePath) return FALSE; - if (strcmpW(lpszCookiePath, searchDomain->lpCookiePath)) + if (allow_partial) + { + len = lstrlenW(searchDomain->lpCookiePath); + if (strncmpiW(searchDomain->lpCookiePath, lpszCookiePath, len)!=0) + return FALSE; + } + else if (strcmpW(lpszCookiePath, searchDomain->lpCookiePath)) return FALSE; + } return TRUE; } @@ -262,6 +280,7 @@ BOOL WINAPI InternetGetCookieW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName, struct list * cursor; unsigned int cnt = 0, domain_count = 0, cookie_count = 0; WCHAR hostName[2048], path[2048]; + FILETIME tm; TRACE("(%s, %s, %p, %p)\n", debugstr_w(lpszUrl),debugstr_w(lpszCookieName), lpCookieData, lpdwSize); @@ -276,10 +295,12 @@ BOOL WINAPI InternetGetCookieW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName, ret = COOKIE_crackUrlSimple(lpszUrl, hostName, sizeof(hostName)/sizeof(hostName[0]), path, sizeof(path)/sizeof(path[0])); if (!ret || !hostName[0]) return FALSE; + GetSystemTimeAsFileTime(&tm); + LIST_FOR_EACH(cursor, &domain_list) { cookie_domain *cookiesDomain = LIST_ENTRY(cursor, cookie_domain, entry); - if (COOKIE_matchDomain(hostName, NULL /* FIXME: path */, cookiesDomain, TRUE)) + if (COOKIE_matchDomain(hostName, path, cookiesDomain, TRUE)) { struct list * cursor; domain_count++; @@ -288,6 +309,14 @@ BOOL WINAPI InternetGetCookieW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName, LIST_FOR_EACH(cursor, &cookiesDomain->cookie_list) { cookie *thisCookie = LIST_ENTRY(cursor, cookie, entry); + /* check for expiry */ + if ((thisCookie->expiry.dwLowDateTime != 0 || thisCookie->expiry.dwHighDateTime != 0) && CompareFileTime(&tm,&thisCookie->expiry) > 0) + { + TRACE("Found expired cookie. deleting\n"); + COOKIE_deleteCookie(thisCookie, FALSE); + continue; + } + if (lpCookieData == NULL) /* return the size of the buffer required to lpdwSize */ { unsigned int len; @@ -356,27 +385,16 @@ BOOL WINAPI InternetGetCookieA(LPCSTR lpszUrl, LPCSTR lpszCookieName, LPSTR lpCookieData, LPDWORD lpdwSize) { DWORD len; - LPWSTR szCookieData = NULL, szUrl = NULL, szCookieName = NULL; + LPWSTR szCookieData = NULL, url, name; BOOL r; TRACE("(%s,%s,%p)\n", debugstr_a(lpszUrl), debugstr_a(lpszCookieName), lpCookieData); - if( lpszUrl ) - { - len = MultiByteToWideChar( CP_ACP, 0, lpszUrl, -1, NULL, 0 ); - szUrl = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, lpszUrl, -1, szUrl, len ); - } + url = heap_strdupAtoW(lpszUrl); + name = heap_strdupAtoW(lpszCookieName); - if( lpszCookieName ) - { - len = MultiByteToWideChar( CP_ACP, 0, lpszCookieName, -1, NULL, 0 ); - szCookieName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, lpszCookieName, -1, szCookieName, len ); - } - - r = InternetGetCookieW( szUrl, szCookieName, NULL, &len ); + r = InternetGetCookieW( url, name, NULL, &len ); if( r ) { szCookieData = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); @@ -386,7 +404,7 @@ BOOL WINAPI InternetGetCookieA(LPCSTR lpszUrl, LPCSTR lpszCookieName, } else { - r = InternetGetCookieW( szUrl, szCookieName, szCookieData, &len ); + r = InternetGetCookieW( url, name, szCookieData, &len ); *lpdwSize = WideCharToMultiByte( CP_ACP, 0, szCookieData, len, lpCookieData, *lpdwSize, NULL, NULL ); @@ -394,8 +412,8 @@ BOOL WINAPI InternetGetCookieA(LPCSTR lpszUrl, LPCSTR lpszCookieName, } HeapFree( GetProcessHeap(), 0, szCookieData ); - HeapFree( GetProcessHeap(), 0, szCookieName ); - HeapFree( GetProcessHeap(), 0, szUrl ); + HeapFree( GetProcessHeap(), 0, name ); + HeapFree( GetProcessHeap(), 0, url ); return r; } @@ -405,27 +423,129 @@ static BOOL set_cookie(LPCWSTR domain, LPCWSTR path, LPCWSTR cookie_name, LPCWST cookie_domain *thisCookieDomain = NULL; cookie *thisCookie; struct list *cursor; + LPWSTR data, value; + WCHAR *ptr; + FILETIME expiry; + BOOL expired = FALSE; + + value = data = heap_strdupW(cookie_data); + if (!data) + { + ERR("could not allocate %zu bytes for the cookie data buffer\n", (strlenW(cookie_data) + 1) * sizeof(WCHAR)); + return FALSE; + } + + memset(&expiry,0,sizeof(expiry)); + + /* lots of information can be parsed out of the cookie value */ + + ptr = data; + for (;;) + { + static const WCHAR szDomain[] = {'d','o','m','a','i','n','=',0}; + static const WCHAR szPath[] = {'p','a','t','h','=',0}; + static const WCHAR szExpires[] = {'e','x','p','i','r','e','s','=',0}; + static const WCHAR szSecure[] = {'s','e','c','u','r','e',0}; + static const WCHAR szHttpOnly[] = {'h','t','t','p','o','n','l','y',0}; + + if (!(ptr = strchrW(ptr,';'))) break; + *ptr++ = 0; + + if (value != data) + HeapFree(GetProcessHeap(), 0, value); + value = HeapAlloc(GetProcessHeap(), 0, (ptr - data) * sizeof(WCHAR)); + if (value == NULL) + { + HeapFree(GetProcessHeap(), 0, data); + ERR("could not allocate %zu bytes for the cookie value buffer\n", (ptr - data) * sizeof(WCHAR)); + return FALSE; + } + strcpyW(value, data); + + while (*ptr == ' ') ptr++; /* whitespace */ + + if (strncmpiW(ptr, szDomain, 7) == 0) + { + ptr+=strlenW(szDomain); + domain = ptr; + TRACE("Parsing new domain %s\n",debugstr_w(domain)); + } + else if (strncmpiW(ptr, szPath, 5) == 0) + { + ptr+=strlenW(szPath); + path = ptr; + TRACE("Parsing new path %s\n",debugstr_w(path)); + } + else if (strncmpiW(ptr, szExpires, 8) == 0) + { + FILETIME ft; + SYSTEMTIME st; + FIXME("persistent cookies not handled (%s)\n",debugstr_w(ptr)); + ptr+=strlenW(szExpires); + if (InternetTimeToSystemTimeW(ptr, &st, 0)) + { + SystemTimeToFileTime(&st, &expiry); + GetSystemTimeAsFileTime(&ft); + + if (CompareFileTime(&ft,&expiry) > 0) + { + TRACE("Cookie already expired.\n"); + expired = TRUE; + } + } + } + else if (strncmpiW(ptr, szSecure, 6) == 0) + { + FIXME("secure not handled (%s)\n",debugstr_w(ptr)); + ptr += strlenW(szSecure); + } + else if (strncmpiW(ptr, szHttpOnly, 8) == 0) + { + FIXME("httponly not handled (%s)\n",debugstr_w(ptr)); + ptr += strlenW(szHttpOnly); + } + else if (*ptr) + { + FIXME("Unknown additional option %s\n",debugstr_w(ptr)); + break; + } + } LIST_FOR_EACH(cursor, &domain_list) { thisCookieDomain = LIST_ENTRY(cursor, cookie_domain, entry); - if (COOKIE_matchDomain(domain, NULL /* FIXME: path */, thisCookieDomain, FALSE)) + if (COOKIE_matchDomain(domain, path, thisCookieDomain, FALSE)) break; thisCookieDomain = NULL; } if (!thisCookieDomain) - thisCookieDomain = COOKIE_addDomain(domain, path); + { + if (!expired) + thisCookieDomain = COOKIE_addDomain(domain, path); + else + { + HeapFree(GetProcessHeap(),0,data); + if (value != data) HeapFree(GetProcessHeap(), 0, value); + return TRUE; + } + } if ((thisCookie = COOKIE_findCookie(thisCookieDomain, cookie_name))) COOKIE_deleteCookie(thisCookie, FALSE); - TRACE("setting cookie %s=%s for domain %s\n", debugstr_w(cookie_name), - debugstr_w(cookie_data), debugstr_w(thisCookieDomain->lpCookieDomain)); + TRACE("setting cookie %s=%s for domain %s path %s\n", debugstr_w(cookie_name), + debugstr_w(value), debugstr_w(thisCookieDomain->lpCookieDomain),debugstr_w(thisCookieDomain->lpCookiePath)); - if (!COOKIE_addCookie(thisCookieDomain, cookie_name, cookie_data)) + if (!expired && !COOKIE_addCookie(thisCookieDomain, cookie_name, value, expiry)) + { + HeapFree(GetProcessHeap(),0,data); + if (value != data) HeapFree(GetProcessHeap(), 0, value); return FALSE; + } + HeapFree(GetProcessHeap(),0,data); + if (value != data) HeapFree(GetProcessHeap(), 0, value); return TRUE; } @@ -454,28 +574,26 @@ BOOL WINAPI InternetSetCookieW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName, return FALSE; } - hostName[0] = path[0] = 0; + hostName[0] = 0; ret = COOKIE_crackUrlSimple(lpszUrl, hostName, sizeof(hostName)/sizeof(hostName[0]), path, sizeof(path)/sizeof(path[0])); if (!ret || !hostName[0]) return FALSE; if (!lpszCookieName) { - unsigned int len; WCHAR *cookie, *data; - len = strlenW(lpCookieData); - if (!(cookie = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)))) + cookie = heap_strdupW(lpCookieData); + if (!cookie) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; } - strcpyW(cookie, lpCookieData); /* some apps (or is it us??) try to add a cookie with no cookie name, but * the cookie data in the form of name[=data]. */ - if (!(data = strchrW(cookie, '='))) data = cookie + len; - else data++; + if (!(data = strchrW(cookie, '='))) data = cookie + strlenW(cookie); + else *data++ = 0; ret = set_cookie(hostName, path, cookie, data); @@ -499,39 +617,21 @@ BOOL WINAPI InternetSetCookieW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName, BOOL WINAPI InternetSetCookieA(LPCSTR lpszUrl, LPCSTR lpszCookieName, LPCSTR lpCookieData) { - DWORD len; - LPWSTR szCookieData = NULL, szUrl = NULL, szCookieName = NULL; + LPWSTR data, url, name; BOOL r; TRACE("(%s,%s,%s)\n", debugstr_a(lpszUrl), debugstr_a(lpszCookieName), debugstr_a(lpCookieData)); - if( lpszUrl ) - { - len = MultiByteToWideChar( CP_ACP, 0, lpszUrl, -1, NULL, 0 ); - szUrl = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, lpszUrl, -1, szUrl, len ); - } + url = heap_strdupAtoW(lpszUrl); + name = heap_strdupAtoW(lpszCookieName); + data = heap_strdupAtoW(lpCookieData); - if( lpszCookieName ) - { - len = MultiByteToWideChar( CP_ACP, 0, lpszCookieName, -1, NULL, 0 ); - szCookieName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, lpszCookieName, -1, szCookieName, len ); - } + r = InternetSetCookieW( url, name, data ); - if( lpCookieData ) - { - len = MultiByteToWideChar( CP_ACP, 0, lpCookieData, -1, NULL, 0 ); - szCookieData = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, lpCookieData, -1, szCookieData, len ); - } - - r = InternetSetCookieW( szUrl, szCookieName, szCookieData ); - - HeapFree( GetProcessHeap(), 0, szCookieData ); - HeapFree( GetProcessHeap(), 0, szCookieName ); - HeapFree( GetProcessHeap(), 0, szUrl ); + HeapFree( GetProcessHeap(), 0, data ); + HeapFree( GetProcessHeap(), 0, name ); + HeapFree( GetProcessHeap(), 0, url ); return r; } @@ -692,3 +792,28 @@ BOOL WINAPI InternetSetPerSiteCookieDecisionW( LPCWSTR pchHostName, DWORD dwDeci FIXME("(%s, 0x%08x) stub\n", debugstr_w(pchHostName), dwDecision); return FALSE; } + +/*********************************************************************** + * IsDomainLegalCookieDomainW (WININET.@) + */ +BOOL WINAPI IsDomainLegalCookieDomainW( LPCWSTR s1, LPCWSTR s2 ) +{ + const WCHAR *p; + + FIXME("(%s, %s)\n", debugstr_w(s1), debugstr_w(s2)); + + if (!s1 || !s2) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + if (s1[0] == '.' || !s1[0] || s2[0] == '.' || !s2[0]) + { + SetLastError(ERROR_INVALID_NAME); + return FALSE; + } + if (!(p = strchrW(s2, '.'))) return FALSE; + if (strchrW(p + 1, '.') && !strcmpW(p + 1, s1)) return TRUE; + else if (!strcmpW(s1, s2)) return TRUE; + return FALSE; +} diff --git a/reactos/dll/win32/wininet/dialogs.c b/reactos/dll/win32/wininet/dialogs.c index dd5aa315a63..2c4a5278569 100644 --- a/reactos/dll/win32/wininet/dialogs.c +++ b/reactos/dll/win32/wininet/dialogs.c @@ -21,6 +21,10 @@ #include "config.h" #include "wine/port.h" +#if defined(__MINGW32__) || defined (_MSC_VER) +#include +#endif + #include #include "windef.h" @@ -58,22 +62,23 @@ struct WININET_ErrorDlgParams */ static BOOL WININET_GetProxyServer( HINTERNET hRequest, LPWSTR szBuf, DWORD sz ) { - LPWININETHTTPREQW lpwhr; - LPWININETHTTPSESSIONW lpwhs = NULL; - LPWININETAPPINFOW hIC = NULL; + http_request_t *lpwhr; + http_session_t *lpwhs = NULL; + appinfo_t *hIC = NULL; + BOOL ret = FALSE; LPWSTR p; - lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest ); + lpwhr = (http_request_t*) WININET_GetObject( hRequest ); if (NULL == lpwhr) - return FALSE; + return FALSE; lpwhs = lpwhr->lpHttpSession; if (NULL == lpwhs) - return FALSE; + goto done; hIC = lpwhs->lpAppInfo; if (NULL == hIC) - return FALSE; + goto done; lstrcpynW(szBuf, hIC->lpszProxy, sz); @@ -82,7 +87,39 @@ static BOOL WININET_GetProxyServer( HINTERNET hRequest, LPWSTR szBuf, DWORD sz ) if (p) *p = 0; - return TRUE; + ret = TRUE; + +done: + WININET_Release( &lpwhr->hdr ); + return ret; +} + +/*********************************************************************** + * WININET_GetServer + * + * Determine the name of the web server + */ +static BOOL WININET_GetServer( HINTERNET hRequest, LPWSTR szBuf, DWORD sz ) +{ + http_request_t *lpwhr; + http_session_t *lpwhs = NULL; + BOOL ret = FALSE; + + lpwhr = (http_request_t*) WININET_GetObject( hRequest ); + if (NULL == lpwhr) + return FALSE; + + lpwhs = lpwhr->lpHttpSession; + if (NULL == lpwhs) + goto done; + + lstrcpynW(szBuf, lpwhs->lpszHostName, sz); + + ret = TRUE; + +done: + WININET_Release( &lpwhr->hdr ); + return ret; } /*********************************************************************** @@ -90,16 +127,20 @@ static BOOL WININET_GetProxyServer( HINTERNET hRequest, LPWSTR szBuf, DWORD sz ) * * Determine the name of the (basic) Authentication realm */ -static BOOL WININET_GetAuthRealm( HINTERNET hRequest, LPWSTR szBuf, DWORD sz ) +static BOOL WININET_GetAuthRealm( HINTERNET hRequest, LPWSTR szBuf, DWORD sz, BOOL proxy ) { LPWSTR p, q; - DWORD index; + DWORD index, query; static const WCHAR szRealm[] = { 'r','e','a','l','m','=',0 }; - /* extract the Realm from the proxy response and show it */ + if (proxy) + query = HTTP_QUERY_PROXY_AUTHENTICATE; + else + query = HTTP_QUERY_WWW_AUTHENTICATE; + + /* extract the Realm from the response and show it */ index = 0; - if( !HttpQueryInfoW( hRequest, HTTP_QUERY_PROXY_AUTHENTICATE, - szBuf, &sz, &index) ) + if( !HttpQueryInfoW( hRequest, query, szBuf, &sz, &index) ) return FALSE; /* @@ -109,11 +150,10 @@ static BOOL WININET_GetAuthRealm( HINTERNET hRequest, LPWSTR szBuf, DWORD sz ) p = strchrW( szBuf, ' ' ); if( !p || strncmpW( p+1, szRealm, strlenW(szRealm) ) ) { - ERR("proxy response wrong? (%s)\n", debugstr_w(szBuf)); + ERR("response wrong? (%s)\n", debugstr_w(szBuf)); return FALSE; } - /* remove quotes */ p += 7; if( *p == '"' ) @@ -194,44 +234,62 @@ static BOOL WININET_GetSetPassword( HWND hdlg, LPCWSTR szServer, } /*********************************************************************** - * WININET_SetProxyAuthorization + * WININET_SetAuthorization */ -static BOOL WININET_SetProxyAuthorization( HINTERNET hRequest, - LPWSTR username, LPWSTR password ) +static BOOL WININET_SetAuthorization( HINTERNET hRequest, LPWSTR username, + LPWSTR password, BOOL proxy ) { - LPWININETHTTPREQW lpwhr; - LPWININETHTTPSESSIONW lpwhs; - LPWININETAPPINFOW hIC; - LPWSTR p; + http_request_t *lpwhr; + http_session_t *lpwhs; + BOOL ret = FALSE; + LPWSTR p, q; - lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest ); + lpwhr = (http_request_t*) WININET_GetObject( hRequest ); if( !lpwhr ) - return FALSE; - + return FALSE; + lpwhs = lpwhr->lpHttpSession; if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION) { INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - return FALSE; + goto done; } - hIC = lpwhs->lpAppInfo; - - p = HeapAlloc( GetProcessHeap(), 0, (strlenW( username ) + 1)*sizeof(WCHAR) ); + p = heap_strdupW(username); if( !p ) - return FALSE; - - lstrcpyW( p, username ); - hIC->lpszProxyUsername = p; + goto done; - p = HeapAlloc( GetProcessHeap(), 0, (strlenW( password ) + 1)*sizeof(WCHAR) ); - if( !p ) - return FALSE; - - lstrcpyW( p, password ); - hIC->lpszProxyPassword = p; + q = heap_strdupW(password); + if( !q ) + { + HeapFree(GetProcessHeap(), 0, username); + goto done; + } - return TRUE; + if (proxy) + { + appinfo_t *hIC = lpwhs->lpAppInfo; + + HeapFree(GetProcessHeap(), 0, hIC->lpszProxyUsername); + hIC->lpszProxyUsername = p; + + HeapFree(GetProcessHeap(), 0, hIC->lpszProxyPassword); + hIC->lpszProxyPassword = q; + } + else + { + HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName); + lpwhs->lpszUserName = p; + + HeapFree(GetProcessHeap(), 0, lpwhs->lpszPassword); + lpwhs->lpszPassword = q; + } + + ret = TRUE; + +done: + WININET_Release( &lpwhr->hdr ); + return ret; } /*********************************************************************** @@ -254,7 +312,7 @@ static INT_PTR WINAPI WININET_ProxyPasswordDialog( /* extract the Realm from the proxy response and show it */ if( WININET_GetAuthRealm( params->hRequest, - szRealm, sizeof szRealm/sizeof(WCHAR)) ) + szRealm, sizeof szRealm/sizeof(WCHAR), TRUE ) ) { hitem = GetDlgItem( hdlg, IDC_REALM ); SetWindowTextW( hitem, szRealm ); @@ -297,13 +355,97 @@ static INT_PTR WINAPI WININET_ProxyPasswordDialog( if( hitem && SendMessageW( hitem, BM_GETSTATE, 0, 0 ) && WININET_GetAuthRealm( params->hRequest, - szRealm, sizeof szRealm/sizeof(WCHAR)) && + szRealm, sizeof szRealm/sizeof(WCHAR), TRUE ) && WININET_GetProxyServer( params->hRequest, szServer, sizeof szServer/sizeof(WCHAR)) ) { WININET_GetSetPassword( hdlg, szServer, szRealm, TRUE ); } - WININET_SetProxyAuthorization( params->hRequest, username, password ); + WININET_SetAuthorization( params->hRequest, username, password, TRUE ); + + EndDialog( hdlg, ERROR_INTERNET_FORCE_RETRY ); + return TRUE; + } + if( wParam == IDCANCEL ) + { + EndDialog( hdlg, 0 ); + return TRUE; + } + break; + } + return FALSE; +} + +/*********************************************************************** + * WININET_PasswordDialog + */ +static INT_PTR WINAPI WININET_PasswordDialog( + HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + HWND hitem; + struct WININET_ErrorDlgParams *params; + WCHAR szRealm[0x80], szServer[0x80]; + + if( uMsg == WM_INITDIALOG ) + { + TRACE("WM_INITDIALOG (%08lx)\n", lParam); + + /* save the parameter list */ + params = (struct WININET_ErrorDlgParams*) lParam; + SetWindowLongPtrW( hdlg, GWLP_USERDATA, lParam ); + + /* extract the Realm from the response and show it */ + if( WININET_GetAuthRealm( params->hRequest, + szRealm, sizeof szRealm/sizeof(WCHAR), FALSE ) ) + { + hitem = GetDlgItem( hdlg, IDC_REALM ); + SetWindowTextW( hitem, szRealm ); + } + + /* extract the name of the server */ + if( WININET_GetServer( params->hRequest, + szServer, sizeof szServer/sizeof(WCHAR)) ) + { + hitem = GetDlgItem( hdlg, IDC_SERVER ); + SetWindowTextW( hitem, szServer ); + } + + WININET_GetSetPassword( hdlg, szServer, szRealm, FALSE ); + + return TRUE; + } + + params = (struct WININET_ErrorDlgParams*) + GetWindowLongPtrW( hdlg, GWLP_USERDATA ); + + switch( uMsg ) + { + case WM_COMMAND: + if( wParam == IDOK ) + { + WCHAR username[0x20], password[0x20]; + + username[0] = 0; + hitem = GetDlgItem( hdlg, IDC_USERNAME ); + if( hitem ) + GetWindowTextW( hitem, username, sizeof username/sizeof(WCHAR) ); + + password[0] = 0; + hitem = GetDlgItem( hdlg, IDC_PASSWORD ); + if( hitem ) + GetWindowTextW( hitem, password, sizeof password/sizeof(WCHAR) ); + + hitem = GetDlgItem( hdlg, IDC_SAVEPASSWORD ); + if( hitem && + SendMessageW( hitem, BM_GETSTATE, 0, 0 ) && + WININET_GetAuthRealm( params->hRequest, + szRealm, sizeof szRealm/sizeof(WCHAR), FALSE ) && + WININET_GetServer( params->hRequest, + szServer, sizeof szServer/sizeof(WCHAR)) ) + { + WININET_GetSetPassword( hdlg, szServer, szRealm, TRUE ); + } + WININET_SetAuthorization( params->hRequest, username, password, FALSE ); EndDialog( hdlg, ERROR_INTERNET_FORCE_RETRY ); return TRUE; @@ -362,17 +504,23 @@ DWORD WINAPI InternetErrorDlg(HWND hWnd, HINTERNET hRequest, switch( dwError ) { case ERROR_SUCCESS: - if( !(dwFlags & FLAGS_ERROR_UI_FILTER_FOR_ERRORS ) ) - return 0; - dwStatus = WININET_GetConnectionStatus( hRequest ); - if( HTTP_STATUS_PROXY_AUTH_REQ != dwStatus ) - return ERROR_SUCCESS; - return DialogBoxParamW( hwininet, MAKEINTRESOURCEW( IDD_PROXYDLG ), - hWnd, WININET_ProxyPasswordDialog, (LPARAM) ¶ms ); - case ERROR_INTERNET_INCORRECT_PASSWORD: - return DialogBoxParamW( hwininet, MAKEINTRESOURCEW( IDD_PROXYDLG ), - hWnd, WININET_ProxyPasswordDialog, (LPARAM) ¶ms ); + if( !dwError && !(dwFlags & FLAGS_ERROR_UI_FILTER_FOR_ERRORS ) ) + return 0; + + dwStatus = WININET_GetConnectionStatus( hRequest ); + switch (dwStatus) + { + case HTTP_STATUS_PROXY_AUTH_REQ: + return DialogBoxParamW( hwininet, MAKEINTRESOURCEW( IDD_PROXYDLG ), + hWnd, WININET_ProxyPasswordDialog, (LPARAM) ¶ms ); + case HTTP_STATUS_DENIED: + return DialogBoxParamW( hwininet, MAKEINTRESOURCEW( IDD_AUTHDLG ), + hWnd, WININET_PasswordDialog, (LPARAM) ¶ms ); + default: + WARN("unhandled status %u\n", dwStatus); + return 0; + } case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR: case ERROR_INTERNET_INVALID_CA: diff --git a/reactos/dll/win32/wininet/ftp.c b/reactos/dll/win32/wininet/ftp.c index 770fef2886a..1f031996811 100644 --- a/reactos/dll/win32/wininet/ftp.c +++ b/reactos/dll/win32/wininet/ftp.c @@ -30,6 +30,10 @@ #include "config.h" #include "wine/port.h" +#if defined(__MINGW32__) || defined (_MSC_VER) +#include +#endif + #include #include #include @@ -39,9 +43,15 @@ #ifdef HAVE_SYS_SOCKET_H # include #endif +#ifdef HAVE_ARPA_INET_H +# include +#endif #ifdef HAVE_UNISTD_H # include #endif +#ifdef HAVE_SYS_IOCTL_H +# include +#endif #include #include @@ -61,43 +71,47 @@ WINE_DEFAULT_DEBUG_CHANNEL(wininet); -typedef struct _WININETFTPSESSIONW WININETFTPSESSIONW; +typedef struct _ftp_session_t ftp_session_t; typedef struct { - WININETHANDLEHEADER hdr; - WININETFTPSESSIONW *lpFtpSession; + object_header_t hdr; + ftp_session_t *lpFtpSession; BOOL session_deleted; int nDataSocket; -} WININETFTPFILE, *LPWININETFTPFILE; + WCHAR *cache_file; + HANDLE cache_file_handle; +} ftp_file_t; -typedef struct _WININETFTPSESSIONW +struct _ftp_session_t { - WININETHANDLEHEADER hdr; - WININETAPPINFOW *lpAppInfo; + object_header_t hdr; + appinfo_t *lpAppInfo; int sndSocket; int lstnSocket; int pasvSocket; /* data socket connected by us in case of passive FTP */ - LPWININETFTPFILE download_in_progress; + ftp_file_t *download_in_progress; struct sockaddr_in socketAddress; struct sockaddr_in lstnSocketAddress; + LPWSTR servername; + INTERNET_PORT serverport; LPWSTR lpszPassword; LPWSTR lpszUserName; -} *LPWININETFTPSESSIONW; +}; typedef struct { BOOL bIsDirectory; LPWSTR lpszName; DWORD nSize; - struct tm tmLastModified; + SYSTEMTIME tmLastModified; unsigned short permissions; } FILEPROPERTIESW, *LPFILEPROPERTIESW; typedef struct { - WININETHANDLEHEADER hdr; - WININETFTPSESSIONW *lpFtpSession; + object_header_t hdr; + ftp_session_t *lpFtpSession; DWORD index; DWORD size; LPFILEPROPERTIESW lpafp; @@ -165,46 +179,51 @@ static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"; static const WCHAR szNoAccount[] = {'n','o','a','c','c','o','u','n','t','\0'}; static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam, - INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext); -static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType); -static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket); -static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile); -static INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD_PTR dwContext); -static BOOL FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType); -static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile); -static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs); -static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs); -static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs); -static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs); -static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType); -static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs); -static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs); -static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs); + INTERNET_STATUS_CALLBACK lpfnStatusCB, object_header_t *hdr, DWORD_PTR dwContext); +static BOOL FTP_SendStore(ftp_session_t*, LPCWSTR lpszRemoteFile, DWORD dwType); +static BOOL FTP_GetDataSocket(ftp_session_t*, LPINT nDataSocket); +static BOOL FTP_SendData(ftp_session_t*, INT nDataSocket, HANDLE hFile); +static INT FTP_ReceiveResponse(ftp_session_t*, DWORD_PTR dwContext); +static BOOL FTP_SendRetrieve(ftp_session_t*, LPCWSTR lpszRemoteFile, DWORD dwType); +static BOOL FTP_RetrieveFileData(ftp_session_t*, INT nDataSocket, HANDLE hFile); +static BOOL FTP_InitListenSocket(ftp_session_t*); +static BOOL FTP_ConnectToHost(ftp_session_t*); +static BOOL FTP_SendPassword(ftp_session_t*); +static BOOL FTP_SendAccount(ftp_session_t*); +static BOOL FTP_SendType(ftp_session_t*, DWORD dwType); +static BOOL FTP_SendPort(ftp_session_t*); +static BOOL FTP_DoPassive(ftp_session_t*); +static BOOL FTP_SendPortOrPasv(ftp_session_t*); static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp); static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW fileprop); -static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile, +static BOOL FTP_ParseDirectory(ftp_session_t*, INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW *lpafp, LPDWORD dwfp); -static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile, +static HINTERNET FTP_ReceiveFileList(ftp_session_t*, INT nSocket, LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext); static DWORD FTP_SetResponseError(DWORD dwResponse); static BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData); -static BOOL FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile, +static BOOL FTP_FtpPutFileW(ftp_session_t*, LPCWSTR lpszLocalFile, LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext); -static BOOL FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory); -static BOOL FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory); -static HINTERNET FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs, +static BOOL FTP_FtpSetCurrentDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory); +static BOOL FTP_FtpCreateDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory); +static HINTERNET FTP_FtpFindFirstFileW(ftp_session_t*, LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext); -static BOOL FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszCurrentDirectory, +static BOOL FTP_FtpGetCurrentDirectoryW(ftp_session_t*, LPWSTR lpszCurrentDirectory, LPDWORD lpdwCurrentDirectory); -static BOOL FTP_FtpRenameFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszSrc, LPCWSTR lpszDest); -static BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory); -static BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName); -static HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName, - DWORD fdwAccess, DWORD dwFlags, DWORD_PTR dwContext); -static BOOL FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile, +static BOOL FTP_FtpRenameFileW(ftp_session_t*, LPCWSTR lpszSrc, LPCWSTR lpszDest); +static BOOL FTP_FtpRemoveDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory); +static BOOL FTP_FtpDeleteFileW(ftp_session_t*, LPCWSTR lpszFileName); +static BOOL FTP_FtpGetFileW(ftp_session_t*, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile, BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags, DWORD_PTR dwContext); +/* A temporary helper until we get rid of INTERNET_GetLastError calls */ +static BOOL res_to_le(DWORD res) +{ + if(res != ERROR_SUCCESS) + INTERNET_SetLastError(res); + return res == ERROR_SUCCESS; +} /*********************************************************************** * FtpPutFileA (WININET.@) @@ -223,8 +242,8 @@ BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile, LPWSTR lpwzNewRemoteFile; BOOL ret; - lpwzLocalFile = lpszLocalFile?WININET_strdup_AtoW(lpszLocalFile):NULL; - lpwzNewRemoteFile = lpszNewRemoteFile?WININET_strdup_AtoW(lpszNewRemoteFile):NULL; + lpwzLocalFile = heap_strdupAtoW(lpszLocalFile); + lpwzNewRemoteFile = heap_strdupAtoW(lpszNewRemoteFile); ret = FtpPutFileW(hConnect, lpwzLocalFile, lpwzNewRemoteFile, dwFlags, dwContext); HeapFree(GetProcessHeap(), 0, lpwzLocalFile); @@ -235,7 +254,7 @@ BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile, static void AsyncFtpPutFileProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPPUTFILEW const *req = &workRequest->u.FtpPutFileW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE("%p\n", lpwfs); @@ -259,8 +278,8 @@ static void AsyncFtpPutFileProc(WORKREQUEST *workRequest) BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile, LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext) { - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; BOOL r = FALSE; if (!lpszLocalFile || !lpszNewRemoteFile) @@ -269,7 +288,7 @@ BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile, return FALSE; } - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect ); + lpwfs = (ftp_session_t*) WININET_GetObject( hConnect ); if (!lpwfs) { INTERNET_SetLastError(ERROR_INVALID_HANDLE); @@ -302,12 +321,12 @@ BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile, workRequest.asyncproc = AsyncFtpPutFileProc; workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); - req->lpszLocalFile = WININET_strdupW(lpszLocalFile); - req->lpszNewRemoteFile = WININET_strdupW(lpszNewRemoteFile); + req->lpszLocalFile = heap_strdupW(lpszLocalFile); + req->lpszNewRemoteFile = heap_strdupW(lpszNewRemoteFile); req->dwFlags = dwFlags; req->dwContext = dwContext; - r = INTERNET_AsyncCall(&workRequest); + r = res_to_le(INTERNET_AsyncCall(&workRequest)); } else { @@ -331,12 +350,12 @@ lend: * FALSE on failure * */ -static BOOL FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile, +static BOOL FTP_FtpPutFileW(ftp_session_t *lpwfs, LPCWSTR lpszLocalFile, LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext) { HANDLE hFile; BOOL bSuccess = FALSE; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; INT nResCode; TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", debugstr_w(lpszLocalFile), debugstr_w(lpszNewRemoteFile)); @@ -375,7 +394,10 @@ static BOOL FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile, } if (lpwfs->lstnSocket != -1) + { closesocket(lpwfs->lstnSocket); + lpwfs->lstnSocket = -1; + } if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) { @@ -408,7 +430,7 @@ BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory) LPWSTR lpwzDirectory; BOOL ret; - lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL; + lpwzDirectory = heap_strdupAtoW(lpszDirectory); ret = FtpSetCurrentDirectoryW(hConnect, lpwzDirectory); HeapFree(GetProcessHeap(), 0, lpwzDirectory); return ret; @@ -418,7 +440,7 @@ BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory) static void AsyncFtpSetCurrentDirectoryProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPSETCURRENTDIRECTORYW const *req = &workRequest->u.FtpSetCurrentDirectoryW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE("%p\n", lpwfs); @@ -438,8 +460,8 @@ static void AsyncFtpSetCurrentDirectoryProc(WORKREQUEST *workRequest) */ BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory) { - LPWININETFTPSESSIONW lpwfs = NULL; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs = NULL; + appinfo_t *hIC = NULL; BOOL r = FALSE; if (!lpszDirectory) @@ -448,7 +470,7 @@ BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory) goto lend; } - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect ); + lpwfs = (ftp_session_t*) WININET_GetObject( hConnect ); if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) { INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); @@ -472,9 +494,9 @@ BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory) workRequest.asyncproc = AsyncFtpSetCurrentDirectoryProc; workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); req = &workRequest.u.FtpSetCurrentDirectoryW; - req->lpszDirectory = WININET_strdupW(lpszDirectory); + req->lpszDirectory = heap_strdupW(lpszDirectory); - r = INTERNET_AsyncCall(&workRequest); + r = res_to_le(INTERNET_AsyncCall(&workRequest)); } else { @@ -499,10 +521,10 @@ lend: * FALSE on failure * */ -static BOOL FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory) +static BOOL FTP_FtpSetCurrentDirectoryW(ftp_session_t *lpwfs, LPCWSTR lpszDirectory) { INT nResCode; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; DWORD bSuccess = FALSE; TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory)); @@ -554,7 +576,7 @@ BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory) LPWSTR lpwzDirectory; BOOL ret; - lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL; + lpwzDirectory = heap_strdupAtoW(lpszDirectory); ret = FtpCreateDirectoryW(hConnect, lpwzDirectory); HeapFree(GetProcessHeap(), 0, lpwzDirectory); return ret; @@ -564,7 +586,7 @@ BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory) static void AsyncFtpCreateDirectoryProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPCREATEDIRECTORYW const *req = &workRequest->u.FtpCreateDirectoryW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE(" %p\n", lpwfs); @@ -584,11 +606,11 @@ static void AsyncFtpCreateDirectoryProc(WORKREQUEST *workRequest) */ BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory) { - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; BOOL r = FALSE; - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect ); + lpwfs = (ftp_session_t*) WININET_GetObject( hConnect ); if (!lpwfs) { INTERNET_SetLastError(ERROR_INVALID_HANDLE); @@ -622,9 +644,9 @@ BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory) workRequest.asyncproc = AsyncFtpCreateDirectoryProc; workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); req = &workRequest.u.FtpCreateDirectoryW; - req->lpszDirectory = WININET_strdupW(lpszDirectory); + req->lpszDirectory = heap_strdupW(lpszDirectory); - r = INTERNET_AsyncCall(&workRequest); + r = res_to_le(INTERNET_AsyncCall(&workRequest)); } else { @@ -647,11 +669,11 @@ lend: * FALSE on failure * */ -static BOOL FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory) +static BOOL FTP_FtpCreateDirectoryW(ftp_session_t *lpwfs, LPCWSTR lpszDirectory) { INT nResCode; BOOL bSuccess = FALSE; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory)); @@ -703,14 +725,14 @@ HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect, LPWIN32_FIND_DATAW lpFindFileDataW; HINTERNET ret; - lpwzSearchFile = lpszSearchFile?WININET_strdup_AtoW(lpszSearchFile):NULL; + lpwzSearchFile = heap_strdupAtoW(lpszSearchFile); lpFindFileDataW = lpFindFileData?&wfd:NULL; ret = FtpFindFirstFileW(hConnect, lpwzSearchFile, lpFindFileDataW, dwFlags, dwContext); HeapFree(GetProcessHeap(), 0, lpwzSearchFile); if (ret && lpFindFileData) WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData); - + return ret; } @@ -718,7 +740,7 @@ HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect, static void AsyncFtpFindFirstFileProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPFINDFIRSTFILEW const *req = &workRequest->u.FtpFindFirstFileW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE("%p\n", lpwfs); @@ -740,11 +762,11 @@ static void AsyncFtpFindFirstFileProc(WORKREQUEST *workRequest) HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect, LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext) { - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; HINTERNET r = NULL; - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect ); + lpwfs = (ftp_session_t*) WININET_GetObject( hConnect ); if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) { INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); @@ -766,7 +788,7 @@ HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect, workRequest.asyncproc = AsyncFtpFindFirstFileProc; workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); req = &workRequest.u.FtpFindFirstFileW; - req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : WININET_strdupW(lpszSearchFile); + req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : heap_strdupW(lpszSearchFile); req->lpFindFileData = lpFindFileData; req->dwFlags = dwFlags; req->dwContext= dwContext; @@ -797,11 +819,11 @@ lend: * NULL on failure * */ -static HINTERNET FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs, +static HINTERNET FTP_FtpFindFirstFileW(ftp_session_t *lpwfs, LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext) { INT nResCode; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; HINTERNET hFindNext = NULL; TRACE("\n"); @@ -845,7 +867,10 @@ static HINTERNET FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs, lend: if (lpwfs->lstnSocket != -1) + { closesocket(lpwfs->lstnSocket); + lpwfs->lstnSocket = -1; + } hIC = lpwfs->lpAppInfo; if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) @@ -854,13 +879,13 @@ lend: if (hFindNext) { - iar.dwResult = (DWORD)hFindNext; + iar.dwResult = (DWORD_PTR)hFindNext; iar.dwError = ERROR_SUCCESS; SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED, &iar, sizeof(INTERNET_ASYNC_RESULT)); } - iar.dwResult = (DWORD)hFindNext; + iar.dwResult = (DWORD_PTR)hFindNext; iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError(); SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar, sizeof(INTERNET_ASYNC_RESULT)); @@ -913,7 +938,7 @@ BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDire static void AsyncFtpGetCurrentDirectoryProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPGETCURRENTDIRECTORYW const *req = &workRequest->u.FtpGetCurrentDirectoryW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE("%p\n", lpwfs); @@ -933,13 +958,13 @@ static void AsyncFtpGetCurrentDirectoryProc(WORKREQUEST *workRequest) BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory, LPDWORD lpdwCurrentDirectory) { - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; BOOL r = FALSE; TRACE("%p %p %p\n", hFtpSession, lpszCurrentDirectory, lpdwCurrentDirectory); - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession ); + lpwfs = (ftp_session_t*) WININET_GetObject( hFtpSession ); if (NULL == lpwfs) { INTERNET_SetLastError(ERROR_INVALID_HANDLE); @@ -982,7 +1007,7 @@ BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDir req->lpszDirectory = lpszCurrentDirectory; req->lpdwDirectory = lpdwCurrentDirectory; - r = INTERNET_AsyncCall(&workRequest); + r = res_to_le(INTERNET_AsyncCall(&workRequest)); } else { @@ -1008,11 +1033,11 @@ lend: * FALSE on failure * */ -static BOOL FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszCurrentDirectory, +static BOOL FTP_FtpGetCurrentDirectoryW(ftp_session_t *lpwfs, LPWSTR lpszCurrentDirectory, LPDWORD lpdwCurrentDirectory) { INT nResCode; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; DWORD bSuccess = FALSE; /* Clear any error information */ @@ -1029,7 +1054,7 @@ static BOOL FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszC if (nResCode == 257) /* Extract directory name */ { DWORD firstpos, lastpos, len; - LPWSTR lpszResponseBuffer = WININET_strdup_AtoW(INTERNET_GetResponseBuffer()); + LPWSTR lpszResponseBuffer = heap_strdupAtoW(INTERNET_GetResponseBuffer()); for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++) { @@ -1071,6 +1096,354 @@ lend: return bSuccess; } + +/*********************************************************************** + * FTPFILE_Destroy(internal) + * + * Closes the file transfer handle. This also 'cleans' the data queue of + * the 'transfer complete' message (this is a bit of a hack though :-/ ) + * + */ +static void FTPFILE_Destroy(object_header_t *hdr) +{ + ftp_file_t *lpwh = (ftp_file_t*) hdr; + ftp_session_t *lpwfs = lpwh->lpFtpSession; + INT nResCode; + + TRACE("\n"); + + if (lpwh->cache_file_handle != INVALID_HANDLE_VALUE) + CloseHandle(lpwh->cache_file_handle); + + HeapFree(GetProcessHeap(), 0, lpwh->cache_file); + + if (!lpwh->session_deleted) + lpwfs->download_in_progress = NULL; + + if (lpwh->nDataSocket != -1) + closesocket(lpwh->nDataSocket); + + nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); + if (nResCode > 0 && nResCode != 226) WARN("server reports failed transfer\n"); + + WININET_Release(&lpwh->lpFtpSession->hdr); + + HeapFree(GetProcessHeap(), 0, lpwh); +} + +static DWORD FTPFILE_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) +{ + switch(option) { + case INTERNET_OPTION_HANDLE_TYPE: + TRACE("INTERNET_OPTION_HANDLE_TYPE\n"); + + if (*size < sizeof(ULONG)) + return ERROR_INSUFFICIENT_BUFFER; + + *size = sizeof(DWORD); + *(DWORD*)buffer = INTERNET_HANDLE_TYPE_FTP_FILE; + return ERROR_SUCCESS; + case INTERNET_OPTION_DATAFILE_NAME: + { + DWORD required; + ftp_file_t *file = (ftp_file_t *)hdr; + + TRACE("INTERNET_OPTION_DATAFILE_NAME\n"); + + if (!file->cache_file) + { + *size = 0; + return ERROR_INTERNET_ITEM_NOT_FOUND; + } + if (unicode) + { + required = (lstrlenW(file->cache_file) + 1) * sizeof(WCHAR); + if (*size < required) + return ERROR_INSUFFICIENT_BUFFER; + + *size = required; + memcpy(buffer, file->cache_file, *size); + return ERROR_SUCCESS; + } + else + { + required = WideCharToMultiByte(CP_ACP, 0, file->cache_file, -1, NULL, 0, NULL, NULL); + if (required > *size) + return ERROR_INSUFFICIENT_BUFFER; + + *size = WideCharToMultiByte(CP_ACP, 0, file->cache_file, -1, buffer, *size, NULL, NULL); + return ERROR_SUCCESS; + } + } + } + return INET_QueryOption(option, buffer, size, unicode); +} + +static DWORD FTPFILE_ReadFile(object_header_t *hdr, void *buffer, DWORD size, DWORD *read) +{ + ftp_file_t *file = (ftp_file_t*)hdr; + int res; + DWORD error; + + if (file->nDataSocket == -1) + return ERROR_INTERNET_DISCONNECTED; + + /* FIXME: FTP should use NETCON_ stuff */ + res = recv(file->nDataSocket, buffer, size, MSG_WAITALL); + *read = res>0 ? res : 0; + + error = res >= 0 ? ERROR_SUCCESS : INTERNET_ERROR_BASE; /* FIXME */ + if (error == ERROR_SUCCESS && file->cache_file) + { + DWORD bytes_written; + + if (!WriteFile(file->cache_file_handle, buffer, *read, &bytes_written, NULL)) + WARN("WriteFile failed: %u\n", GetLastError()); + } + return error; +} + +static DWORD FTPFILE_ReadFileExA(object_header_t *hdr, INTERNET_BUFFERSA *buffers, + DWORD flags, DWORD_PTR context) +{ + return FTPFILE_ReadFile(hdr, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength); +} + +static DWORD FTPFILE_ReadFileExW(object_header_t *hdr, INTERNET_BUFFERSW *buffers, + DWORD flags, DWORD_PTR context) +{ + return FTPFILE_ReadFile(hdr, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength); +} + +static DWORD FTPFILE_WriteFile(object_header_t *hdr, const void *buffer, DWORD size, DWORD *written) +{ + ftp_file_t *lpwh = (ftp_file_t*) hdr; + int res; + + res = send(lpwh->nDataSocket, buffer, size, 0); + + *written = res>0 ? res : 0; + return res >= 0 ? ERROR_SUCCESS : sock_get_error(errno); +} + +static void FTP_ReceiveRequestData(ftp_file_t *file, BOOL first_notif) +{ + INTERNET_ASYNC_RESULT iar; + BYTE buffer[4096]; + int available; + + TRACE("%p\n", file); + + available = recv(file->nDataSocket, buffer, sizeof(buffer), MSG_PEEK); + + if(available != -1) { + iar.dwResult = (DWORD_PTR)file->hdr.hInternet; + iar.dwError = first_notif ? 0 : available; + }else { + iar.dwResult = 0; + iar.dwError = INTERNET_GetLastError(); + } + + INTERNET_SendCallback(&file->hdr, file->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar, + sizeof(INTERNET_ASYNC_RESULT)); +} + +static void FTPFILE_AsyncQueryDataAvailableProc(WORKREQUEST *workRequest) +{ + ftp_file_t *file = (ftp_file_t*)workRequest->hdr; + + FTP_ReceiveRequestData(file, FALSE); +} + +static DWORD FTPFILE_QueryDataAvailable(object_header_t *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx) +{ + ftp_file_t *file = (ftp_file_t*) hdr; + int retval, unread = 0; + + TRACE("(%p %p %x %lx)\n", file, available, flags, ctx); + +#ifdef FIONREAD + retval = ioctlsocket(file->nDataSocket, FIONREAD, &unread); + if (!retval) + TRACE("%d bytes of queued, but unread data\n", unread); +#else + FIXME("FIONREAD not available\n"); +#endif + + *available = unread; + + if(!unread) { + BYTE byte; + + *available = 0; + + retval = recv(file->nDataSocket, &byte, 1, MSG_PEEK); + if(retval > 0) { + WORKREQUEST workRequest; + + *available = 0; + workRequest.asyncproc = FTPFILE_AsyncQueryDataAvailableProc; + workRequest.hdr = WININET_AddRef( &file->hdr ); + + INTERNET_AsyncCall(&workRequest); + + return ERROR_IO_PENDING; + } + } + + return ERROR_SUCCESS; +} + + +static const object_vtbl_t FTPFILEVtbl = { + FTPFILE_Destroy, + NULL, + FTPFILE_QueryOption, + NULL, + FTPFILE_ReadFile, + FTPFILE_ReadFileExA, + FTPFILE_ReadFileExW, + FTPFILE_WriteFile, + FTPFILE_QueryDataAvailable, + NULL +}; + +/*********************************************************************** + * FTP_FtpOpenFileW (Internal) + * + * Open a remote file for writing or reading + * + * RETURNS + * HINTERNET handle on success + * NULL on failure + * + */ +static HINTERNET FTP_FtpOpenFileW(ftp_session_t *lpwfs, + LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags, + DWORD_PTR dwContext) +{ + INT nDataSocket; + BOOL bSuccess = FALSE; + ftp_file_t *lpwh = NULL; + appinfo_t *hIC = NULL; + HINTERNET handle = NULL; + + TRACE("\n"); + + /* Clear any error information */ + INTERNET_SetLastError(0); + + if (GENERIC_READ == fdwAccess) + { + /* Set up socket to retrieve data */ + bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags); + } + else if (GENERIC_WRITE == fdwAccess) + { + /* Set up socket to send data */ + bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags); + } + + /* Get data socket to server */ + if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket)) + { + lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(ftp_file_t)); + lpwh->hdr.htype = WH_HFILE; + lpwh->hdr.vtbl = &FTPFILEVtbl; + lpwh->hdr.dwFlags = dwFlags; + lpwh->hdr.dwContext = dwContext; + lpwh->hdr.dwInternalFlags = 0; + lpwh->hdr.refs = 1; + lpwh->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB; + lpwh->nDataSocket = nDataSocket; + lpwh->cache_file = NULL; + lpwh->cache_file_handle = INVALID_HANDLE_VALUE; + lpwh->session_deleted = FALSE; + + WININET_AddRef( &lpwfs->hdr ); + lpwh->lpFtpSession = lpwfs; + list_add_head( &lpwfs->hdr.children, &lpwh->hdr.entry ); + + handle = WININET_AllocHandle( &lpwh->hdr ); + if( !handle ) + goto lend; + + /* Indicate that a download is currently in progress */ + lpwfs->download_in_progress = lpwh; + } + + if (lpwfs->lstnSocket != -1) + { + closesocket(lpwfs->lstnSocket); + lpwfs->lstnSocket = -1; + } + + if (bSuccess && fdwAccess == GENERIC_READ) + { + WCHAR filename[MAX_PATH + 1]; + URL_COMPONENTSW uc; + DWORD len; + + memset(&uc, 0, sizeof(uc)); + uc.dwStructSize = sizeof(uc); + uc.nScheme = INTERNET_SCHEME_FTP; + uc.lpszHostName = lpwfs->servername; + uc.nPort = lpwfs->serverport; + uc.lpszUserName = lpwfs->lpszUserName; + uc.lpszUrlPath = heap_strdupW(lpszFileName); + + if (!InternetCreateUrlW(&uc, 0, NULL, &len) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + WCHAR *url = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + + if (url && InternetCreateUrlW(&uc, 0, url, &len) && CreateUrlCacheEntryW(url, 0, NULL, filename, 0)) + { + lpwh->cache_file = heap_strdupW(filename); + lpwh->cache_file_handle = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (lpwh->cache_file_handle == INVALID_HANDLE_VALUE) + { + WARN("Could not create cache file: %u\n", GetLastError()); + HeapFree(GetProcessHeap(), 0, lpwh->cache_file); + lpwh->cache_file = NULL; + } + } + HeapFree(GetProcessHeap(), 0, url); + } + HeapFree(GetProcessHeap(), 0, uc.lpszUrlPath); + } + + hIC = lpwfs->lpAppInfo; + if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) + { + INTERNET_ASYNC_RESULT iar; + + if (lpwh) + { + iar.dwResult = (DWORD_PTR)handle; + iar.dwError = ERROR_SUCCESS; + SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED, + &iar, sizeof(INTERNET_ASYNC_RESULT)); + } + + if(bSuccess) { + FTP_ReceiveRequestData(lpwh, TRUE); + }else { + iar.dwResult = 0; + iar.dwError = INTERNET_GetLastError(); + SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, + &iar, sizeof(INTERNET_ASYNC_RESULT)); + } + } + +lend: + if( lpwh ) + WININET_Release( &lpwh->hdr ); + + return handle; +} + + /*********************************************************************** * FtpOpenFileA (WININET.@) * @@ -1087,8 +1460,8 @@ HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession, { LPWSTR lpwzFileName; HINTERNET ret; - - lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL; + + lpwzFileName = heap_strdupAtoW(lpszFileName); ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext); HeapFree(GetProcessHeap(), 0, lpwzFileName); return ret; @@ -1098,7 +1471,7 @@ HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession, static void AsyncFtpOpenFileProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPOPENFILEW const *req = &workRequest->u.FtpOpenFileW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE("%p\n", lpwfs); @@ -1121,14 +1494,14 @@ HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags, DWORD_PTR dwContext) { - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; HINTERNET r = NULL; - + TRACE("(%p,%s,0x%08x,0x%08x,0x%08lx)\n", hFtpSession, debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext); - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession ); + lpwfs = (ftp_session_t*) WININET_GetObject( hFtpSession ); if (!lpwfs) { INTERNET_SetLastError(ERROR_INVALID_HANDLE); @@ -1164,7 +1537,7 @@ HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession, workRequest.asyncproc = AsyncFtpOpenFileProc; workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); req = &workRequest.u.FtpOpenFileW; - req->lpszFilename = WININET_strdupW(lpszFileName); + req->lpszFilename = heap_strdupW(lpszFileName); req->dwAccess = fdwAccess; req->dwFlags = dwFlags; req->dwContext = dwContext; @@ -1184,181 +1557,6 @@ lend: } -/*********************************************************************** - * FTPFILE_Destroy(internal) - * - * Closes the file transfer handle. This also 'cleans' the data queue of - * the 'transfer complete' message (this is a bit of a hack though :-/ ) - * - */ -static void FTPFILE_Destroy(WININETHANDLEHEADER *hdr) -{ - LPWININETFTPFILE lpwh = (LPWININETFTPFILE) hdr; - LPWININETFTPSESSIONW lpwfs = lpwh->lpFtpSession; - INT nResCode; - - TRACE("\n"); - - WININET_Release(&lpwh->lpFtpSession->hdr); - - if (!lpwh->session_deleted) - lpwfs->download_in_progress = NULL; - - if (lpwh->nDataSocket != -1) - closesocket(lpwh->nDataSocket); - - nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); - if (nResCode > 0 && nResCode != 226) WARN("server reports failed transfer\n"); - - HeapFree(GetProcessHeap(), 0, lpwh); -} - -static DWORD FTPFILE_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) -{ - switch(option) { - case INTERNET_OPTION_HANDLE_TYPE: - TRACE("INTERNET_OPTION_HANDLE_TYPE\n"); - - if (*size < sizeof(ULONG)) - return ERROR_INSUFFICIENT_BUFFER; - - *size = sizeof(DWORD); - *(DWORD*)buffer = INTERNET_HANDLE_TYPE_FTP_FILE; - return ERROR_SUCCESS; - } - - return INET_QueryOption(option, buffer, size, unicode); -} - -static DWORD FTPFILE_ReadFile(WININETHANDLEHEADER *hdr, void *buffer, DWORD size, DWORD *read) -{ - WININETFTPFILE *file = (WININETFTPFILE*)hdr; - int res; - - if (file->nDataSocket == -1) - return ERROR_INTERNET_DISCONNECTED; - - /* FIXME: FTP should use NETCON_ stuff */ - res = recv(file->nDataSocket, buffer, size, MSG_WAITALL); - *read = res>0 ? res : 0; - - return res>=0 ? ERROR_SUCCESS : INTERNET_ERROR_BASE; /* FIXME*/ -} - -static BOOL FTPFILE_WriteFile(WININETHANDLEHEADER *hdr, const void *buffer, DWORD size, DWORD *written) -{ - LPWININETFTPFILE lpwh = (LPWININETFTPFILE) hdr; - int res; - - res = send(lpwh->nDataSocket, buffer, size, 0); - - *written = res>0 ? res : 0; - return res >= 0; -} - -static const HANDLEHEADERVtbl FTPFILEVtbl = { - FTPFILE_Destroy, - NULL, - FTPFILE_QueryOption, - NULL, - FTPFILE_ReadFile, - NULL, - FTPFILE_WriteFile, - NULL, - NULL -}; - -/*********************************************************************** - * FTP_FtpOpenFileW (Internal) - * - * Open a remote file for writing or reading - * - * RETURNS - * HINTERNET handle on success - * NULL on failure - * - */ -HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs, - LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags, - DWORD_PTR dwContext) -{ - INT nDataSocket; - BOOL bSuccess = FALSE; - LPWININETFTPFILE lpwh = NULL; - LPWININETAPPINFOW hIC = NULL; - HINTERNET handle = NULL; - - TRACE("\n"); - - /* Clear any error information */ - INTERNET_SetLastError(0); - - if (GENERIC_READ == fdwAccess) - { - /* Set up socket to retrieve data */ - bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags); - } - else if (GENERIC_WRITE == fdwAccess) - { - /* Set up socket to send data */ - bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags); - } - - /* Get data socket to server */ - if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket)) - { - lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPFILE)); - lpwh->hdr.htype = WH_HFILE; - lpwh->hdr.vtbl = &FTPFILEVtbl; - lpwh->hdr.dwFlags = dwFlags; - lpwh->hdr.dwContext = dwContext; - lpwh->hdr.refs = 1; - lpwh->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB; - lpwh->nDataSocket = nDataSocket; - lpwh->session_deleted = FALSE; - - WININET_AddRef( &lpwfs->hdr ); - lpwh->lpFtpSession = lpwfs; - list_add_head( &lpwfs->hdr.children, &lpwh->hdr.entry ); - - handle = WININET_AllocHandle( &lpwh->hdr ); - if( !handle ) - goto lend; - - /* Indicate that a download is currently in progress */ - lpwfs->download_in_progress = lpwh; - } - - if (lpwfs->lstnSocket != -1) - closesocket(lpwfs->lstnSocket); - - hIC = lpwfs->lpAppInfo; - if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) - { - INTERNET_ASYNC_RESULT iar; - - if (lpwh) - { - iar.dwResult = (DWORD)handle; - iar.dwError = ERROR_SUCCESS; - SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED, - &iar, sizeof(INTERNET_ASYNC_RESULT)); - } - - iar.dwResult = (DWORD)bSuccess; - iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); - SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, - &iar, sizeof(INTERNET_ASYNC_RESULT)); - } - -lend: - if( lpwh ) - WININET_Release( &lpwh->hdr ); - - return handle; -} - - /*********************************************************************** * FtpGetFileA (WININET.@) * @@ -1377,8 +1575,8 @@ BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszN LPWSTR lpwzNewFile; BOOL ret; - lpwzRemoteFile = lpszRemoteFile?WININET_strdup_AtoW(lpszRemoteFile):NULL; - lpwzNewFile = lpszNewFile?WININET_strdup_AtoW(lpszNewFile):NULL; + lpwzRemoteFile = heap_strdupAtoW(lpszRemoteFile); + lpwzNewFile = heap_strdupAtoW(lpszNewFile); ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext); HeapFree(GetProcessHeap(), 0, lpwzRemoteFile); @@ -1390,7 +1588,7 @@ BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszN static void AsyncFtpGetFileProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPGETFILEW const *req = &workRequest->u.FtpGetFileW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE("%p\n", lpwfs); @@ -1416,8 +1614,8 @@ BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lps BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags, DWORD_PTR dwContext) { - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; BOOL r = FALSE; if (!lpszRemoteFile || !lpszNewFile) @@ -1426,7 +1624,7 @@ BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lps return FALSE; } - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet ); + lpwfs = (ftp_session_t*) WININET_GetObject( hInternet ); if (!lpwfs) { INTERNET_SetLastError(ERROR_INVALID_HANDLE); @@ -1460,14 +1658,14 @@ BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lps workRequest.asyncproc = AsyncFtpGetFileProc; workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); req = &workRequest.u.FtpGetFileW; - req->lpszRemoteFile = WININET_strdupW(lpszRemoteFile); - req->lpszNewFile = WININET_strdupW(lpszNewFile); + req->lpszRemoteFile = heap_strdupW(lpszRemoteFile); + req->lpszNewFile = heap_strdupW(lpszNewFile); req->dwLocalFlagsAttribute = dwLocalFlagsAttribute; req->fFailIfExists = fFailIfExists; req->dwFlags = dwInternetFlags; req->dwContext = dwContext; - r = INTERNET_AsyncCall(&workRequest); + r = res_to_le(INTERNET_AsyncCall(&workRequest)); } else { @@ -1492,13 +1690,13 @@ lend: * FALSE on failure * */ -static BOOL FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile, +static BOOL FTP_FtpGetFileW(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile, BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags, DWORD_PTR dwContext) { BOOL bSuccess = FALSE; HANDLE hFile; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile)); @@ -1537,7 +1735,10 @@ static BOOL FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, } if (lpwfs->lstnSocket != -1) + { closesocket(lpwfs->lstnSocket); + lpwfs->lstnSocket = -1; + } CloseHandle(hFile); @@ -1584,7 +1785,7 @@ BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName) LPWSTR lpwzFileName; BOOL ret; - lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL; + lpwzFileName = heap_strdupAtoW(lpszFileName); ret = FtpDeleteFileW(hFtpSession, lpwzFileName); HeapFree(GetProcessHeap(), 0, lpwzFileName); return ret; @@ -1593,7 +1794,7 @@ BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName) static void AsyncFtpDeleteFileProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPDELETEFILEW const *req = &workRequest->u.FtpDeleteFileW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE("%p\n", lpwfs); @@ -1613,11 +1814,11 @@ static void AsyncFtpDeleteFileProc(WORKREQUEST *workRequest) */ BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName) { - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; BOOL r = FALSE; - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession ); + lpwfs = (ftp_session_t*) WININET_GetObject( hFtpSession ); if (!lpwfs) { INTERNET_SetLastError(ERROR_INVALID_HANDLE); @@ -1651,9 +1852,9 @@ BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName) workRequest.asyncproc = AsyncFtpDeleteFileProc; workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); req = &workRequest.u.FtpDeleteFileW; - req->lpszFilename = WININET_strdupW(lpszFileName); + req->lpszFilename = heap_strdupW(lpszFileName); - r = INTERNET_AsyncCall(&workRequest); + r = res_to_le(INTERNET_AsyncCall(&workRequest)); } else { @@ -1676,11 +1877,11 @@ lend: * FALSE on failure * */ -BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName) +BOOL FTP_FtpDeleteFileW(ftp_session_t *lpwfs, LPCWSTR lpszFileName) { INT nResCode; BOOL bSuccess = FALSE; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; TRACE("%p\n", lpwfs); @@ -1729,7 +1930,7 @@ BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory) LPWSTR lpwzDirectory; BOOL ret; - lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL; + lpwzDirectory = heap_strdupAtoW(lpszDirectory); ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory); HeapFree(GetProcessHeap(), 0, lpwzDirectory); return ret; @@ -1738,7 +1939,7 @@ BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory) static void AsyncFtpRemoveDirectoryProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPREMOVEDIRECTORYW const *req = &workRequest->u.FtpRemoveDirectoryW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE("%p\n", lpwfs); @@ -1758,11 +1959,11 @@ static void AsyncFtpRemoveDirectoryProc(WORKREQUEST *workRequest) */ BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory) { - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; BOOL r = FALSE; - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession ); + lpwfs = (ftp_session_t*) WININET_GetObject( hFtpSession ); if (!lpwfs) { INTERNET_SetLastError(ERROR_INVALID_HANDLE); @@ -1796,9 +1997,9 @@ BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory) workRequest.asyncproc = AsyncFtpRemoveDirectoryProc; workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); req = &workRequest.u.FtpRemoveDirectoryW; - req->lpszDirectory = WININET_strdupW(lpszDirectory); + req->lpszDirectory = heap_strdupW(lpszDirectory); - r = INTERNET_AsyncCall(&workRequest); + r = res_to_le(INTERNET_AsyncCall(&workRequest)); } else { @@ -1821,11 +2022,11 @@ lend: * FALSE on failure * */ -BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory) +BOOL FTP_FtpRemoveDirectoryW(ftp_session_t *lpwfs, LPCWSTR lpszDirectory) { INT nResCode; BOOL bSuccess = FALSE; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; TRACE("\n"); @@ -1876,8 +2077,8 @@ BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDes LPWSTR lpwzDest; BOOL ret; - lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL; - lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL; + lpwzSrc = heap_strdupAtoW(lpszSrc); + lpwzDest = heap_strdupAtoW(lpszDest); ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest); HeapFree(GetProcessHeap(), 0, lpwzSrc); HeapFree(GetProcessHeap(), 0, lpwzDest); @@ -1887,7 +2088,7 @@ BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDes static void AsyncFtpRenameFileProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPRENAMEFILEW const *req = &workRequest->u.FtpRenameFileW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE("%p\n", lpwfs); @@ -1908,11 +2109,11 @@ static void AsyncFtpRenameFileProc(WORKREQUEST *workRequest) */ BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest) { - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; BOOL r = FALSE; - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession ); + lpwfs = (ftp_session_t*) WININET_GetObject( hFtpSession ); if (!lpwfs) { INTERNET_SetLastError(ERROR_INVALID_HANDLE); @@ -1946,10 +2147,10 @@ BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszD workRequest.asyncproc = AsyncFtpRenameFileProc; workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); req = &workRequest.u.FtpRenameFileW; - req->lpszSrcFile = WININET_strdupW(lpszSrc); - req->lpszDestFile = WININET_strdupW(lpszDest); + req->lpszSrcFile = heap_strdupW(lpszSrc); + req->lpszDestFile = heap_strdupW(lpszDest); - r = INTERNET_AsyncCall(&workRequest); + r = res_to_le(INTERNET_AsyncCall(&workRequest)); } else { @@ -1972,12 +2173,11 @@ lend: * FALSE on failure * */ -BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs, - LPCWSTR lpszSrc, LPCWSTR lpszDest) +BOOL FTP_FtpRenameFileW(ftp_session_t *lpwfs, LPCWSTR lpszSrc, LPCWSTR lpszDest) { INT nResCode; BOOL bSuccess = FALSE; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; TRACE("\n"); @@ -2040,7 +2240,7 @@ BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags return FALSE; } - if (!(cmdW = WININET_strdup_AtoW(lpszCommand))) + if (!(cmdW = heap_strdupAtoW(lpszCommand))) { INTERNET_SetLastError(ERROR_OUTOFMEMORY); return FALSE; @@ -2059,7 +2259,7 @@ BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand ) { BOOL r = FALSE; - LPWININETFTPSESSIONW lpwfs; + ftp_session_t *lpwfs; LPSTR cmd = NULL; DWORD len, nBytesSent= 0; INT nResCode, nRC = 0; @@ -2079,7 +2279,7 @@ BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags return FALSE; } - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect ); + lpwfs = (ftp_session_t*) WININET_GetObject( hConnect ); if (!lpwfs) { INTERNET_SetLastError(ERROR_INVALID_HANDLE); @@ -2142,9 +2342,9 @@ lend: * * Deallocate session handle */ -static void FTPSESSION_Destroy(WININETHANDLEHEADER *hdr) +static void FTPSESSION_Destroy(object_header_t *hdr) { - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr; + ftp_session_t *lpwfs = (ftp_session_t*) hdr; TRACE("\n"); @@ -2152,12 +2352,13 @@ static void FTPSESSION_Destroy(WININETHANDLEHEADER *hdr) HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword); HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName); + HeapFree(GetProcessHeap(), 0, lpwfs->servername); HeapFree(GetProcessHeap(), 0, lpwfs); } -static void FTPSESSION_CloseConnection(WININETHANDLEHEADER *hdr) +static void FTPSESSION_CloseConnection(object_header_t *hdr) { - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr; + ftp_session_t *lpwfs = (ftp_session_t*) hdr; TRACE("\n"); @@ -2180,7 +2381,7 @@ static void FTPSESSION_CloseConnection(WININETHANDLEHEADER *hdr) INTERNET_STATUS_CONNECTION_CLOSED, 0, 0); } -static DWORD FTPSESSION_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) +static DWORD FTPSESSION_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) { switch(option) { case INTERNET_OPTION_HANDLE_TYPE: @@ -2197,7 +2398,7 @@ static DWORD FTPSESSION_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void return INET_QueryOption(option, buffer, size, unicode); } -static const HANDLEHEADERVtbl FTPSESSIONVtbl = { +static const object_vtbl_t FTPSESSIONVtbl = { FTPSESSION_Destroy, FTPSESSION_CloseConnection, FTPSESSION_QueryOption, @@ -2230,7 +2431,7 @@ static const HANDLEHEADERVtbl FTPSESSIONVtbl = { * */ -HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, +HINTERNET FTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName, INTERNET_PORT nServerPort, LPCWSTR lpszUserName, LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext, DWORD dwInternalFlags) @@ -2247,8 +2448,9 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, INT nsocket = -1; UINT sock_namelen; BOOL bSuccess = FALSE; - LPWININETFTPSESSIONW lpwfs = NULL; + ftp_session_t *lpwfs = NULL; HINTERNET handle = NULL; + char szaddr[INET_ADDRSTRLEN]; TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n", hIC, debugstr_w(lpszServerName), @@ -2256,13 +2458,13 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, assert( hIC->hdr.htype == WH_HINIT ); - if (NULL == lpszUserName && NULL != lpszPassword) + if ((!lpszUserName || !*lpszUserName) && lpszPassword && *lpszPassword) { INTERNET_SetLastError(ERROR_INVALID_PARAMETER); goto lerror; } - lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW)); + lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(ftp_session_t)); if (NULL == lpwfs) { INTERNET_SetLastError(ERROR_OUTOFMEMORY); @@ -2270,7 +2472,9 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, } if (nServerPort == INTERNET_INVALID_PORT_NUMBER) - nServerPort = INTERNET_DEFAULT_FTP_PORT; + lpwfs->serverport = INTERNET_DEFAULT_FTP_PORT; + else + lpwfs->serverport = nServerPort; lpwfs->hdr.htype = WH_HFTPSESSION; lpwfs->hdr.vtbl = &FTPSESSIONVtbl; @@ -2302,12 +2506,12 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, if(hIC->lpszProxyBypass) FIXME("Proxy bypass is ignored.\n"); } - if ( !lpszUserName) { + if (!lpszUserName || !strlenW(lpszUserName)) { HKEY key; WCHAR szPassword[MAX_PATH]; DWORD len = sizeof(szPassword); - lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername); + lpwfs->lpszUserName = heap_strdupW(szDefaultUsername); RegOpenKeyW(HKEY_CURRENT_USER, szKey, &key); if (RegQueryValueExW(key, szValue, NULL, NULL, (LPBYTE)szPassword, &len)) { @@ -2320,23 +2524,20 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, RegCloseKey(key); TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword)); - lpwfs->lpszPassword = WININET_strdupW(szPassword); + lpwfs->lpszPassword = heap_strdupW(szPassword); } else { - lpwfs->lpszUserName = WININET_strdupW(lpszUserName); - - if (lpszPassword) - lpwfs->lpszPassword = WININET_strdupW(lpszPassword); - else - lpwfs->lpszPassword = WININET_strdupW(szEmpty); + lpwfs->lpszUserName = heap_strdupW(lpszUserName); + lpwfs->lpszPassword = heap_strdupW(lpszPassword ? lpszPassword : szEmpty); } + lpwfs->servername = heap_strdupW(lpszServerName); /* Don't send a handle created callback if this handle was created with InternetOpenUrl */ if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL)) { INTERNET_ASYNC_RESULT iar; - iar.dwResult = (DWORD)handle; + iar.dwResult = (DWORD_PTR)handle; iar.dwError = ERROR_SUCCESS; SendAsyncCallback(&hIC->hdr, dwContext, @@ -2345,16 +2546,25 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, } SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME, - (LPWSTR) lpszServerName, strlenW(lpszServerName)); + (LPWSTR) lpszServerName, (strlenW(lpszServerName)+1) * sizeof(WCHAR)); - if (!GetAddress(lpszServerName, nServerPort, &socketAddr)) + sock_namelen = sizeof(socketAddr); + if (!GetAddress(lpszServerName, lpwfs->serverport, (struct sockaddr *)&socketAddr, &sock_namelen)) { INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED); goto lerror; } + if (socketAddr.sin_family != AF_INET) + { + WARN("unsupported address family %d\n", socketAddr.sin_family); + INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT); + goto lerror; + } + + inet_ntop(socketAddr.sin_family, &socketAddr.sin_addr, szaddr, sizeof(szaddr)); SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED, - (LPWSTR) lpszServerName, strlenW(lpszServerName)); + szaddr, strlen(szaddr)+1); nsocket = socket(AF_INET,SOCK_STREAM,0); if (nsocket == -1) @@ -2364,19 +2574,20 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, } SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER, - &socketAddr, sizeof(struct sockaddr_in)); + szaddr, strlen(szaddr)+1); - if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0) + if (connect(nsocket, (struct sockaddr *)&socketAddr, sock_namelen) < 0) { ERR("Unable to connect (%s)\n", strerror(errno)); INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT); + closesocket(nsocket); } else { TRACE("Connected to server\n"); lpwfs->sndSocket = nsocket; SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER, - &socketAddr, sizeof(struct sockaddr_in)); + szaddr, strlen(szaddr)+1); sock_namelen = sizeof(lpwfs->socketAddress); getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen); @@ -2397,16 +2608,6 @@ lerror: handle = NULL; } - if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) - { - INTERNET_ASYNC_RESULT iar; - - iar.dwResult = bSuccess ? (DWORD_PTR)lpwfs : 0; - iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); - SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE, - &iar, sizeof(INTERNET_ASYNC_RESULT)); - } - return handle; } @@ -2421,7 +2622,7 @@ lerror: * NULL on failure * */ -static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs) +static BOOL FTP_ConnectToHost(ftp_session_t *lpwfs) { INT nResCode; BOOL bSuccess = FALSE; @@ -2465,7 +2666,7 @@ lend: * */ static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam, - INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext) + INTERNET_STATUS_CALLBACK lpfnStatusCB, object_header_t *hdr, DWORD_PTR dwContext) { DWORD len; CHAR *buf; @@ -2520,10 +2721,10 @@ static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam, * */ static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam, - INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext) + INTERNET_STATUS_CALLBACK lpfnStatusCB, object_header_t *hdr, DWORD_PTR dwContext) { BOOL ret; - LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL; + LPSTR lpszParamA = heap_strdupWtoA(lpszParam); ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext); HeapFree(GetProcessHeap(), 0, lpszParamA); return ret; @@ -2539,7 +2740,7 @@ static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam, * 0 on failure * */ -INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD_PTR dwContext) +INT FTP_ReceiveResponse(ftp_session_t *lpwfs, DWORD_PTR dwContext) { LPSTR lpszResponse = INTERNET_GetResponseBuffer(); DWORD nRecv; @@ -2602,7 +2803,7 @@ lerror: * NULL on failure * */ -static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs) +static BOOL FTP_SendPassword(ftp_session_t *lpwfs) { INT nResCode; BOOL bSuccess = FALSE; @@ -2642,7 +2843,7 @@ lend: * FALSE on failure * */ -static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs) +static BOOL FTP_SendAccount(ftp_session_t *lpwfs) { INT nResCode; BOOL bSuccess = FALSE; @@ -2672,7 +2873,7 @@ lend: * FALSE on failure * */ -static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType) +static BOOL FTP_SendStore(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType) { INT nResCode; BOOL bSuccess = FALSE; @@ -2719,10 +2920,10 @@ lend: * FALSE on failure * */ -static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs) +static BOOL FTP_InitListenSocket(ftp_session_t *lpwfs) { BOOL bSuccess = FALSE; - socklen_t namelen = sizeof(struct sockaddr_in); + socklen_t namelen = sizeof(lpwfs->lstnSocketAddress); TRACE("\n"); @@ -2737,9 +2938,9 @@ static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs) lpwfs->lstnSocketAddress = lpwfs->socketAddress; /* and get the system to assign us a port */ - lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0); + lpwfs->lstnSocketAddress.sin_port = htons(0); - if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1) + if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(lpwfs->lstnSocketAddress)) == -1) { TRACE("Unable to bind socket\n"); goto lend; @@ -2778,7 +2979,7 @@ lend: * (i.e. it sends it always), * so we probably don't want to do that either. */ -static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType) +static BOOL FTP_SendType(ftp_session_t *lpwfs, DWORD dwType) { INT nResCode; WCHAR type[] = { 'I','\0' }; @@ -2816,7 +3017,7 @@ lend: * FALSE on failure * */ -static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize) +static BOOL FTP_GetFileSize(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize) { INT nResCode; BOOL bSuccess = FALSE; @@ -2860,7 +3061,7 @@ lend: * FALSE on failure * */ -static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs) +static BOOL FTP_SendPort(ftp_session_t *lpwfs) { static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'}; INT nResCode; @@ -2904,7 +3105,7 @@ lend: * FALSE on failure * */ -static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs) +static BOOL FTP_DoPassive(ftp_session_t *lpwfs) { INT nResCode; BOOL bSuccess = FALSE; @@ -2976,7 +3177,7 @@ lend: } -static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs) +static BOOL FTP_SendPortOrPasv(ftp_session_t *lpwfs) { if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE) { @@ -3005,7 +3206,7 @@ static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs) * FALSE on failure * */ -static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket) +static BOOL FTP_GetDataSocket(ftp_session_t *lpwfs, LPINT nDataSocket) { struct sockaddr_in saddr; socklen_t addrlen = sizeof(struct sockaddr); @@ -3014,6 +3215,7 @@ static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket) if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE) { *nDataSocket = lpwfs->pasvSocket; + lpwfs->pasvSocket = -1; } else { @@ -3035,7 +3237,7 @@ static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket) * FALSE on failure * */ -static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile) +static BOOL FTP_SendData(ftp_session_t *lpwfs, INT nDataSocket, HANDLE hFile) { BY_HANDLE_FILE_INFORMATION fi; DWORD nBytesRead = 0; @@ -3116,7 +3318,7 @@ static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFi * 0 on failure * */ -static BOOL FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType) +static BOOL FTP_SendRetrieve(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType) { INT nResCode; BOOL ret; @@ -3162,7 +3364,7 @@ lend: * FALSE on failure * */ -static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile) +static BOOL FTP_RetrieveFileData(ftp_session_t *lpwfs, INT nDataSocket, HANDLE hFile) { DWORD nBytesWritten; INT nRC = 0; @@ -3202,7 +3404,7 @@ recv_end: * * Deallocate session handle */ -static void FTPFINDNEXT_Destroy(WININETHANDLEHEADER *hdr) +static void FTPFINDNEXT_Destroy(object_header_t *hdr) { LPWININETFTPFINDNEXTW lpwfn = (LPWININETFTPFINDNEXTW) hdr; DWORD i; @@ -3220,7 +3422,7 @@ static void FTPFINDNEXT_Destroy(WININETHANDLEHEADER *hdr) HeapFree(GetProcessHeap(), 0, lpwfn); } -static DWORD WINAPI FTPFINDNEXT_FindNextFileProc(WININETFTPFINDNEXTW *find, LPVOID data) +static DWORD FTPFINDNEXT_FindNextFileProc(WININETFTPFINDNEXTW *find, LPVOID data) { WIN32_FIND_DATAW *find_data = data; DWORD res = ERROR_SUCCESS; @@ -3260,7 +3462,7 @@ static void FTPFINDNEXT_AsyncFindNextFileProc(WORKREQUEST *workRequest) FTPFINDNEXT_FindNextFileProc((WININETFTPFINDNEXTW*)workRequest->hdr, req->lpFindFileData); } -static DWORD FTPFINDNEXT_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) +static DWORD FTPFINDNEXT_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) { switch(option) { case INTERNET_OPTION_HANDLE_TYPE: @@ -3277,7 +3479,7 @@ static DWORD FTPFINDNEXT_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, voi return INET_QueryOption(option, buffer, size, unicode); } -static DWORD FTPFINDNEXT_FindNextFileW(WININETHANDLEHEADER *hdr, void *data) +static DWORD FTPFINDNEXT_FindNextFileW(object_header_t *hdr, void *data) { WININETFTPFINDNEXTW *find = (WININETFTPFINDNEXTW*)hdr; @@ -3299,7 +3501,7 @@ static DWORD FTPFINDNEXT_FindNextFileW(WININETHANDLEHEADER *hdr, void *data) return FTPFINDNEXT_FindNextFileProc(find, data); } -static const HANDLEHEADERVtbl FTPFINDNEXTVtbl = { +static const object_vtbl_t FTPFINDNEXTVtbl = { FTPFINDNEXT_Destroy, NULL, FTPFINDNEXT_QueryOption, @@ -3308,6 +3510,7 @@ static const HANDLEHEADERVtbl FTPFINDNEXTVtbl = { NULL, NULL, NULL, + NULL, FTPFINDNEXT_FindNextFileW }; @@ -3321,7 +3524,7 @@ static const HANDLEHEADERVtbl FTPFINDNEXTVtbl = { * NULL on failure * */ -static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile, +static HINTERNET FTP_ReceiveFileList(ftp_session_t *lpwfs, INT nSocket, LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext) { DWORD dwSize = 0; @@ -3382,9 +3585,7 @@ static BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFi if (lpafp) { - /* Convert 'Unix' time to Windows time */ - RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified), - (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime)); + SystemTimeToFileTime( &lpafp->tmLastModified, &lpFindFileData->ftLastAccessTime ); lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime; lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime; @@ -3452,12 +3653,12 @@ static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERT lpfp->nSize = atol(pszToken); } - lpfp->tmLastModified.tm_sec = 0; - lpfp->tmLastModified.tm_min = 0; - lpfp->tmLastModified.tm_hour = 0; - lpfp->tmLastModified.tm_mday = 0; - lpfp->tmLastModified.tm_mon = 0; - lpfp->tmLastModified.tm_year = 0; + lpfp->tmLastModified.wSecond = 0; + lpfp->tmLastModified.wMinute = 0; + lpfp->tmLastModified.wHour = 0; + lpfp->tmLastModified.wDay = 0; + lpfp->tmLastModified.wMonth = 0; + lpfp->tmLastModified.wYear = 0; /* Determine month */ pszToken = strtok(NULL, szSpace); @@ -3465,38 +3666,35 @@ static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERT if(strlen(pszToken) >= 3) { pszToken[3] = 0; if((pszTmp = StrStrIA(szMonths, pszToken))) - lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1; + lpfp->tmLastModified.wMonth = ((pszTmp - szMonths) / 3)+1; } /* Determine day */ pszToken = strtok(NULL, szSpace); if(!pszToken) continue; - lpfp->tmLastModified.tm_mday = atoi(pszToken); + lpfp->tmLastModified.wDay = atoi(pszToken); /* Determine time or year */ pszToken = strtok(NULL, szSpace); if(!pszToken) continue; if((pszTmp = strchr(pszToken, ':'))) { - struct tm* apTM; - time_t aTime; + SYSTEMTIME curr_time; *pszTmp = 0; pszTmp++; - lpfp->tmLastModified.tm_min = atoi(pszTmp); - lpfp->tmLastModified.tm_hour = atoi(pszToken); - time(&aTime); - apTM = localtime(&aTime); - lpfp->tmLastModified.tm_year = apTM->tm_year; + lpfp->tmLastModified.wMinute = atoi(pszTmp); + lpfp->tmLastModified.wHour = atoi(pszToken); + GetLocalTime( &curr_time ); + lpfp->tmLastModified.wYear = curr_time.wYear; } else { - lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900; - lpfp->tmLastModified.tm_hour = 12; + lpfp->tmLastModified.wYear = atoi(pszToken); + lpfp->tmLastModified.wHour = 12; } - TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n", - lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec, - (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year, - lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday); + TRACE("Mod time: %02d:%02d:%02d %04d/%02d/%02d\n", + lpfp->tmLastModified.wHour, lpfp->tmLastModified.wMinute, lpfp->tmLastModified.wSecond, + lpfp->tmLastModified.wYear, lpfp->tmLastModified.wMonth, lpfp->tmLastModified.wDay); pszToken = strtok(NULL, szSpace); if(!pszToken) continue; - lpfp->lpszName = WININET_strdup_AtoW(pszToken); + lpfp->lpszName = heap_strdupAtoW(pszToken); TRACE("File: %s\n", debugstr_w(lpfp->lpszName)); } /* NT way of parsing ... : @@ -3505,32 +3703,31 @@ static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERT 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz */ else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) { + int mon, mday, year, hour, min; lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */ - sscanf(pszToken, "%d-%d-%d", - &lpfp->tmLastModified.tm_mon, - &lpfp->tmLastModified.tm_mday, - &lpfp->tmLastModified.tm_year); + sscanf(pszToken, "%d-%d-%d", &mon, &mday, &year); + lpfp->tmLastModified.wDay = mday; + lpfp->tmLastModified.wMonth = mon; + lpfp->tmLastModified.wYear = year; /* Hacky and bad Y2K protection :-) */ - if (lpfp->tmLastModified.tm_year < 70) - lpfp->tmLastModified.tm_year += 100; - + if (lpfp->tmLastModified.wYear < 70) lpfp->tmLastModified.wYear += 2000; + pszToken = strtok(NULL, szSpace); if(!pszToken) continue; - sscanf(pszToken, "%d:%d", - &lpfp->tmLastModified.tm_hour, - &lpfp->tmLastModified.tm_min); + sscanf(pszToken, "%d:%d", &hour, &min); + lpfp->tmLastModified.wHour = hour; + lpfp->tmLastModified.wMinute = min; if((pszToken[5] == 'P') && (pszToken[6] == 'M')) { - lpfp->tmLastModified.tm_hour += 12; + lpfp->tmLastModified.wHour += 12; } - lpfp->tmLastModified.tm_sec = 0; + lpfp->tmLastModified.wSecond = 0; + + TRACE("Mod time: %02d:%02d:%02d %04d/%02d/%02d\n", + lpfp->tmLastModified.wHour, lpfp->tmLastModified.wMinute, lpfp->tmLastModified.wSecond, + lpfp->tmLastModified.wYear, lpfp->tmLastModified.wMonth, lpfp->tmLastModified.wDay); - TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n", - lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec, - (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year, - lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday); - pszToken = strtok(NULL, szSpace); if(!pszToken) continue; if(!strcasecmp(pszToken, "")) { @@ -3546,7 +3743,7 @@ static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERT pszToken = strtok(NULL, szSpace); if(!pszToken) continue; - lpfp->lpszName = WININET_strdup_AtoW(pszToken); + lpfp->lpszName = heap_strdupAtoW(pszToken); TRACE("Name: %s\n", debugstr_w(lpfp->lpszName)); } /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */ @@ -3578,7 +3775,7 @@ static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERT * TRUE on success * FALSE on failure */ -static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile, +static BOOL FTP_ParseDirectory(ftp_session_t *lpwfs, INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW *lpafp, LPDWORD dwfp) { BOOL bSuccess = TRUE; diff --git a/reactos/dll/win32/wininet/http.c b/reactos/dll/win32/wininet/http.c index f0ad6beddc1..5b7459db6f7 100644 --- a/reactos/dll/win32/wininet/http.c +++ b/reactos/dll/win32/wininet/http.c @@ -29,6 +29,10 @@ #include "config.h" #include "wine/port.h" +#if defined(__MINGW32__) || defined (_MSC_VER) +#include +#endif + #include #ifdef HAVE_SYS_SOCKET_H # include @@ -44,6 +48,9 @@ #endif #include #include +#ifdef HAVE_ZLIB +# include +#endif #include "windef.h" #include "winbase.h" @@ -59,6 +66,7 @@ #include "internet.h" #include "wine/debug.h" +#include "wine/exception.h" #include "wine/unicode.h" #include "inet_ntop.c" @@ -67,23 +75,77 @@ WINE_DEFAULT_DEBUG_CHANNEL(wininet); static const WCHAR g_szHttp1_0[] = {'H','T','T','P','/','1','.','0',0}; static const WCHAR g_szHttp1_1[] = {'H','T','T','P','/','1','.','1',0}; -static const WCHAR g_szReferer[] = {'R','e','f','e','r','e','r',0}; -static const WCHAR g_szAccept[] = {'A','c','c','e','p','t',0}; -static const WCHAR g_szUserAgent[] = {'U','s','e','r','-','A','g','e','n','t',0}; -static const WCHAR szHost[] = { 'H','o','s','t',0 }; +static const WCHAR szOK[] = {'O','K',0}; +static const WCHAR szDefaultHeader[] = {'H','T','T','P','/','1','.','0',' ','2','0','0',' ','O','K',0}; +static const WCHAR hostW[] = { 'H','o','s','t',0 }; static const WCHAR szAuthorization[] = { 'A','u','t','h','o','r','i','z','a','t','i','o','n',0 }; static const WCHAR szProxy_Authorization[] = { 'P','r','o','x','y','-','A','u','t','h','o','r','i','z','a','t','i','o','n',0 }; static const WCHAR szStatus[] = { 'S','t','a','t','u','s',0 }; static const WCHAR szKeepAlive[] = {'K','e','e','p','-','A','l','i','v','e',0}; static const WCHAR szGET[] = { 'G','E','T', 0 }; +static const WCHAR szHEAD[] = { 'H','E','A','D', 0 }; +static const WCHAR szCrLf[] = {'\r','\n', 0}; + +static const WCHAR szAccept[] = { 'A','c','c','e','p','t',0 }; +static const WCHAR szAccept_Charset[] = { 'A','c','c','e','p','t','-','C','h','a','r','s','e','t', 0 }; +static const WCHAR szAccept_Encoding[] = { 'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',0 }; +static const WCHAR szAccept_Language[] = { 'A','c','c','e','p','t','-','L','a','n','g','u','a','g','e',0 }; +static const WCHAR szAccept_Ranges[] = { 'A','c','c','e','p','t','-','R','a','n','g','e','s',0 }; +static const WCHAR szAge[] = { 'A','g','e',0 }; +static const WCHAR szAllow[] = { 'A','l','l','o','w',0 }; +static const WCHAR szCache_Control[] = { 'C','a','c','h','e','-','C','o','n','t','r','o','l',0 }; +static const WCHAR szConnection[] = { 'C','o','n','n','e','c','t','i','o','n',0 }; +static const WCHAR szContent_Base[] = { 'C','o','n','t','e','n','t','-','B','a','s','e',0 }; +static const WCHAR szContent_Encoding[] = { 'C','o','n','t','e','n','t','-','E','n','c','o','d','i','n','g',0 }; +static const WCHAR szContent_ID[] = { 'C','o','n','t','e','n','t','-','I','D',0 }; +static const WCHAR szContent_Language[] = { 'C','o','n','t','e','n','t','-','L','a','n','g','u','a','g','e',0 }; +static const WCHAR szContent_Length[] = { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0 }; +static const WCHAR szContent_Location[] = { 'C','o','n','t','e','n','t','-','L','o','c','a','t','i','o','n',0 }; +static const WCHAR szContent_MD5[] = { 'C','o','n','t','e','n','t','-','M','D','5',0 }; +static const WCHAR szContent_Range[] = { 'C','o','n','t','e','n','t','-','R','a','n','g','e',0 }; +static const WCHAR szContent_Transfer_Encoding[] = { 'C','o','n','t','e','n','t','-','T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 }; +static const WCHAR szContent_Type[] = { 'C','o','n','t','e','n','t','-','T','y','p','e',0 }; +static const WCHAR szCookie[] = { 'C','o','o','k','i','e',0 }; +static const WCHAR szDate[] = { 'D','a','t','e',0 }; +static const WCHAR szFrom[] = { 'F','r','o','m',0 }; +static const WCHAR szETag[] = { 'E','T','a','g',0 }; +static const WCHAR szExpect[] = { 'E','x','p','e','c','t',0 }; +static const WCHAR szExpires[] = { 'E','x','p','i','r','e','s',0 }; +static const WCHAR szIf_Match[] = { 'I','f','-','M','a','t','c','h',0 }; +static const WCHAR szIf_Modified_Since[] = { 'I','f','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 }; +static const WCHAR szIf_None_Match[] = { 'I','f','-','N','o','n','e','-','M','a','t','c','h',0 }; +static const WCHAR szIf_Range[] = { 'I','f','-','R','a','n','g','e',0 }; +static const WCHAR szIf_Unmodified_Since[] = { 'I','f','-','U','n','m','o','d','i','f','i','e','d','-','S','i','n','c','e',0 }; +static const WCHAR szLast_Modified[] = { 'L','a','s','t','-','M','o','d','i','f','i','e','d',0 }; +static const WCHAR szLocation[] = { 'L','o','c','a','t','i','o','n',0 }; +static const WCHAR szMax_Forwards[] = { 'M','a','x','-','F','o','r','w','a','r','d','s',0 }; +static const WCHAR szMime_Version[] = { 'M','i','m','e','-','V','e','r','s','i','o','n',0 }; +static const WCHAR szPragma[] = { 'P','r','a','g','m','a',0 }; +static const WCHAR szProxy_Authenticate[] = { 'P','r','o','x','y','-','A','u','t','h','e','n','t','i','c','a','t','e',0 }; +static const WCHAR szProxy_Connection[] = { 'P','r','o','x','y','-','C','o','n','n','e','c','t','i','o','n',0 }; +static const WCHAR szPublic[] = { 'P','u','b','l','i','c',0 }; +static const WCHAR szRange[] = { 'R','a','n','g','e',0 }; +static const WCHAR szReferer[] = { 'R','e','f','e','r','e','r',0 }; +static const WCHAR szRetry_After[] = { 'R','e','t','r','y','-','A','f','t','e','r',0 }; +static const WCHAR szServer[] = { 'S','e','r','v','e','r',0 }; +static const WCHAR szSet_Cookie[] = { 'S','e','t','-','C','o','o','k','i','e',0 }; +static const WCHAR szTransfer_Encoding[] = { 'T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 }; +static const WCHAR szUnless_Modified_Since[] = { 'U','n','l','e','s','s','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 }; +static const WCHAR szUpgrade[] = { 'U','p','g','r','a','d','e',0 }; +static const WCHAR szURI[] = { 'U','R','I',0 }; +static const WCHAR szUser_Agent[] = { 'U','s','e','r','-','A','g','e','n','t',0 }; +static const WCHAR szVary[] = { 'V','a','r','y',0 }; +static const WCHAR szVia[] = { 'V','i','a',0 }; +static const WCHAR szWarning[] = { 'W','a','r','n','i','n','g',0 }; +static const WCHAR szWWW_Authenticate[] = { 'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',0 }; #define MAXHOSTNAME 100 #define MAX_FIELD_VALUE_LEN 256 #define MAX_FIELD_LEN 256 -#define HTTP_REFERER g_szReferer -#define HTTP_ACCEPT g_szAccept -#define HTTP_USERAGENT g_szUserAgent +#define HTTP_REFERER szReferer +#define HTTP_ACCEPT szAccept +#define HTTP_USERAGENT szUser_Agent #define HTTP_ADDHDR_FLAG_ADD 0x20000000 #define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000 @@ -108,23 +170,54 @@ struct HttpAuthInfo BOOL finished; /* finished authenticating */ }; -static BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr); -static BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear); -static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier); -static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer); -static BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr); -static INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField, INT index, BOOL Request); -static BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, DWORD index); -static LPWSTR HTTP_build_req( LPCWSTR *list, int len ); -static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD - dwInfoLevel, LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD - lpdwIndex); -static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl); -static UINT HTTP_DecodeBase64(LPCWSTR base64, LPSTR bin); -static BOOL HTTP_VerifyValidHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field); -static void HTTP_DrainContent(WININETHTTPREQW *req); -LPHTTPHEADERW HTTP_GetHeader(LPWININETHTTPREQW req, LPCWSTR head) +struct gzip_stream_t { +#ifdef HAVE_ZLIB + z_stream zstream; +#endif + BYTE buf[8192]; + DWORD buf_size; + DWORD buf_pos; + BOOL end_of_data; +}; + +typedef struct _authorizationData +{ + struct list entry; + + LPWSTR lpszwHost; + LPWSTR lpszwRealm; + LPSTR lpszAuthorization; + UINT AuthorizationLen; +} authorizationData; + +static struct list basicAuthorizationCache = LIST_INIT(basicAuthorizationCache); + +static CRITICAL_SECTION authcache_cs; +static CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &authcache_cs, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": authcache_cs") } +}; +static CRITICAL_SECTION authcache_cs = { &critsect_debug, -1, 0, 0, 0, 0 }; + +static DWORD HTTP_OpenConnection(http_request_t *req); +static BOOL HTTP_GetResponseHeaders(http_request_t *req, BOOL clear); +static DWORD HTTP_ProcessHeader(http_request_t *req, LPCWSTR field, LPCWSTR value, DWORD dwModifier); +static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer); +static DWORD HTTP_InsertCustomHeader(http_request_t *req, LPHTTPHEADERW lpHdr); +static INT HTTP_GetCustomHeaderIndex(http_request_t *req, LPCWSTR lpszField, INT index, BOOL Request); +static BOOL HTTP_DeleteCustomHeader(http_request_t *req, DWORD index); +static LPWSTR HTTP_build_req( LPCWSTR *list, int len ); +static DWORD HTTP_HttpQueryInfoW(http_request_t*, DWORD, LPVOID, LPDWORD, LPDWORD); +static LPWSTR HTTP_GetRedirectURL(http_request_t *req, LPCWSTR lpszUrl); +static UINT HTTP_DecodeBase64(LPCWSTR base64, LPSTR bin); +static BOOL HTTP_VerifyValidHeader(http_request_t *req, LPCWSTR field); +static void HTTP_DrainContent(http_request_t *req); +static BOOL HTTP_FinishedReading(http_request_t *req); + +static LPHTTPHEADERW HTTP_GetHeader(http_request_t *req, LPCWSTR head) { int HeaderIndex = 0; HeaderIndex = HTTP_GetCustomHeaderIndex(req, head, 0, TRUE); @@ -134,6 +227,91 @@ LPHTTPHEADERW HTTP_GetHeader(LPWININETHTTPREQW req, LPCWSTR head) return &req->pCustHeaders[HeaderIndex]; } +#ifdef HAVE_ZLIB + +static voidpf wininet_zalloc(voidpf opaque, uInt items, uInt size) +{ + return HeapAlloc(GetProcessHeap(), 0, items*size); +} + +static void wininet_zfree(voidpf opaque, voidpf address) +{ + HeapFree(GetProcessHeap(), 0, address); +} + +static void init_gzip_stream(http_request_t *req) +{ + gzip_stream_t *gzip_stream; + int index, zres; + + gzip_stream = HeapAlloc(GetProcessHeap(), 0, sizeof(gzip_stream_t)); + gzip_stream->zstream.zalloc = wininet_zalloc; + gzip_stream->zstream.zfree = wininet_zfree; + gzip_stream->zstream.opaque = NULL; + gzip_stream->zstream.next_in = NULL; + gzip_stream->zstream.avail_in = 0; + gzip_stream->zstream.next_out = NULL; + gzip_stream->zstream.avail_out = 0; + gzip_stream->buf_pos = 0; + gzip_stream->buf_size = 0; + gzip_stream->end_of_data = FALSE; + + zres = inflateInit2(&gzip_stream->zstream, 0x1f); + if(zres != Z_OK) { + ERR("inflateInit failed: %d\n", zres); + HeapFree(GetProcessHeap(), 0, gzip_stream); + return; + } + + req->gzip_stream = gzip_stream; + + index = HTTP_GetCustomHeaderIndex(req, szContent_Length, 0, FALSE); + if(index != -1) + HTTP_DeleteCustomHeader(req, index); +} + +#else + +static void init_gzip_stream(http_request_t *req) +{ + ERR("gzip stream not supported, missing zlib.\n"); +} + +#endif + +/* set the request content length based on the headers */ +static DWORD set_content_length( http_request_t *lpwhr ) +{ + static const WCHAR szChunked[] = {'c','h','u','n','k','e','d',0}; + WCHAR encoding[20]; + DWORD size; + + size = sizeof(lpwhr->dwContentLength); + if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH, + &lpwhr->dwContentLength, &size, NULL) != ERROR_SUCCESS) + lpwhr->dwContentLength = ~0u; + + size = sizeof(encoding); + if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_TRANSFER_ENCODING, encoding, &size, NULL) == ERROR_SUCCESS && + !strcmpiW(encoding, szChunked)) + { + lpwhr->dwContentLength = ~0u; + lpwhr->read_chunked = TRUE; + } + + if(lpwhr->decoding) { + int encoding_idx; + + static const WCHAR gzipW[] = {'g','z','i','p',0}; + + encoding_idx = HTTP_GetCustomHeaderIndex(lpwhr, szContent_Encoding, 0, FALSE); + if(encoding_idx != -1 && !strcmpiW(lpwhr->pCustHeaders[encoding_idx].lpszValue, gzipW)) + init_gzip_stream(lpwhr); + } + + return lpwhr->dwContentLength; +} + /*********************************************************************** * HTTP_Tokenize (internal) * @@ -146,21 +324,26 @@ static LPWSTR * HTTP_Tokenize(LPCWSTR string, LPCWSTR token_string) int i; LPCWSTR next_token; - /* empty string has no tokens */ - if (*string) - tokens++; - /* count tokens */ - for (i = 0; string[i]; i++) - if (!strncmpW(string+i, token_string, strlenW(token_string))) - { - DWORD j; + if (string) + { + /* empty string has no tokens */ + if (*string) tokens++; - /* we want to skip over separators, but not the null terminator */ - for (j = 0; j < strlenW(token_string) - 1; j++) - if (!string[i+j]) - break; - i += j; + /* count tokens */ + for (i = 0; string[i]; i++) + { + if (!strncmpW(string+i, token_string, strlenW(token_string))) + { + DWORD j; + tokens++; + /* we want to skip over separators, but not the null terminator */ + for (j = 0; j < strlenW(token_string) - 1; j++) + if (!string[i+j]) + break; + i += j; + } } + } /* add 1 for terminating NULL */ token_array = HeapAlloc(GetProcessHeap(), 0, (tokens+1) * sizeof(*token_array)); @@ -194,33 +377,14 @@ static void HTTP_FreeTokens(LPWSTR * token_array) HeapFree(GetProcessHeap(), 0, token_array); } -/* ********************************************************************** - * - * Helper functions for the HttpSendRequest(Ex) functions - * - */ -static void AsyncHttpSendRequestProc(WORKREQUEST *workRequest) -{ - struct WORKREQ_HTTPSENDREQUESTW const *req = &workRequest->u.HttpSendRequestW; - LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) workRequest->hdr; - - TRACE("%p\n", lpwhr); - - HTTP_HttpSendRequestW(lpwhr, req->lpszHeader, - req->dwHeaderLength, req->lpOptional, req->dwOptionalLength, - req->dwContentLength, req->bEndRequest); - - HeapFree(GetProcessHeap(), 0, req->lpszHeader); -} - -static void HTTP_FixURL( LPWININETHTTPREQW lpwhr) +static void HTTP_FixURL(http_request_t *lpwhr) { static const WCHAR szSlash[] = { '/',0 }; static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/', 0 }; /* If we don't have a path we set it to root */ if (NULL == lpwhr->lpszPath) - lpwhr->lpszPath = WININET_strdupW(szSlash); + lpwhr->lpszPath = heap_strdupW(szSlash); else /* remove \r and \n*/ { int nLen = strlenW(lpwhr->lpszPath); @@ -249,7 +413,7 @@ static void HTTP_FixURL( LPWININETHTTPREQW lpwhr) } } -static LPWSTR HTTP_BuildHeaderRequestString( LPWININETHTTPREQW lpwhr, LPCWSTR verb, LPCWSTR path, LPCWSTR version ) +static LPWSTR HTTP_BuildHeaderRequestString( http_request_t *lpwhr, LPCWSTR verb, LPCWSTR path, LPCWSTR version ) { LPWSTR requestString; DWORD len, n; @@ -258,7 +422,6 @@ static LPWSTR HTTP_BuildHeaderRequestString( LPWININETHTTPREQW lpwhr, LPCWSTR ve LPWSTR p; static const WCHAR szSpace[] = { ' ',0 }; - static const WCHAR szcrlf[] = {'\r','\n', 0}; static const WCHAR szColon[] = { ':',' ',0 }; static const WCHAR sztwocrlf[] = {'\r','\n','\r','\n', 0}; @@ -279,7 +442,7 @@ static LPWSTR HTTP_BuildHeaderRequestString( LPWININETHTTPREQW lpwhr, LPCWSTR ve { if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) { - req[n++] = szcrlf; + req[n++] = szCrLf; req[n++] = lpwhr->pCustHeaders[i].lpszField; req[n++] = szColon; req[n++] = lpwhr->pCustHeaders[i].lpszValue; @@ -309,103 +472,176 @@ static LPWSTR HTTP_BuildHeaderRequestString( LPWININETHTTPREQW lpwhr, LPCWSTR ve return requestString; } -static void HTTP_ProcessCookies( LPWININETHTTPREQW lpwhr ) +static void HTTP_ProcessCookies( http_request_t *lpwhr ) { - static const WCHAR szSet_Cookie[] = { 'S','e','t','-','C','o','o','k','i','e',0 }; int HeaderIndex; + int numCookies = 0; LPHTTPHEADERW setCookieHeader; - HeaderIndex = HTTP_GetCustomHeaderIndex(lpwhr, szSet_Cookie, 0, FALSE); - if (HeaderIndex == -1) - return; - setCookieHeader = &lpwhr->pCustHeaders[HeaderIndex]; - - if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES) && setCookieHeader->lpszValue) + while((HeaderIndex = HTTP_GetCustomHeaderIndex(lpwhr, szSet_Cookie, numCookies, FALSE)) != -1) { - int nPosStart = 0, nPosEnd = 0, len; - static const WCHAR szFmt[] = { 'h','t','t','p',':','/','/','%','s','/',0}; + setCookieHeader = &lpwhr->pCustHeaders[HeaderIndex]; - while (setCookieHeader->lpszValue[nPosEnd] != '\0') + if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES) && setCookieHeader->lpszValue) { - LPWSTR buf_cookie, cookie_name, cookie_data; + int len; + static const WCHAR szFmt[] = { 'h','t','t','p',':','/','/','%','s','%','s',0}; LPWSTR buf_url; - LPWSTR domain = NULL; LPHTTPHEADERW Host; - int nEqualPos = 0; - while (setCookieHeader->lpszValue[nPosEnd] != ';' && setCookieHeader->lpszValue[nPosEnd] != ',' && - setCookieHeader->lpszValue[nPosEnd] != '\0') - { - nPosEnd++; - } - if (setCookieHeader->lpszValue[nPosEnd] == ';') - { - /* fixme: not case sensitive, strcasestr is gnu only */ - int nDomainPosEnd = 0; - int nDomainPosStart = 0, nDomainLength = 0; - static const WCHAR szDomain[] = {'d','o','m','a','i','n','=',0}; - LPWSTR lpszDomain = strstrW(&setCookieHeader->lpszValue[nPosEnd], szDomain); - if (lpszDomain) - { /* they have specified their own domain, lets use it */ - while (lpszDomain[nDomainPosEnd] != ';' && lpszDomain[nDomainPosEnd] != ',' && - lpszDomain[nDomainPosEnd] != '\0') - { - nDomainPosEnd++; - } - nDomainPosStart = strlenW(szDomain); - nDomainLength = (nDomainPosEnd - nDomainPosStart) + 1; - domain = HeapAlloc(GetProcessHeap(), 0, (nDomainLength + 1)*sizeof(WCHAR)); - lstrcpynW(domain, &lpszDomain[nDomainPosStart], nDomainLength + 1); - } - } - if (setCookieHeader->lpszValue[nPosEnd] == '\0') break; - buf_cookie = HeapAlloc(GetProcessHeap(), 0, ((nPosEnd - nPosStart) + 1)*sizeof(WCHAR)); - lstrcpynW(buf_cookie, &setCookieHeader->lpszValue[nPosStart], (nPosEnd - nPosStart) + 1); - TRACE("%s\n", debugstr_w(buf_cookie)); - while (buf_cookie[nEqualPos] != '=' && buf_cookie[nEqualPos] != '\0') - { - nEqualPos++; - } - if (buf_cookie[nEqualPos] == '\0' || buf_cookie[nEqualPos + 1] == '\0') - { - HeapFree(GetProcessHeap(), 0, buf_cookie); - break; - } - - cookie_name = HeapAlloc(GetProcessHeap(), 0, (nEqualPos + 1)*sizeof(WCHAR)); - lstrcpynW(cookie_name, buf_cookie, nEqualPos + 1); - cookie_data = &buf_cookie[nEqualPos + 1]; - - Host = HTTP_GetHeader(lpwhr,szHost); - len = lstrlenW((domain ? domain : (Host?Host->lpszValue:NULL))) + - strlenW(lpwhr->lpszPath) + 9; + Host = HTTP_GetHeader(lpwhr, hostW); + len = lstrlenW(Host->lpszValue) + 9 + lstrlenW(lpwhr->lpszPath); buf_url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - sprintfW(buf_url, szFmt, (domain ? domain : (Host?Host->lpszValue:NULL))); /* FIXME PATH!!! */ - InternetSetCookieW(buf_url, cookie_name, cookie_data); + sprintfW(buf_url, szFmt, Host->lpszValue, lpwhr->lpszPath); + InternetSetCookieW(buf_url, NULL, setCookieHeader->lpszValue); HeapFree(GetProcessHeap(), 0, buf_url); - HeapFree(GetProcessHeap(), 0, buf_cookie); - HeapFree(GetProcessHeap(), 0, cookie_name); - HeapFree(GetProcessHeap(), 0, domain); - nPosStart = nPosEnd; } + numCookies++; } } -static inline BOOL is_basic_auth_value( LPCWSTR pszAuthValue ) +static void strip_spaces(LPWSTR start) { - static const WCHAR szBasic[] = {'B','a','s','i','c'}; /* Note: not nul-terminated */ - return !strncmpiW(pszAuthValue, szBasic, ARRAYSIZE(szBasic)) && - ((pszAuthValue[ARRAYSIZE(szBasic)] == ' ') || !pszAuthValue[ARRAYSIZE(szBasic)]); + LPWSTR str = start; + LPWSTR end; + + while (*str == ' ' && *str != '\0') + str++; + + if (str != start) + memmove(start, str, sizeof(WCHAR) * (strlenW(str) + 1)); + + end = start + strlenW(start) - 1; + while (end >= start && *end == ' ') + { + *end = '\0'; + end--; + } } -static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue, +static inline BOOL is_basic_auth_value( LPCWSTR pszAuthValue, LPWSTR *pszRealm ) +{ + static const WCHAR szBasic[] = {'B','a','s','i','c'}; /* Note: not nul-terminated */ + static const WCHAR szRealm[] = {'r','e','a','l','m'}; /* Note: not nul-terminated */ + BOOL is_basic; + is_basic = !strncmpiW(pszAuthValue, szBasic, ARRAYSIZE(szBasic)) && + ((pszAuthValue[ARRAYSIZE(szBasic)] == ' ') || !pszAuthValue[ARRAYSIZE(szBasic)]); + if (is_basic && pszRealm) + { + LPCWSTR token; + LPCWSTR ptr = &pszAuthValue[ARRAYSIZE(szBasic)]; + LPCWSTR realm; + ptr++; + *pszRealm=NULL; + token = strchrW(ptr,'='); + if (!token) + return TRUE; + realm = ptr; + while (*realm == ' ' && *realm != '\0') + realm++; + if(!strncmpiW(realm, szRealm, ARRAYSIZE(szRealm)) && + (realm[ARRAYSIZE(szRealm)] == ' ' || realm[ARRAYSIZE(szRealm)] == '=')) + { + token++; + while (*token == ' ' && *token != '\0') + token++; + if (*token == '\0') + return TRUE; + *pszRealm = heap_strdupW(token); + strip_spaces(*pszRealm); + } + } + + return is_basic; +} + +static void destroy_authinfo( struct HttpAuthInfo *authinfo ) +{ + if (!authinfo) return; + + if (SecIsValidHandle(&authinfo->ctx)) + DeleteSecurityContext(&authinfo->ctx); + if (SecIsValidHandle(&authinfo->cred)) + FreeCredentialsHandle(&authinfo->cred); + + HeapFree(GetProcessHeap(), 0, authinfo->auth_data); + HeapFree(GetProcessHeap(), 0, authinfo->scheme); + HeapFree(GetProcessHeap(), 0, authinfo); +} + +static UINT retrieve_cached_basic_authorization(LPWSTR host, LPWSTR realm, LPSTR *auth_data) +{ + authorizationData *ad; + UINT rc = 0; + + TRACE("Looking for authorization for %s:%s\n",debugstr_w(host),debugstr_w(realm)); + + EnterCriticalSection(&authcache_cs); + LIST_FOR_EACH_ENTRY(ad, &basicAuthorizationCache, authorizationData, entry) + { + if (!strcmpiW(host,ad->lpszwHost) && !strcmpW(realm,ad->lpszwRealm)) + { + TRACE("Authorization found in cache\n"); + *auth_data = HeapAlloc(GetProcessHeap(),0,ad->AuthorizationLen); + memcpy(*auth_data,ad->lpszAuthorization,ad->AuthorizationLen); + rc = ad->AuthorizationLen; + break; + } + } + LeaveCriticalSection(&authcache_cs); + return rc; +} + +static void cache_basic_authorization(LPWSTR host, LPWSTR realm, LPSTR auth_data, UINT auth_data_len) +{ + struct list *cursor; + authorizationData* ad = NULL; + + TRACE("caching authorization for %s:%s = %s\n",debugstr_w(host),debugstr_w(realm),debugstr_an(auth_data,auth_data_len)); + + EnterCriticalSection(&authcache_cs); + LIST_FOR_EACH(cursor, &basicAuthorizationCache) + { + authorizationData *check = LIST_ENTRY(cursor,authorizationData,entry); + if (!strcmpiW(host,check->lpszwHost) && !strcmpW(realm,check->lpszwRealm)) + { + ad = check; + break; + } + } + + if (ad) + { + TRACE("Found match in cache, replacing\n"); + HeapFree(GetProcessHeap(),0,ad->lpszAuthorization); + ad->lpszAuthorization = HeapAlloc(GetProcessHeap(),0,auth_data_len); + memcpy(ad->lpszAuthorization, auth_data, auth_data_len); + ad->AuthorizationLen = auth_data_len; + } + else + { + ad = HeapAlloc(GetProcessHeap(),0,sizeof(authorizationData)); + ad->lpszwHost = heap_strdupW(host); + ad->lpszwRealm = heap_strdupW(realm); + ad->lpszAuthorization = HeapAlloc(GetProcessHeap(),0,auth_data_len); + memcpy(ad->lpszAuthorization, auth_data, auth_data_len); + ad->AuthorizationLen = auth_data_len; + list_add_head(&basicAuthorizationCache,&ad->entry); + TRACE("authorization cached\n"); + } + LeaveCriticalSection(&authcache_cs); +} + +static BOOL HTTP_DoAuthorization( http_request_t *lpwhr, LPCWSTR pszAuthValue, struct HttpAuthInfo **ppAuthInfo, - LPWSTR domain_and_username, LPWSTR password ) + LPWSTR domain_and_username, LPWSTR password, + LPWSTR host ) { SECURITY_STATUS sec_status; struct HttpAuthInfo *pAuthInfo = *ppAuthInfo; BOOL first = FALSE; + LPWSTR szRealm = NULL; TRACE("%s\n", debugstr_w(pszAuthValue)); @@ -426,10 +662,10 @@ static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue, pAuthInfo->auth_data_len = 0; pAuthInfo->finished = FALSE; - if (is_basic_auth_value(pszAuthValue)) + if (is_basic_auth_value(pszAuthValue,NULL)) { static const WCHAR szBasic[] = {'B','a','s','i','c',0}; - pAuthInfo->scheme = WININET_strdupW(szBasic); + pAuthInfo->scheme = heap_strdupW(szBasic); if (!pAuthInfo->scheme) { HeapFree(GetProcessHeap(), 0, pAuthInfo); @@ -441,7 +677,7 @@ static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue, PVOID pAuthData; SEC_WINNT_AUTH_IDENTITY_W nt_auth_identity; - pAuthInfo->scheme = WININET_strdupW(pszAuthValue); + pAuthInfo->scheme = heap_strdupW(pszAuthValue); if (!pAuthInfo->scheme) { HeapFree(GetProcessHeap(), 0, pAuthInfo); @@ -513,33 +749,50 @@ static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue, return FALSE; } - if (is_basic_auth_value(pszAuthValue)) + if (is_basic_auth_value(pszAuthValue,&szRealm)) { int userlen; int passlen; - char *auth_data; + char *auth_data = NULL; + UINT auth_data_len = 0; - TRACE("basic authentication\n"); + TRACE("basic authentication realm %s\n",debugstr_w(szRealm)); - /* we don't cache credentials for basic authentication, so we can't - * retrieve them if the application didn't pass us any credentials */ - if (!domain_and_username) return FALSE; + if (!domain_and_username) + { + if (host && szRealm) + auth_data_len = retrieve_cached_basic_authorization(host, szRealm,&auth_data); + if (auth_data_len == 0) + { + HeapFree(GetProcessHeap(),0,szRealm); + return FALSE; + } + } + else + { + userlen = WideCharToMultiByte(CP_UTF8, 0, domain_and_username, lstrlenW(domain_and_username), NULL, 0, NULL, NULL); + passlen = WideCharToMultiByte(CP_UTF8, 0, password, lstrlenW(password), NULL, 0, NULL, NULL); - userlen = WideCharToMultiByte(CP_UTF8, 0, domain_and_username, lstrlenW(domain_and_username), NULL, 0, NULL, NULL); - passlen = WideCharToMultiByte(CP_UTF8, 0, password, lstrlenW(password), NULL, 0, NULL, NULL); + /* length includes a nul terminator, which will be re-used for the ':' */ + auth_data = HeapAlloc(GetProcessHeap(), 0, userlen + 1 + passlen); + if (!auth_data) + { + HeapFree(GetProcessHeap(),0,szRealm); + return FALSE; + } - /* length includes a nul terminator, which will be re-used for the ':' */ - auth_data = HeapAlloc(GetProcessHeap(), 0, userlen + 1 + passlen); - if (!auth_data) - return FALSE; - - WideCharToMultiByte(CP_UTF8, 0, domain_and_username, -1, auth_data, userlen, NULL, NULL); - auth_data[userlen] = ':'; - WideCharToMultiByte(CP_UTF8, 0, password, -1, &auth_data[userlen+1], passlen, NULL, NULL); + WideCharToMultiByte(CP_UTF8, 0, domain_and_username, -1, auth_data, userlen, NULL, NULL); + auth_data[userlen] = ':'; + WideCharToMultiByte(CP_UTF8, 0, password, -1, &auth_data[userlen+1], passlen, NULL, NULL); + auth_data_len = userlen + 1 + passlen; + if (host && szRealm) + cache_basic_authorization(host, szRealm, auth_data, auth_data_len); + } pAuthInfo->auth_data = auth_data; - pAuthInfo->auth_data_len = userlen + 1 + passlen; + pAuthInfo->auth_data_len = auth_data_len; pAuthInfo->finished = TRUE; + HeapFree(GetProcessHeap(),0,szRealm); return TRUE; } @@ -602,8 +855,9 @@ static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue, else { ERR("InitializeSecurityContextW returned error 0x%08x\n", sec_status); - pAuthInfo->finished = TRUE; HeapFree(GetProcessHeap(), 0, out.pvBuffer); + destroy_authinfo(pAuthInfo); + *ppAuthInfo = NULL; return FALSE; } } @@ -614,14 +868,13 @@ static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue, /*********************************************************************** * HTTP_HttpAddRequestHeadersW (internal) */ -static BOOL WINAPI HTTP_HttpAddRequestHeadersW(LPWININETHTTPREQW lpwhr, +static DWORD HTTP_HttpAddRequestHeadersW(http_request_t *lpwhr, LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier) { LPWSTR lpszStart; LPWSTR lpszEnd; LPWSTR buffer; - BOOL bSuccess = FALSE; - DWORD len; + DWORD len, res = ERROR_HTTP_INVALID_HEADER; TRACE("copying header: %s\n", debugstr_wn(lpszHeader, dwHeaderLength)); @@ -642,7 +895,7 @@ static BOOL WINAPI HTTP_HttpAddRequestHeadersW(LPWININETHTTPREQW lpwhr, while (*lpszEnd != '\0') { - if (*lpszEnd == '\r' && *(lpszEnd + 1) == '\n') + if (*lpszEnd == '\r' || *lpszEnd == '\n') break; lpszEnd++; } @@ -650,28 +903,35 @@ static BOOL WINAPI HTTP_HttpAddRequestHeadersW(LPWININETHTTPREQW lpwhr, if (*lpszStart == '\0') break; - if (*lpszEnd == '\r') + if (*lpszEnd == '\r' || *lpszEnd == '\n') { *lpszEnd = '\0'; - lpszEnd += 2; /* Jump over \r\n */ + lpszEnd++; /* Jump over newline */ } TRACE("interpreting header %s\n", debugstr_w(lpszStart)); + if (*lpszStart == '\0') + { + /* Skip 0-length headers */ + lpszStart = lpszEnd; + res = ERROR_SUCCESS; + continue; + } pFieldAndValue = HTTP_InterpretHttpHeader(lpszStart); if (pFieldAndValue) { - bSuccess = HTTP_VerifyValidHeader(lpwhr, pFieldAndValue[0]); - if (bSuccess) - bSuccess = HTTP_ProcessHeader(lpwhr, pFieldAndValue[0], + res = HTTP_VerifyValidHeader(lpwhr, pFieldAndValue[0]); + if (res == ERROR_SUCCESS) + res = HTTP_ProcessHeader(lpwhr, pFieldAndValue[0], pFieldAndValue[1], dwModifier | HTTP_ADDHDR_FLAG_REQ); HTTP_FreeTokens(pFieldAndValue); } lpszStart = lpszEnd; - } while (bSuccess); + } while (res == ERROR_SUCCESS); HeapFree(GetProcessHeap(), 0, buffer); - return bSuccess; + return res; } /*********************************************************************** @@ -693,26 +953,23 @@ static BOOL WINAPI HTTP_HttpAddRequestHeadersW(LPWININETHTTPREQW lpwhr, BOOL WINAPI HttpAddRequestHeadersW(HINTERNET hHttpRequest, LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier) { - BOOL bSuccess = FALSE; - LPWININETHTTPREQW lpwhr; + http_request_t *lpwhr; + DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; TRACE("%p, %s, %i, %i\n", hHttpRequest, debugstr_wn(lpszHeader, dwHeaderLength), dwHeaderLength, dwModifier); if (!lpszHeader) return TRUE; - lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest ); - if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) - { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - goto lend; - } - bSuccess = HTTP_HttpAddRequestHeadersW( lpwhr, lpszHeader, dwHeaderLength, dwModifier ); -lend: + lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest ); + if (lpwhr && lpwhr->hdr.htype == WH_HHTTPREQ) + res = HTTP_HttpAddRequestHeadersW( lpwhr, lpszHeader, dwHeaderLength, dwModifier ); if( lpwhr ) WININET_Release( &lpwhr->hdr ); - return bSuccess; + if(res != ERROR_SUCCESS) + SetLastError(res); + return res == ERROR_SUCCESS; } /*********************************************************************** @@ -747,208 +1004,6 @@ BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest, return r; } -/*********************************************************************** - * HttpEndRequestA (WININET.@) - * - * Ends an HTTP request that was started by HttpSendRequestEx - * - * RETURNS - * TRUE if successful - * FALSE on failure - * - */ -BOOL WINAPI HttpEndRequestA(HINTERNET hRequest, - LPINTERNET_BUFFERSA lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext) -{ - LPINTERNET_BUFFERSA ptr; - LPINTERNET_BUFFERSW lpBuffersOutW,ptrW; - BOOL rc = FALSE; - - TRACE("(%p, %p, %08x, %08lx): stub\n", hRequest, lpBuffersOut, dwFlags, - dwContext); - - ptr = lpBuffersOut; - if (ptr) - lpBuffersOutW = (LPINTERNET_BUFFERSW)HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, sizeof(INTERNET_BUFFERSW)); - else - lpBuffersOutW = NULL; - - ptrW = lpBuffersOutW; - while (ptr) - { - if (ptr->lpvBuffer && ptr->dwBufferLength) - ptrW->lpvBuffer = HeapAlloc(GetProcessHeap(),0,ptr->dwBufferLength); - ptrW->dwBufferLength = ptr->dwBufferLength; - ptrW->dwBufferTotal= ptr->dwBufferTotal; - - if (ptr->Next) - ptrW->Next = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, - sizeof(INTERNET_BUFFERSW)); - - ptr = ptr->Next; - ptrW = ptrW->Next; - } - - rc = HttpEndRequestW(hRequest, lpBuffersOutW, dwFlags, dwContext); - - if (lpBuffersOutW) - { - ptrW = lpBuffersOutW; - while (ptrW) - { - LPINTERNET_BUFFERSW ptrW2; - - FIXME("Do we need to translate info out of these buffer?\n"); - - HeapFree(GetProcessHeap(),0,ptrW->lpvBuffer); - ptrW2 = ptrW->Next; - HeapFree(GetProcessHeap(),0,ptrW); - ptrW = ptrW2; - } - } - - return rc; -} - -/*********************************************************************** - * HttpEndRequestW (WININET.@) - * - * Ends an HTTP request that was started by HttpSendRequestEx - * - * RETURNS - * TRUE if successful - * FALSE on failure - * - */ -BOOL WINAPI HttpEndRequestW(HINTERNET hRequest, - LPINTERNET_BUFFERSW lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext) -{ - BOOL rc = FALSE; - LPWININETHTTPREQW lpwhr; - INT responseLen; - DWORD dwBufferSize; - - TRACE("-->\n"); - lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest ); - - if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) - { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - if (lpwhr) - WININET_Release( &lpwhr->hdr ); - return FALSE; - } - - lpwhr->hdr.dwFlags |= dwFlags; - lpwhr->hdr.dwContext = dwContext; - - /* We appear to do nothing with lpBuffersOut.. is that correct? */ - - SendAsyncCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, - INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); - - responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE); - if (responseLen) - rc = TRUE; - - SendAsyncCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, - INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, sizeof(DWORD)); - - /* process cookies here. Is this right? */ - HTTP_ProcessCookies(lpwhr); - - dwBufferSize = sizeof(lpwhr->dwContentLength); - if (!HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH, - &lpwhr->dwContentLength,&dwBufferSize,NULL)) - lpwhr->dwContentLength = -1; - - if (lpwhr->dwContentLength == 0) - HTTP_FinishedReading(lpwhr); - - if(!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT)) - { - DWORD dwCode,dwCodeLength=sizeof(DWORD); - if(HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,&dwCode,&dwCodeLength,NULL) && - (dwCode==302 || dwCode==301)) - { - WCHAR szNewLocation[INTERNET_MAX_URL_LENGTH]; - dwBufferSize=sizeof(szNewLocation); - if(HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,NULL)) - { - /* redirects are always GETs */ - HeapFree(GetProcessHeap(),0,lpwhr->lpszVerb); - lpwhr->lpszVerb = WININET_strdupW(szGET); - HTTP_DrainContent(lpwhr); - INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, - INTERNET_STATUS_REDIRECT, szNewLocation, - dwBufferSize); - rc = HTTP_HandleRedirect(lpwhr, szNewLocation); - if (rc) - rc = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, TRUE); - } - } - } - - WININET_Release( &lpwhr->hdr ); - TRACE("%i <--\n",rc); - return rc; -} - -/*********************************************************************** - * HttpOpenRequestW (WININET.@) - * - * Open a HTTP request handle - * - * RETURNS - * HINTERNET a HTTP request handle on success - * NULL on failure - * - */ -HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession, - LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion, - LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes, - DWORD dwFlags, DWORD_PTR dwContext) -{ - LPWININETHTTPSESSIONW lpwhs; - HINTERNET handle = NULL; - - TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession, - debugstr_w(lpszVerb), debugstr_w(lpszObjectName), - debugstr_w(lpszVersion), debugstr_w(lpszReferrer), lpszAcceptTypes, - dwFlags, dwContext); - if(lpszAcceptTypes!=NULL) - { - int i; - for(i=0;lpszAcceptTypes[i]!=NULL;i++) - TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes[i])); - } - - lpwhs = (LPWININETHTTPSESSIONW) WININET_GetObject( hHttpSession ); - if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION) - { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - goto lend; - } - - /* - * My tests seem to show that the windows version does not - * become asynchronous until after this point. And anyhow - * if this call was asynchronous then how would you get the - * necessary HINTERNET pointer returned by this function. - * - */ - handle = HTTP_HttpOpenRequestW(lpwhs, lpszVerb, lpszObjectName, - lpszVersion, lpszReferrer, lpszAcceptTypes, - dwFlags, dwContext); -lend: - if( lpwhs ) - WININET_Release( &lpwhs->hdr ); - TRACE("returning %p\n", handle); - return handle; -} - - /*********************************************************************** * HttpOpenRequestA (WININET.@) * @@ -966,7 +1021,7 @@ HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession, { LPWSTR szVerb = NULL, szObjectName = NULL; LPWSTR szVersion = NULL, szReferrer = NULL, *szAcceptTypes = NULL; - INT len, acceptTypesCount; + INT acceptTypesCount; HINTERNET rc = FALSE; LPCSTR *types; @@ -977,38 +1032,30 @@ HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession, if (lpszVerb) { - len = MultiByteToWideChar(CP_ACP, 0, lpszVerb, -1, NULL, 0 ); - szVerb = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR) ); + szVerb = heap_strdupAtoW(lpszVerb); if ( !szVerb ) goto end; - MultiByteToWideChar(CP_ACP, 0, lpszVerb, -1, szVerb, len); } if (lpszObjectName) { - len = MultiByteToWideChar(CP_ACP, 0, lpszObjectName, -1, NULL, 0 ); - szObjectName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR) ); + szObjectName = heap_strdupAtoW(lpszObjectName); if ( !szObjectName ) goto end; - MultiByteToWideChar(CP_ACP, 0, lpszObjectName, -1, szObjectName, len ); } if (lpszVersion) { - len = MultiByteToWideChar(CP_ACP, 0, lpszVersion, -1, NULL, 0 ); - szVersion = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + szVersion = heap_strdupAtoW(lpszVersion); if ( !szVersion ) goto end; - MultiByteToWideChar(CP_ACP, 0, lpszVersion, -1, szVersion, len ); } if (lpszReferrer) { - len = MultiByteToWideChar(CP_ACP, 0, lpszReferrer, -1, NULL, 0 ); - szReferrer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + szReferrer = heap_strdupAtoW(lpszReferrer); if ( !szReferrer ) goto end; - MultiByteToWideChar(CP_ACP, 0, lpszReferrer, -1, szReferrer, len ); } if (lpszAcceptTypes) @@ -1017,12 +1064,20 @@ HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession, types = lpszAcceptTypes; while (*types) { - /* find out how many there are */ - if (((ULONG_PTR)*types >> 16) && **types) + __TRY { - TRACE("accept type: %s\n", debugstr_a(*types)); - acceptTypesCount++; + /* find out how many there are */ + if (*types && **types) + { + TRACE("accept type: %s\n", debugstr_a(*types)); + acceptTypesCount++; + } } + __EXCEPT_PAGE_FAULT + { + WARN("invalid accept type pointer\n"); + } + __ENDTRY; types++; } szAcceptTypes = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *) * (acceptTypesCount+1)); @@ -1032,20 +1087,20 @@ HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession, types = lpszAcceptTypes; while (*types) { - if (((ULONG_PTR)*types >> 16) && **types) + __TRY { - len = MultiByteToWideChar(CP_ACP, 0, *types, -1, NULL, 0 ); - szAcceptTypes[acceptTypesCount] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); - if (!szAcceptTypes[acceptTypesCount]) goto end; - - MultiByteToWideChar(CP_ACP, 0, *types, -1, szAcceptTypes[acceptTypesCount], len); - acceptTypesCount++; + if (*types && **types) + szAcceptTypes[acceptTypesCount++] = heap_strdupAtoW(*types); } + __EXCEPT_PAGE_FAULT + { + /* ignore invalid pointer */ + } + __ENDTRY; types++; } szAcceptTypes[acceptTypesCount] = NULL; } - else szAcceptTypes = 0; rc = HttpOpenRequestW(hHttpSession, szVerb, szObjectName, szVersion, szReferrer, @@ -1207,7 +1262,7 @@ static UINT HTTP_DecodeBase64( LPCWSTR base64, LPSTR bin ) * * Insert or delete the authorization field in the request header. */ -static BOOL HTTP_InsertAuthorization( LPWININETHTTPREQW lpwhr, struct HttpAuthInfo *pAuthInfo, LPCWSTR header ) +static BOOL HTTP_InsertAuthorization( http_request_t *lpwhr, struct HttpAuthInfo *pAuthInfo, LPCWSTR header ) { if (pAuthInfo) { @@ -1250,13 +1305,13 @@ static BOOL HTTP_InsertAuthorization( LPWININETHTTPREQW lpwhr, struct HttpAuthIn return TRUE; } -static WCHAR *HTTP_BuildProxyRequestUrl(WININETHTTPREQW *req) +static WCHAR *HTTP_BuildProxyRequestUrl(http_request_t *req) { WCHAR new_location[INTERNET_MAX_URL_LENGTH], *url; DWORD size; size = sizeof(new_location); - if (HTTP_HttpQueryInfoW(req, HTTP_QUERY_LOCATION, new_location, &size, NULL)) + if (HTTP_HttpQueryInfoW(req, HTTP_QUERY_LOCATION, new_location, &size, NULL) == ERROR_SUCCESS) { if (!(url = HeapAlloc( GetProcessHeap(), 0, size + sizeof(WCHAR) ))) return NULL; strcpyW( url, new_location ); @@ -1266,7 +1321,7 @@ static WCHAR *HTTP_BuildProxyRequestUrl(WININETHTTPREQW *req) static const WCHAR slash[] = { '/',0 }; static const WCHAR format[] = { 'h','t','t','p',':','/','/','%','s',':','%','d',0 }; static const WCHAR formatSSL[] = { 'h','t','t','p','s',':','/','/','%','s',':','%','d',0 }; - WININETHTTPSESSIONW *session = req->lpHttpSession; + http_session_t *session = req->lpHttpSession; size = 16; /* "https://" + sizeof(port#) + ":/\0" */ size += strlenW( session->lpszHostName ) + strlenW( req->lpszPath ); @@ -1287,8 +1342,7 @@ static WCHAR *HTTP_BuildProxyRequestUrl(WININETHTTPREQW *req) /*********************************************************************** * HTTP_DealWithProxy */ -static BOOL HTTP_DealWithProxy( LPWININETAPPINFOW hIC, - LPWININETHTTPSESSIONW lpwhs, LPWININETHTTPREQW lpwhr) +static BOOL HTTP_DealWithProxy(appinfo_t *hIC, http_session_t *lpwhs, http_request_t *lpwhr) { WCHAR buf[MAXHOSTNAME]; WCHAR proxy[MAXHOSTNAME + 15]; /* 15 == "http://" + sizeof(port#) + ":/\0" */ @@ -1319,38 +1373,52 @@ static BOOL HTTP_DealWithProxy( LPWININETAPPINFOW hIC, UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT; HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName); - lpwhs->lpszServerName = WININET_strdupW(UrlComponents.lpszHostName); + lpwhs->lpszServerName = heap_strdupW(UrlComponents.lpszHostName); lpwhs->nServerPort = UrlComponents.nPort; TRACE("proxy server=%s port=%d\n", debugstr_w(lpwhs->lpszServerName), lpwhs->nServerPort); return TRUE; } -static BOOL HTTP_ResolveName(LPWININETHTTPREQW lpwhr) +#ifndef INET6_ADDRSTRLEN +#define INET6_ADDRSTRLEN 46 +#endif + +static DWORD HTTP_ResolveName(http_request_t *lpwhr) { - char szaddr[32]; - LPWININETHTTPSESSIONW lpwhs = lpwhr->lpHttpSession; + char szaddr[INET6_ADDRSTRLEN]; + http_session_t *lpwhs = lpwhr->lpHttpSession; + const void *addr; INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_RESOLVING_NAME, lpwhs->lpszServerName, - strlenW(lpwhs->lpszServerName)+1); + (strlenW(lpwhs->lpszServerName)+1) * sizeof(WCHAR)); + lpwhs->sa_len = sizeof(lpwhs->socketAddress); if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort, - &lpwhs->socketAddress)) - { - INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED); - return FALSE; - } + (struct sockaddr *)&lpwhs->socketAddress, &lpwhs->sa_len)) + return ERROR_INTERNET_NAME_NOT_RESOLVED; - inet_ntop(lpwhs->socketAddress.sin_family, &lpwhs->socketAddress.sin_addr, - szaddr, sizeof(szaddr)); + switch (lpwhs->socketAddress.ss_family) + { + case AF_INET: + addr = &((struct sockaddr_in *)&lpwhs->socketAddress)->sin_addr; + break; + case AF_INET6: + addr = &((struct sockaddr_in6 *)&lpwhs->socketAddress)->sin6_addr; + break; + default: + WARN("unsupported family %d\n", lpwhs->socketAddress.ss_family); + return ERROR_INTERNET_NAME_NOT_RESOLVED; + } + inet_ntop(lpwhs->socketAddress.ss_family, addr, szaddr, sizeof(szaddr)); INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_NAME_RESOLVED, szaddr, strlen(szaddr)+1); TRACE("resolved %s to %s\n", debugstr_w(lpwhs->lpszServerName), szaddr); - return TRUE; + return ERROR_SUCCESS; } @@ -1360,9 +1428,9 @@ static BOOL HTTP_ResolveName(LPWININETHTTPREQW lpwhr) * Deallocate request handle * */ -static void HTTPREQ_Destroy(WININETHANDLEHEADER *hdr) +static void HTTPREQ_Destroy(object_header_t *hdr) { - LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) hdr; + http_request_t *lpwhr = (http_request_t*) hdr; DWORD i; TRACE("\n"); @@ -1370,13 +1438,14 @@ static void HTTPREQ_Destroy(WININETHANDLEHEADER *hdr) if(lpwhr->hCacheFile) CloseHandle(lpwhr->hCacheFile); - if(lpwhr->lpszCacheFile) { - DeleteFileW(lpwhr->lpszCacheFile); /* FIXME */ - HeapFree(GetProcessHeap(), 0, lpwhr->lpszCacheFile); - } + HeapFree(GetProcessHeap(), 0, lpwhr->lpszCacheFile); + DeleteCriticalSection( &lpwhr->read_section ); WININET_Release(&lpwhr->lpHttpSession->hdr); + destroy_authinfo(lpwhr->pAuthInfo); + destroy_authinfo(lpwhr->pProxyAuthInfo); + HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath); HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb); HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders); @@ -1389,44 +1458,27 @@ static void HTTPREQ_Destroy(WININETHANDLEHEADER *hdr) HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszValue); } +#ifdef HAVE_ZLIB + if(lpwhr->gzip_stream) { + if(!lpwhr->gzip_stream->end_of_data) + inflateEnd(&lpwhr->gzip_stream->zstream); + HeapFree(GetProcessHeap(), 0, lpwhr->gzip_stream); + } +#endif + HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders); HeapFree(GetProcessHeap(), 0, lpwhr); } -static void HTTPREQ_CloseConnection(WININETHANDLEHEADER *hdr) +static void HTTPREQ_CloseConnection(object_header_t *hdr) { - LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) hdr; + http_request_t *lpwhr = (http_request_t*) hdr; TRACE("%p\n",lpwhr); if (!NETCON_connected(&lpwhr->netConnection)) return; - if (lpwhr->pAuthInfo) - { - if (SecIsValidHandle(&lpwhr->pAuthInfo->ctx)) - DeleteSecurityContext(&lpwhr->pAuthInfo->ctx); - if (SecIsValidHandle(&lpwhr->pAuthInfo->cred)) - FreeCredentialsHandle(&lpwhr->pAuthInfo->cred); - - HeapFree(GetProcessHeap(), 0, lpwhr->pAuthInfo->auth_data); - HeapFree(GetProcessHeap(), 0, lpwhr->pAuthInfo->scheme); - HeapFree(GetProcessHeap(), 0, lpwhr->pAuthInfo); - lpwhr->pAuthInfo = NULL; - } - if (lpwhr->pProxyAuthInfo) - { - if (SecIsValidHandle(&lpwhr->pProxyAuthInfo->ctx)) - DeleteSecurityContext(&lpwhr->pProxyAuthInfo->ctx); - if (SecIsValidHandle(&lpwhr->pProxyAuthInfo->cred)) - FreeCredentialsHandle(&lpwhr->pProxyAuthInfo->cred); - - HeapFree(GetProcessHeap(), 0, lpwhr->pProxyAuthInfo->auth_data); - HeapFree(GetProcessHeap(), 0, lpwhr->pProxyAuthInfo->scheme); - HeapFree(GetProcessHeap(), 0, lpwhr->pProxyAuthInfo); - lpwhr->pProxyAuthInfo = NULL; - } - INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_CLOSING_CONNECTION, 0, 0); @@ -1436,11 +1488,95 @@ static void HTTPREQ_CloseConnection(WININETHANDLEHEADER *hdr) INTERNET_STATUS_CONNECTION_CLOSED, 0, 0); } -static DWORD HTTPREQ_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) +static BOOL HTTP_GetRequestURL(http_request_t *req, LPWSTR buf) { - WININETHTTPREQW *req = (WININETHTTPREQW*)hdr; + LPHTTPHEADERW host_header; + + static const WCHAR formatW[] = {'h','t','t','p',':','/','/','%','s','%','s',0}; + + host_header = HTTP_GetHeader(req, hostW); + if(!host_header) + return FALSE; + + sprintfW(buf, formatW, host_header->lpszValue, req->lpszPath); /* FIXME */ + return TRUE; +} + +static BOOL HTTP_KeepAlive(http_request_t *lpwhr) +{ + WCHAR szVersion[10]; + WCHAR szConnectionResponse[20]; + DWORD dwBufferSize = sizeof(szVersion); + BOOL keepalive = FALSE; + + /* as per RFC 2068, S8.1.2.1, if the client is HTTP/1.1 then assume that + * the connection is keep-alive by default */ + if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_VERSION, szVersion, &dwBufferSize, NULL) == ERROR_SUCCESS + && !strcmpiW(szVersion, g_szHttp1_1)) + { + keepalive = TRUE; + } + + dwBufferSize = sizeof(szConnectionResponse); + if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_PROXY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) == ERROR_SUCCESS + || HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) == ERROR_SUCCESS) + { + keepalive = !strcmpiW(szConnectionResponse, szKeepAlive); + } + + return keepalive; +} + +static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) +{ + http_request_t *req = (http_request_t*)hdr; switch(option) { + case INTERNET_OPTION_DIAGNOSTIC_SOCKET_INFO: + { + http_session_t *lpwhs = req->lpHttpSession; + INTERNET_DIAGNOSTIC_SOCKET_INFO *info = buffer; + + FIXME("INTERNET_DIAGNOSTIC_SOCKET_INFO stub\n"); + + if (*size < sizeof(INTERNET_DIAGNOSTIC_SOCKET_INFO)) + return ERROR_INSUFFICIENT_BUFFER; + *size = sizeof(INTERNET_DIAGNOSTIC_SOCKET_INFO); + /* FIXME: can't get a SOCKET from our connection since we don't use + * winsock + */ + info->Socket = 0; + /* FIXME: get source port from req->netConnection */ + info->SourcePort = 0; + info->DestPort = lpwhs->nHostPort; + info->Flags = 0; + if (HTTP_KeepAlive(req)) + info->Flags |= IDSI_FLAG_KEEP_ALIVE; + if (lpwhs->lpAppInfo->lpszProxy && lpwhs->lpAppInfo->lpszProxy[0] != 0) + info->Flags |= IDSI_FLAG_PROXY; + if (req->netConnection.useSSL) + info->Flags |= IDSI_FLAG_SECURE; + + return ERROR_SUCCESS; + } + + case INTERNET_OPTION_SECURITY_FLAGS: + { + http_session_t *lpwhs; + lpwhs = req->lpHttpSession; + + if (*size < sizeof(ULONG)) + return ERROR_INSUFFICIENT_BUFFER; + + *size = sizeof(DWORD); + if (lpwhs->hdr.dwFlags & INTERNET_FLAG_SECURE) + *(DWORD*)buffer = SECURITY_FLAG_SECURE; + else + *(DWORD*)buffer = 0; + FIXME("Semi-STUB INTERNET_OPTION_SECURITY_FLAGS: %x\n",*(DWORD*)buffer); + return ERROR_SUCCESS; + } + case INTERNET_OPTION_HANDLE_TYPE: TRACE("INTERNET_OPTION_HANDLE_TYPE\n"); @@ -1458,7 +1594,6 @@ static DWORD HTTPREQ_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b WCHAR *pch; static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0}; - static const WCHAR hostW[] = {'H','o','s','t',0}; TRACE("INTERNET_OPTION_URL\n"); @@ -1489,6 +1624,41 @@ static DWORD HTTPREQ_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b } } + case INTERNET_OPTION_CACHE_TIMESTAMPS: { + INTERNET_CACHE_ENTRY_INFOW *info; + INTERNET_CACHE_TIMESTAMPS *ts = buffer; + WCHAR url[INTERNET_MAX_URL_LENGTH]; + DWORD nbytes, error; + BOOL ret; + + TRACE("INTERNET_OPTION_CACHE_TIMESTAMPS\n"); + + if (*size < sizeof(*ts)) + { + *size = sizeof(*ts); + return ERROR_INSUFFICIENT_BUFFER; + } + nbytes = 0; + HTTP_GetRequestURL(req, url); + ret = GetUrlCacheEntryInfoW(url, NULL, &nbytes); + error = GetLastError(); + if (!ret && error == ERROR_INSUFFICIENT_BUFFER) + { + if (!(info = HeapAlloc(GetProcessHeap(), 0, nbytes))) + return ERROR_OUTOFMEMORY; + + GetUrlCacheEntryInfoW(url, info, &nbytes); + + ts->ftExpires = info->ExpireTime; + ts->ftLastModified = info->LastModifiedTime; + + HeapFree(GetProcessHeap(), 0, info); + *size = sizeof(*ts); + return ERROR_SUCCESS; + } + return error; + } + case INTERNET_OPTION_DATAFILE_NAME: { DWORD req_size; @@ -1584,9 +1754,9 @@ static DWORD HTTPREQ_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b return INET_QueryOption(option, buffer, size, unicode); } -static DWORD HTTPREQ_SetOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD size) +static DWORD HTTPREQ_SetOption(object_header_t *hdr, DWORD option, void *buffer, DWORD size) { - WININETHTTPREQW *req = (WININETHTTPREQW*)hdr; + http_request_t *req = (http_request_t*)hdr; switch(option) { case INTERNET_OPTION_SEND_TIMEOUT: @@ -1598,30 +1768,340 @@ static DWORD HTTPREQ_SetOption(WININETHANDLEHEADER *hdr, DWORD option, void *buf return NETCON_set_timeout(&req->netConnection, option == INTERNET_OPTION_SEND_TIMEOUT, *(DWORD*)buffer); + + case INTERNET_OPTION_USERNAME: + HeapFree(GetProcessHeap(), 0, req->lpHttpSession->lpszUserName); + if (!(req->lpHttpSession->lpszUserName = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; + return ERROR_SUCCESS; + + case INTERNET_OPTION_PASSWORD: + HeapFree(GetProcessHeap(), 0, req->lpHttpSession->lpszPassword); + if (!(req->lpHttpSession->lpszPassword = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; + return ERROR_SUCCESS; + case INTERNET_OPTION_HTTP_DECODING: + if(size != sizeof(BOOL)) + return ERROR_INVALID_PARAMETER; + req->decoding = *(BOOL*)buffer; + return ERROR_SUCCESS; } return ERROR_INTERNET_INVALID_OPTION; } -static DWORD HTTP_Read(WININETHTTPREQW *req, void *buffer, DWORD size, DWORD *read, BOOL sync) +/* read some more data into the read buffer (the read section must be held) */ +static DWORD read_more_data( http_request_t *req, int maxlen ) { - int bytes_read; + DWORD res; + int len; - if(!NETCON_recv(&req->netConnection, buffer, min(size, req->dwContentLength - req->dwContentRead), - sync ? MSG_WAITALL : 0, &bytes_read)) { - if(req->dwContentLength != -1 && req->dwContentRead != req->dwContentLength) - ERR("not all data received %d/%d\n", req->dwContentRead, req->dwContentLength); - - /* always return success, even if the network layer returns an error */ - *read = 0; - HTTP_FinishedReading(req); - return ERROR_SUCCESS; + if (req->read_pos) + { + /* move existing data to the start of the buffer */ + if(req->read_size) + memmove( req->read_buf, req->read_buf + req->read_pos, req->read_size ); + req->read_pos = 0; } - req->dwContentRead += bytes_read; + if (maxlen == -1) maxlen = sizeof(req->read_buf); + + res = NETCON_recv( &req->netConnection, req->read_buf + req->read_size, + maxlen - req->read_size, 0, &len ); + if(res == ERROR_SUCCESS) + req->read_size += len; + + return res; +} + +/* remove some amount of data from the read buffer (the read section must be held) */ +static void remove_data( http_request_t *req, int count ) +{ + if (!(req->read_size -= count)) req->read_pos = 0; + else req->read_pos += count; +} + +static BOOL read_line( http_request_t *req, LPSTR buffer, DWORD *len ) +{ + int count, bytes_read, pos = 0; + DWORD res; + + EnterCriticalSection( &req->read_section ); + for (;;) + { + BYTE *eol = memchr( req->read_buf + req->read_pos, '\n', req->read_size ); + + if (eol) + { + count = eol - (req->read_buf + req->read_pos); + bytes_read = count + 1; + } + else count = bytes_read = req->read_size; + + count = min( count, *len - pos ); + memcpy( buffer + pos, req->read_buf + req->read_pos, count ); + pos += count; + remove_data( req, bytes_read ); + if (eol) break; + + if ((res = read_more_data( req, -1 )) != ERROR_SUCCESS || !req->read_size) + { + *len = 0; + TRACE( "returning empty string\n" ); + LeaveCriticalSection( &req->read_section ); + INTERNET_SetLastError(res); + return FALSE; + } + } + LeaveCriticalSection( &req->read_section ); + + if (pos < *len) + { + if (pos && buffer[pos - 1] == '\r') pos--; + *len = pos + 1; + } + buffer[*len - 1] = 0; + TRACE( "returning %s\n", debugstr_a(buffer)); + return TRUE; +} + +/* discard data contents until we reach end of line (the read section must be held) */ +static DWORD discard_eol( http_request_t *req ) +{ + DWORD res; + + do + { + BYTE *eol = memchr( req->read_buf + req->read_pos, '\n', req->read_size ); + if (eol) + { + remove_data( req, (eol + 1) - (req->read_buf + req->read_pos) ); + break; + } + req->read_pos = req->read_size = 0; /* discard everything */ + if ((res = read_more_data( req, -1 )) != ERROR_SUCCESS) return res; + } while (req->read_size); + return ERROR_SUCCESS; +} + +/* read the size of the next chunk (the read section must be held) */ +static DWORD start_next_chunk( http_request_t *req ) +{ + DWORD chunk_size = 0, res; + + if (!req->dwContentLength) return ERROR_SUCCESS; + if (req->dwContentLength == req->dwContentRead) + { + /* read terminator for the previous chunk */ + if ((res = discard_eol( req )) != ERROR_SUCCESS) return res; + req->dwContentLength = ~0u; + req->dwContentRead = 0; + } + for (;;) + { + while (req->read_size) + { + char ch = req->read_buf[req->read_pos]; + if (ch >= '0' && ch <= '9') chunk_size = chunk_size * 16 + ch - '0'; + else if (ch >= 'a' && ch <= 'f') chunk_size = chunk_size * 16 + ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'F') chunk_size = chunk_size * 16 + ch - 'A' + 10; + else if (ch == ';' || ch == '\r' || ch == '\n') + { + TRACE( "reading %u byte chunk\n", chunk_size ); + req->dwContentLength = chunk_size; + req->dwContentRead = 0; + return discard_eol( req ); + } + remove_data( req, 1 ); + } + if ((res = read_more_data( req, -1 )) != ERROR_SUCCESS) return res; + if (!req->read_size) + { + req->dwContentLength = req->dwContentRead = 0; + return ERROR_SUCCESS; + } + } +} + +/* check if we have reached the end of the data to read (the read section must be held) */ +static BOOL end_of_read_data( http_request_t *req ) +{ + if (req->gzip_stream) return req->gzip_stream->end_of_data && !req->gzip_stream->buf_size; + if (req->read_chunked) return (req->dwContentLength == 0); + if (req->dwContentLength == ~0u) return FALSE; + return (req->dwContentLength == req->dwContentRead); +} + +/* fetch some more data into the read buffer (the read section must be held) */ +static DWORD refill_buffer( http_request_t *req ) +{ + int len = sizeof(req->read_buf); + DWORD res; + + if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead)) + { + if ((res = start_next_chunk( req )) != ERROR_SUCCESS) return res; + } + + if (req->dwContentLength != ~0u) len = min( len, req->dwContentLength - req->dwContentRead ); + if (len <= req->read_size) return ERROR_SUCCESS; + + if ((res = read_more_data( req, len )) != ERROR_SUCCESS) return res; + if (!req->read_size) req->dwContentLength = req->dwContentRead = 0; + return ERROR_SUCCESS; +} + +static DWORD read_gzip_data(http_request_t *req, BYTE *buf, int size, BOOL sync, int *read_ret) +{ + DWORD ret = ERROR_SUCCESS; + int read = 0; + +#ifdef HAVE_ZLIB + z_stream *zstream = &req->gzip_stream->zstream; + DWORD buf_avail; + int zres; + + while(read < size && !req->gzip_stream->end_of_data) { + if(!req->read_size) { + if(!sync || refill_buffer(req) != ERROR_SUCCESS) + break; + } + + buf_avail = req->dwContentLength == ~0 ? req->read_size : min(req->read_size, req->dwContentLength-req->dwContentRead); + + zstream->next_in = req->read_buf+req->read_pos; + zstream->avail_in = buf_avail; + zstream->next_out = buf+read; + zstream->avail_out = size-read; + zres = inflate(zstream, Z_FULL_FLUSH); + read = size - zstream->avail_out; + req->dwContentRead += buf_avail-zstream->avail_in; + remove_data(req, buf_avail-zstream->avail_in); + if(zres == Z_STREAM_END) { + TRACE("end of data\n"); + req->gzip_stream->end_of_data = TRUE; + inflateEnd(&req->gzip_stream->zstream); + }else if(zres != Z_OK) { + WARN("inflate failed %d\n", zres); + if(!read) + ret = ERROR_INTERNET_DECODING_FAILED; + break; + } + } +#endif + + *read_ret = read; + return ret; +} + +static void refill_gzip_buffer(http_request_t *req) +{ + DWORD res; + int len; + + if(!req->gzip_stream || !req->read_size || req->gzip_stream->buf_size == sizeof(req->gzip_stream->buf)) + return; + + if(req->gzip_stream->buf_pos) { + if(req->gzip_stream->buf_size) + memmove(req->gzip_stream->buf, req->gzip_stream->buf + req->gzip_stream->buf_pos, req->gzip_stream->buf_size); + req->gzip_stream->buf_pos = 0; + } + + res = read_gzip_data(req, req->gzip_stream->buf + req->gzip_stream->buf_size, + sizeof(req->gzip_stream->buf) - req->gzip_stream->buf_size, FALSE, &len); + if(res == ERROR_SUCCESS) + req->gzip_stream->buf_size += len; +} + +/* return the size of data available to be read immediately (the read section must be held) */ +static DWORD get_avail_data( http_request_t *req ) +{ + if (req->gzip_stream) { + refill_gzip_buffer(req); + return req->gzip_stream->buf_size; + } + if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead)) + return 0; + return min( req->read_size, req->dwContentLength - req->dwContentRead ); +} + +static void HTTP_ReceiveRequestData(http_request_t *req, BOOL first_notif) +{ + INTERNET_ASYNC_RESULT iar; + DWORD res; + + TRACE("%p\n", req); + + EnterCriticalSection( &req->read_section ); + if ((res = refill_buffer( req )) == ERROR_SUCCESS) { + iar.dwResult = (DWORD_PTR)req->hdr.hInternet; + iar.dwError = first_notif ? 0 : get_avail_data(req); + }else { + iar.dwResult = 0; + iar.dwError = res; + } + LeaveCriticalSection( &req->read_section ); + + INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar, + sizeof(INTERNET_ASYNC_RESULT)); +} + +/* read data from the http connection (the read section must be held) */ +static DWORD HTTPREQ_Read(http_request_t *req, void *buffer, DWORD size, DWORD *read, BOOL sync) +{ + BOOL finished_reading = FALSE; + int len, bytes_read = 0; + DWORD ret = ERROR_SUCCESS; + + EnterCriticalSection( &req->read_section ); + + if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead)) + { + if (start_next_chunk( req ) != ERROR_SUCCESS) goto done; + } + + if(req->gzip_stream) { + if(req->gzip_stream->buf_size) { + bytes_read = min(req->gzip_stream->buf_size, size); + memcpy(buffer, req->gzip_stream->buf + req->gzip_stream->buf_pos, bytes_read); + req->gzip_stream->buf_pos += bytes_read; + req->gzip_stream->buf_size -= bytes_read; + }else if(!req->read_size && !req->gzip_stream->end_of_data) { + refill_buffer(req); + } + + if(size > bytes_read) { + ret = read_gzip_data(req, (BYTE*)buffer+bytes_read, size-bytes_read, sync, &len); + if(ret == ERROR_SUCCESS) + bytes_read += len; + } + + finished_reading = req->gzip_stream->end_of_data && !req->gzip_stream->buf_size; + }else { + if (req->dwContentLength != ~0u) size = min( size, req->dwContentLength - req->dwContentRead ); + + if (req->read_size) { + bytes_read = min( req->read_size, size ); + memcpy( buffer, req->read_buf + req->read_pos, bytes_read ); + remove_data( req, bytes_read ); + } + + if (size > bytes_read && (!bytes_read || sync)) { + if (NETCON_recv( &req->netConnection, (char *)buffer + bytes_read, size - bytes_read, + sync ? MSG_WAITALL : 0, &len) == ERROR_SUCCESS) + bytes_read += len; + /* always return success, even if the network layer returns an error */ + } + + finished_reading = !bytes_read && req->dwContentRead == req->dwContentLength; + req->dwContentRead += bytes_read; + } +done: *read = bytes_read; - if(req->lpszCacheFile) { + TRACE( "retrieved %u bytes (%u/%u)\n", bytes_read, req->dwContentRead, req->dwContentLength ); + LeaveCriticalSection( &req->read_section ); + + if(ret == ERROR_SUCCESS && req->lpszCacheFile) { BOOL res; DWORD dwBytesWritten; @@ -1630,119 +2110,23 @@ static DWORD HTTP_Read(WININETHTTPREQW *req, void *buffer, DWORD size, DWORD *re WARN("WriteFile failed: %u\n", GetLastError()); } - if(!bytes_read && (req->dwContentRead == req->dwContentLength)) + if(finished_reading) HTTP_FinishedReading(req); - return ERROR_SUCCESS; + return ret; } -static DWORD get_chunk_size(const char *buffer) + +static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buffer, DWORD size, DWORD *read) { - const char *p; - DWORD size = 0; - - for (p = buffer; *p; p++) - { - if (*p >= '0' && *p <= '9') size = size * 16 + *p - '0'; - else if (*p >= 'a' && *p <= 'f') size = size * 16 + *p - 'a' + 10; - else if (*p >= 'A' && *p <= 'F') size = size * 16 + *p - 'A' + 10; - else if (*p == ';') break; - } - return size; -} - -static DWORD HTTP_ReadChunked(WININETHTTPREQW *req, void *buffer, DWORD size, DWORD *read, BOOL sync) -{ - char reply[MAX_REPLY_LEN], *p = buffer; - DWORD buflen, to_read, to_write = size; - int bytes_read; - - *read = 0; - for (;;) - { - if (*read == size) break; - - if (req->dwContentLength == ~0UL) /* new chunk */ - { - buflen = sizeof(reply); - if (!NETCON_getNextLine(&req->netConnection, reply, &buflen)) break; - - if (!(req->dwContentLength = get_chunk_size(reply))) - { - /* zero sized chunk marks end of transfer; read any trailing headers and return */ - HTTP_GetResponseHeaders(req, FALSE); - break; - } - } - to_read = min(to_write, req->dwContentLength - req->dwContentRead); - - if (!NETCON_recv(&req->netConnection, p, to_read, sync ? MSG_WAITALL : 0, &bytes_read)) - { - if (bytes_read != to_read) - ERR("Not all data received %d/%d\n", bytes_read, to_read); - - /* always return success, even if the network layer returns an error */ - *read = 0; - break; - } - if (!bytes_read) break; - - req->dwContentRead += bytes_read; - to_write -= bytes_read; - *read += bytes_read; - - if (req->lpszCacheFile) - { - DWORD dwBytesWritten; - - if (!WriteFile(req->hCacheFile, p, bytes_read, &dwBytesWritten, NULL)) - WARN("WriteFile failed: %u\n", GetLastError()); - } - p += bytes_read; - - if (req->dwContentRead == req->dwContentLength) /* chunk complete */ - { - req->dwContentRead = 0; - req->dwContentLength = ~0UL; - - buflen = sizeof(reply); - if (!NETCON_getNextLine(&req->netConnection, reply, &buflen)) - { - ERR("Malformed chunk\n"); - *read = 0; - break; - } - } - } - if (!*read) HTTP_FinishedReading(req); - return ERROR_SUCCESS; -} - -static DWORD HTTPREQ_Read(WININETHTTPREQW *req, void *buffer, DWORD size, DWORD *read, BOOL sync) -{ - WCHAR encoding[20]; - DWORD buflen = sizeof(encoding); - static const WCHAR szChunked[] = {'c','h','u','n','k','e','d',0}; - - if (HTTP_HttpQueryInfoW(req, HTTP_QUERY_TRANSFER_ENCODING, encoding, &buflen, NULL) && - !strcmpiW(encoding, szChunked)) - { - return HTTP_ReadChunked(req, buffer, size, read, sync); - } - else - return HTTP_Read(req, buffer, size, read, sync); -} - -static DWORD HTTPREQ_ReadFile(WININETHANDLEHEADER *hdr, void *buffer, DWORD size, DWORD *read) -{ - WININETHTTPREQW *req = (WININETHTTPREQW*)hdr; + http_request_t *req = (http_request_t*)hdr; return HTTPREQ_Read(req, buffer, size, read, TRUE); } -static void HTTPREQ_AsyncReadFileExProc(WORKREQUEST *workRequest) +static void HTTPREQ_AsyncReadFileExAProc(WORKREQUEST *workRequest) { struct WORKREQ_INTERNETREADFILEEXA const *data = &workRequest->u.InternetReadFileExA; - WININETHTTPREQW *req = (WININETHTTPREQW*)workRequest->hdr; + http_request_t *req = (http_request_t*)workRequest->hdr; INTERNET_ASYNC_RESULT iar; DWORD res; @@ -1759,11 +2143,10 @@ static void HTTPREQ_AsyncReadFileExProc(WORKREQUEST *workRequest) sizeof(INTERNET_ASYNC_RESULT)); } -static DWORD HTTPREQ_ReadFileExA(WININETHANDLEHEADER *hdr, INTERNET_BUFFERSA *buffers, +static DWORD HTTPREQ_ReadFileExA(object_header_t *hdr, INTERNET_BUFFERSA *buffers, DWORD flags, DWORD_PTR context) { - - WININETHTTPREQW *req = (WININETHTTPREQW*)hdr; + http_request_t *req = (http_request_t*)hdr; DWORD res; if (flags & ~(IRF_ASYNC|IRF_NO_WAIT)) @@ -1774,27 +2157,35 @@ static DWORD HTTPREQ_ReadFileExA(WININETHANDLEHEADER *hdr, INTERNET_BUFFERSA *bu INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); - if (hdr->dwFlags & INTERNET_FLAG_ASYNC) { - DWORD available = 0; + if ((hdr->dwFlags & INTERNET_FLAG_ASYNC) && !get_avail_data(req)) + { + WORKREQUEST workRequest; - NETCON_query_data_available(&req->netConnection, &available); - if (!available) + if (TryEnterCriticalSection( &req->read_section )) { - WORKREQUEST workRequest; - - workRequest.asyncproc = HTTPREQ_AsyncReadFileExProc; - workRequest.hdr = WININET_AddRef(&req->hdr); - workRequest.u.InternetReadFileExA.lpBuffersOut = buffers; - - INTERNET_AsyncCall(&workRequest); - - return ERROR_IO_PENDING; + if (get_avail_data(req)) + { + res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength, + &buffers->dwBufferLength, FALSE); + LeaveCriticalSection( &req->read_section ); + goto done; + } + LeaveCriticalSection( &req->read_section ); } + + workRequest.asyncproc = HTTPREQ_AsyncReadFileExAProc; + workRequest.hdr = WININET_AddRef(&req->hdr); + workRequest.u.InternetReadFileExA.lpBuffersOut = buffers; + + INTERNET_AsyncCall(&workRequest); + + return ERROR_IO_PENDING; } res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength, !(flags & IRF_NO_WAIT)); +done: if (res == ERROR_SUCCESS) { DWORD size = buffers->dwBufferLength; INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED, @@ -1804,52 +2195,120 @@ static DWORD HTTPREQ_ReadFileExA(WININETHANDLEHEADER *hdr, INTERNET_BUFFERSA *bu return res; } -static BOOL HTTPREQ_WriteFile(WININETHANDLEHEADER *hdr, const void *buffer, DWORD size, DWORD *written) +static void HTTPREQ_AsyncReadFileExWProc(WORKREQUEST *workRequest) { - LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW)hdr; + struct WORKREQ_INTERNETREADFILEEXW const *data = &workRequest->u.InternetReadFileExW; + http_request_t *req = (http_request_t*)workRequest->hdr; + INTERNET_ASYNC_RESULT iar; + DWORD res; - return NETCON_send(&lpwhr->netConnection, buffer, size, 0, (LPINT)written); + TRACE("INTERNETREADFILEEXW %p\n", workRequest->hdr); + + res = HTTPREQ_Read(req, data->lpBuffersOut->lpvBuffer, + data->lpBuffersOut->dwBufferLength, &data->lpBuffersOut->dwBufferLength, TRUE); + + iar.dwResult = res == ERROR_SUCCESS; + iar.dwError = res; + + INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, + INTERNET_STATUS_REQUEST_COMPLETE, &iar, + sizeof(INTERNET_ASYNC_RESULT)); +} + +static DWORD HTTPREQ_ReadFileExW(object_header_t *hdr, INTERNET_BUFFERSW *buffers, + DWORD flags, DWORD_PTR context) +{ + + http_request_t *req = (http_request_t*)hdr; + DWORD res; + + if (flags & ~(IRF_ASYNC|IRF_NO_WAIT)) + FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT)); + + if (buffers->dwStructSize != sizeof(*buffers)) + return ERROR_INVALID_PARAMETER; + + INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); + + if (hdr->dwFlags & INTERNET_FLAG_ASYNC) + { + WORKREQUEST workRequest; + + if (TryEnterCriticalSection( &req->read_section )) + { + if (get_avail_data(req)) + { + res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength, + &buffers->dwBufferLength, FALSE); + LeaveCriticalSection( &req->read_section ); + goto done; + } + LeaveCriticalSection( &req->read_section ); + } + + workRequest.asyncproc = HTTPREQ_AsyncReadFileExWProc; + workRequest.hdr = WININET_AddRef(&req->hdr); + workRequest.u.InternetReadFileExW.lpBuffersOut = buffers; + + INTERNET_AsyncCall(&workRequest); + + return ERROR_IO_PENDING; + } + + res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength, + !(flags & IRF_NO_WAIT)); + +done: + if (res == ERROR_SUCCESS) { + DWORD size = buffers->dwBufferLength; + INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED, + &size, sizeof(size)); + } + + return res; +} + +static DWORD HTTPREQ_WriteFile(object_header_t *hdr, const void *buffer, DWORD size, DWORD *written) +{ + DWORD res; + http_request_t *lpwhr = (http_request_t*)hdr; + + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0); + + *written = 0; + res = NETCON_send(&lpwhr->netConnection, buffer, size, 0, (LPINT)written); + if (res == ERROR_SUCCESS) + lpwhr->dwBytesWritten += *written; + + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REQUEST_SENT, written, sizeof(DWORD)); + return res; } static void HTTPREQ_AsyncQueryDataAvailableProc(WORKREQUEST *workRequest) { - WININETHTTPREQW *req = (WININETHTTPREQW*)workRequest->hdr; - INTERNET_ASYNC_RESULT iar; - char buffer[4048]; + http_request_t *req = (http_request_t*)workRequest->hdr; - TRACE("%p\n", workRequest->hdr); - - iar.dwResult = NETCON_recv(&req->netConnection, buffer, - min(sizeof(buffer), req->dwContentLength - req->dwContentRead), - MSG_PEEK, (int *)&iar.dwError); - - INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar, - sizeof(INTERNET_ASYNC_RESULT)); + HTTP_ReceiveRequestData(req, FALSE); } -static DWORD HTTPREQ_QueryDataAvailable(WININETHANDLEHEADER *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx) +static DWORD HTTPREQ_QueryDataAvailable(object_header_t *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx) { - WININETHTTPREQW *req = (WININETHTTPREQW*)hdr; - BYTE buffer[4048]; - BOOL async; + http_request_t *req = (http_request_t*)hdr; TRACE("(%p %p %x %lx)\n", req, available, flags, ctx); - if(!NETCON_query_data_available(&req->netConnection, available) || *available) - return ERROR_SUCCESS; - - /* Even if we are in async mode, we need to determine whether - * there is actually more data available. We do this by trying - * to peek only a single byte in async mode. */ - async = (req->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC) != 0; - - if (NETCON_recv(&req->netConnection, buffer, - min(async ? 1 : sizeof(buffer), req->dwContentLength - req->dwContentRead), - MSG_PEEK, (int *)available) && async && *available) + if (req->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC) { WORKREQUEST workRequest; - *available = 0; + /* never wait, if we can't enter the section we queue an async request right away */ + if (TryEnterCriticalSection( &req->read_section )) + { + if ((*available = get_avail_data( req ))) goto done; + if (end_of_read_data( req )) goto done; + LeaveCriticalSection( &req->read_section ); + } + workRequest.asyncproc = HTTPREQ_AsyncQueryDataAvailableProc; workRequest.hdr = WININET_AddRef( &req->hdr ); @@ -1858,16 +2317,35 @@ static DWORD HTTPREQ_QueryDataAvailable(WININETHANDLEHEADER *hdr, DWORD *availab return ERROR_IO_PENDING; } + EnterCriticalSection( &req->read_section ); + + if (!(*available = get_avail_data( req )) && !end_of_read_data( req )) + { + refill_buffer( req ); + *available = get_avail_data( req ); + } + +done: + if (*available == sizeof(req->read_buf) && !req->gzip_stream) /* check if we have even more pending in the socket */ + { + DWORD extra; + if (NETCON_query_data_available(&req->netConnection, &extra)) + *available = min( *available + extra, req->dwContentLength - req->dwContentRead ); + } + LeaveCriticalSection( &req->read_section ); + + TRACE( "returning %u\n", *available ); return ERROR_SUCCESS; } -static const HANDLEHEADERVtbl HTTPREQVtbl = { +static const object_vtbl_t HTTPREQVtbl = { HTTPREQ_Destroy, HTTPREQ_CloseConnection, HTTPREQ_QueryOption, HTTPREQ_SetOption, HTTPREQ_ReadFile, HTTPREQ_ReadFileExA, + HTTPREQ_ReadFileExW, HTTPREQ_WriteFile, HTTPREQ_QueryDataAvailable, NULL @@ -1883,27 +2361,27 @@ static const HANDLEHEADERVtbl HTTPREQVtbl = { * NULL on failure * */ -HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs, - LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion, - LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes, - DWORD dwFlags, DWORD_PTR dwContext) +static DWORD HTTP_HttpOpenRequestW(http_session_t *lpwhs, + LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion, + LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes, + DWORD dwFlags, DWORD_PTR dwContext, HINTERNET *ret) { - LPWININETAPPINFOW hIC = NULL; - LPWININETHTTPREQW lpwhr; + appinfo_t *hIC = NULL; + http_request_t *lpwhr; LPWSTR lpszHostName = NULL; HINTERNET handle = NULL; static const WCHAR szHostForm[] = {'%','s',':','%','u',0}; - DWORD len; + DWORD len, res; TRACE("-->\n"); assert( lpwhs->hdr.htype == WH_HHTTPSESSION ); hIC = lpwhs->lpAppInfo; - lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPREQW)); + lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(http_request_t)); if (NULL == lpwhr) { - INTERNET_SetLastError(ERROR_OUTOFMEMORY); + res = ERROR_OUTOFMEMORY; goto lend; } lpwhr->hdr.htype = WH_HHTTPREQ; @@ -1913,6 +2391,8 @@ HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs, lpwhr->hdr.refs = 1; lpwhr->hdr.lpfnStatusCB = lpwhs->hdr.lpfnStatusCB; lpwhr->hdr.dwInternalFlags = lpwhs->hdr.dwInternalFlags & INET_CALLBACKW; + lpwhr->dwContentLength = ~0u; + InitializeCriticalSection( &lpwhr->read_section ); WININET_AddRef( &lpwhs->hdr ); lpwhr->lpHttpSession = lpwhs; @@ -1922,18 +2402,18 @@ HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs, (strlenW(lpwhs->lpszHostName) + 7 /* length of ":65535" + 1 */)); if (NULL == lpszHostName) { - INTERNET_SetLastError(ERROR_OUTOFMEMORY); + res = ERROR_OUTOFMEMORY; goto lend; } handle = WININET_AllocHandle( &lpwhr->hdr ); if (NULL == handle) { - INTERNET_SetLastError(ERROR_OUTOFMEMORY); + res = ERROR_OUTOFMEMORY; goto lend; } - if (!NETCON_init(&lpwhr->netConnection, dwFlags & INTERNET_FLAG_SECURE)) + if ((res = NETCON_init(&lpwhr->netConnection, dwFlags & INTERNET_FLAG_SECURE)) != ERROR_SUCCESS) { InternetCloseHandle( handle ); handle = NULL; @@ -1950,11 +2430,15 @@ HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs, lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); rc = UrlEscapeW(lpszObjectName, lpwhr->lpszPath, &len, URL_ESCAPE_SPACES_ONLY); - if (rc) + if (rc != S_OK) { ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(lpszObjectName),rc); strcpyW(lpwhr->lpszPath,lpszObjectName); } + }else { + static const WCHAR slashW[] = {'/',0}; + + lpwhr->lpszPath = heap_strdupW(slashW); } if (lpszReferrer && *lpszReferrer) @@ -1973,23 +2457,19 @@ HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs, } } - lpwhr->lpszVerb = WININET_strdupW(lpszVerb && *lpszVerb ? lpszVerb : szGET); - - if (lpszVersion) - lpwhr->lpszVersion = WININET_strdupW(lpszVersion); - else - lpwhr->lpszVersion = WININET_strdupW(g_szHttp1_1); + lpwhr->lpszVerb = heap_strdupW(lpszVerb && *lpszVerb ? lpszVerb : szGET); + lpwhr->lpszVersion = heap_strdupW(lpszVersion ? lpszVersion : g_szHttp1_1); if (lpwhs->nHostPort != INTERNET_INVALID_PORT_NUMBER && lpwhs->nHostPort != INTERNET_DEFAULT_HTTP_PORT && lpwhs->nHostPort != INTERNET_DEFAULT_HTTPS_PORT) { sprintfW(lpszHostName, szHostForm, lpwhs->lpszHostName, lpwhs->nHostPort); - HTTP_ProcessHeader(lpwhr, szHost, lpszHostName, + HTTP_ProcessHeader(lpwhr, hostW, lpszHostName, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ); } else - HTTP_ProcessHeader(lpwhr, szHost, lpwhs->lpszHostName, + HTTP_ProcessHeader(lpwhr, hostW, lpwhs->lpszHostName, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ); if (lpwhs->nServerPort == INTERNET_INVALID_PORT_NUMBER) @@ -2015,81 +2495,89 @@ lend: WININET_Release( &lpwhr->hdr ); TRACE("<-- %p (%p)\n", handle, lpwhr); + *ret = handle; + return res; +} + +/*********************************************************************** + * HttpOpenRequestW (WININET.@) + * + * Open a HTTP request handle + * + * RETURNS + * HINTERNET a HTTP request handle on success + * NULL on failure + * + */ +HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession, + LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion, + LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes, + DWORD dwFlags, DWORD_PTR dwContext) +{ + http_session_t *lpwhs; + HINTERNET handle = NULL; + DWORD res; + + TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession, + debugstr_w(lpszVerb), debugstr_w(lpszObjectName), + debugstr_w(lpszVersion), debugstr_w(lpszReferrer), lpszAcceptTypes, + dwFlags, dwContext); + if(lpszAcceptTypes!=NULL) + { + int i; + for(i=0;lpszAcceptTypes[i]!=NULL;i++) + TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes[i])); + } + + lpwhs = (http_session_t*) WININET_GetObject( hHttpSession ); + if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION) + { + res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; + goto lend; + } + + /* + * My tests seem to show that the windows version does not + * become asynchronous until after this point. And anyhow + * if this call was asynchronous then how would you get the + * necessary HINTERNET pointer returned by this function. + * + */ + res = HTTP_HttpOpenRequestW(lpwhs, lpszVerb, lpszObjectName, + lpszVersion, lpszReferrer, lpszAcceptTypes, + dwFlags, dwContext, &handle); +lend: + if( lpwhs ) + WININET_Release( &lpwhs->hdr ); + TRACE("returning %p\n", handle); + if(res != ERROR_SUCCESS) + SetLastError(res); return handle; } /* read any content returned by the server so that the connection can be * reused */ -static void HTTP_DrainContent(WININETHTTPREQW *req) +static void HTTP_DrainContent(http_request_t *req) { DWORD bytes_read; if (!NETCON_connected(&req->netConnection)) return; if (req->dwContentLength == -1) + { NETCON_close(&req->netConnection); + return; + } + if (!strcmpW(req->lpszVerb, szHEAD)) return; do { char buffer[2048]; - if (HTTP_Read(req, buffer, sizeof(buffer), &bytes_read, TRUE) != ERROR_SUCCESS) + if (HTTPREQ_Read(req, buffer, sizeof(buffer), &bytes_read, TRUE) != ERROR_SUCCESS) return; } while (bytes_read); } -static const WCHAR szAccept[] = { 'A','c','c','e','p','t',0 }; -static const WCHAR szAccept_Charset[] = { 'A','c','c','e','p','t','-','C','h','a','r','s','e','t', 0 }; -static const WCHAR szAccept_Encoding[] = { 'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',0 }; -static const WCHAR szAccept_Language[] = { 'A','c','c','e','p','t','-','L','a','n','g','u','a','g','e',0 }; -static const WCHAR szAccept_Ranges[] = { 'A','c','c','e','p','t','-','R','a','n','g','e','s',0 }; -static const WCHAR szAge[] = { 'A','g','e',0 }; -static const WCHAR szAllow[] = { 'A','l','l','o','w',0 }; -static const WCHAR szCache_Control[] = { 'C','a','c','h','e','-','C','o','n','t','r','o','l',0 }; -static const WCHAR szConnection[] = { 'C','o','n','n','e','c','t','i','o','n',0 }; -static const WCHAR szContent_Base[] = { 'C','o','n','t','e','n','t','-','B','a','s','e',0 }; -static const WCHAR szContent_Encoding[] = { 'C','o','n','t','e','n','t','-','E','n','c','o','d','i','n','g',0 }; -static const WCHAR szContent_ID[] = { 'C','o','n','t','e','n','t','-','I','D',0 }; -static const WCHAR szContent_Language[] = { 'C','o','n','t','e','n','t','-','L','a','n','g','u','a','g','e',0 }; -static const WCHAR szContent_Length[] = { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0 }; -static const WCHAR szContent_Location[] = { 'C','o','n','t','e','n','t','-','L','o','c','a','t','i','o','n',0 }; -static const WCHAR szContent_MD5[] = { 'C','o','n','t','e','n','t','-','M','D','5',0 }; -static const WCHAR szContent_Range[] = { 'C','o','n','t','e','n','t','-','R','a','n','g','e',0 }; -static const WCHAR szContent_Transfer_Encoding[] = { 'C','o','n','t','e','n','t','-','T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 }; -static const WCHAR szContent_Type[] = { 'C','o','n','t','e','n','t','-','T','y','p','e',0 }; -static const WCHAR szCookie[] = { 'C','o','o','k','i','e',0 }; -static const WCHAR szDate[] = { 'D','a','t','e',0 }; -static const WCHAR szFrom[] = { 'F','r','o','m',0 }; -static const WCHAR szETag[] = { 'E','T','a','g',0 }; -static const WCHAR szExpect[] = { 'E','x','p','e','c','t',0 }; -static const WCHAR szExpires[] = { 'E','x','p','i','r','e','s',0 }; -static const WCHAR szIf_Match[] = { 'I','f','-','M','a','t','c','h',0 }; -static const WCHAR szIf_Modified_Since[] = { 'I','f','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 }; -static const WCHAR szIf_None_Match[] = { 'I','f','-','N','o','n','e','-','M','a','t','c','h',0 }; -static const WCHAR szIf_Range[] = { 'I','f','-','R','a','n','g','e',0 }; -static const WCHAR szIf_Unmodified_Since[] = { 'I','f','-','U','n','m','o','d','i','f','i','e','d','-','S','i','n','c','e',0 }; -static const WCHAR szLast_Modified[] = { 'L','a','s','t','-','M','o','d','i','f','i','e','d',0 }; -static const WCHAR szLocation[] = { 'L','o','c','a','t','i','o','n',0 }; -static const WCHAR szMax_Forwards[] = { 'M','a','x','-','F','o','r','w','a','r','d','s',0 }; -static const WCHAR szMime_Version[] = { 'M','i','m','e','-','V','e','r','s','i','o','n',0 }; -static const WCHAR szPragma[] = { 'P','r','a','g','m','a',0 }; -static const WCHAR szProxy_Authenticate[] = { 'P','r','o','x','y','-','A','u','t','h','e','n','t','i','c','a','t','e',0 }; -static const WCHAR szProxy_Connection[] = { 'P','r','o','x','y','-','C','o','n','n','e','c','t','i','o','n',0 }; -static const WCHAR szPublic[] = { 'P','u','b','l','i','c',0 }; -static const WCHAR szRange[] = { 'R','a','n','g','e',0 }; -static const WCHAR szReferer[] = { 'R','e','f','e','r','e','r',0 }; -static const WCHAR szRetry_After[] = { 'R','e','t','r','y','-','A','f','t','e','r',0 }; -static const WCHAR szServer[] = { 'S','e','r','v','e','r',0 }; -static const WCHAR szSet_Cookie[] = { 'S','e','t','-','C','o','o','k','i','e',0 }; -static const WCHAR szTransfer_Encoding[] = { 'T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 }; -static const WCHAR szUnless_Modified_Since[] = { 'U','n','l','e','s','s','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 }; -static const WCHAR szUpgrade[] = { 'U','p','g','r','a','d','e',0 }; -static const WCHAR szURI[] = { 'U','R','I',0 }; -static const WCHAR szUser_Agent[] = { 'U','s','e','r','-','A','g','e','n','t',0 }; -static const WCHAR szVary[] = { 'V','a','r','y',0 }; -static const WCHAR szVia[] = { 'V','i','a',0 }; -static const WCHAR szWarning[] = { 'W','a','r','n','i','n','g',0 }; -static const WCHAR szWWW_Authenticate[] = { 'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',0 }; - static const LPCWSTR header_lookup[] = { szMime_Version, /* HTTP_QUERY_MIME_VERSION = 0 */ szContent_Type, /* HTTP_QUERY_CONTENT_TYPE = 1 */ @@ -2146,7 +2634,7 @@ static const LPCWSTR header_lookup[] = { szContent_MD5, /* HTTP_QUERY_CONTENT_MD5 = 52 */ szContent_Range, /* HTTP_QUERY_CONTENT_RANGE = 53 */ szETag, /* HTTP_QUERY_ETAG = 54 */ - szHost, /* HTTP_QUERY_HOST = 55 */ + hostW, /* HTTP_QUERY_HOST = 55 */ szIf_Match, /* HTTP_QUERY_IF_MATCH = 56 */ szIf_None_Match, /* HTTP_QUERY_IF_NONE_MATCH = 57 */ szIf_Range, /* HTTP_QUERY_IF_RANGE = 58 */ @@ -2169,58 +2657,64 @@ static const LPCWSTR header_lookup[] = { /*********************************************************************** * HTTP_HttpQueryInfoW (internal) */ -static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLevel, - LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex) +static DWORD HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel, + LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex) { LPHTTPHEADERW lphttpHdr = NULL; - BOOL bSuccess = FALSE; BOOL request_only = dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS; INT requested_index = lpdwIndex ? *lpdwIndex : 0; - INT level = (dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK); + DWORD level = (dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK); INT index = -1; /* Find requested header structure */ switch (level) { case HTTP_QUERY_CUSTOM: + if (!lpBuffer) return ERROR_INVALID_PARAMETER; index = HTTP_GetCustomHeaderIndex(lpwhr, lpBuffer, requested_index, request_only); break; - case HTTP_QUERY_RAW_HEADERS_CRLF: { LPWSTR headers; - DWORD len; - BOOL ret = FALSE; + DWORD len = 0; + DWORD res = ERROR_INVALID_PARAMETER; if (request_only) headers = HTTP_BuildHeaderRequestString(lpwhr, lpwhr->lpszVerb, lpwhr->lpszPath, lpwhr->lpszVersion); else headers = lpwhr->lpszRawHeaders; - len = (strlenW(headers) + 1) * sizeof(WCHAR); - if (len > *lpdwBufferLength) + if (headers) + len = strlenW(headers) * sizeof(WCHAR); + + if (len + sizeof(WCHAR) > *lpdwBufferLength) { - INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); - ret = FALSE; + len += sizeof(WCHAR); + res = ERROR_INSUFFICIENT_BUFFER; } else if (lpBuffer) { - memcpy(lpBuffer, headers, len); + if (headers) + memcpy(lpBuffer, headers, len + sizeof(WCHAR)); + else + { + len = strlenW(szCrLf) * sizeof(WCHAR); + memcpy(lpBuffer, szCrLf, sizeof(szCrLf)); + } TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len / sizeof(WCHAR))); - ret = TRUE; + res = ERROR_SUCCESS; } *lpdwBufferLength = len; if (request_only) HeapFree(GetProcessHeap(), 0, headers); - return ret; + return res; } case HTTP_QUERY_RAW_HEADERS: { - static const WCHAR szCrLf[] = {'\r','\n',0}; LPWSTR * ppszRawHeaderLines = HTTP_Tokenize(lpwhr->lpszRawHeaders, szCrLf); DWORD i, size = 0; - LPWSTR pszString = (WCHAR*)lpBuffer; + LPWSTR pszString = lpBuffer; for (i = 0; ppszRawHeaderLines[i]; i++) size += strlenW(ppszRawHeaderLines[i]) + 1; @@ -2229,24 +2723,23 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev { HTTP_FreeTokens(ppszRawHeaderLines); *lpdwBufferLength = (size + 1) * sizeof(WCHAR); - INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); - return FALSE; + return ERROR_INSUFFICIENT_BUFFER; } - - for (i = 0; ppszRawHeaderLines[i]; i++) + if (pszString) { - DWORD len = strlenW(ppszRawHeaderLines[i]); - memcpy(pszString, ppszRawHeaderLines[i], (len+1)*sizeof(WCHAR)); - pszString += len+1; + for (i = 0; ppszRawHeaderLines[i]; i++) + { + DWORD len = strlenW(ppszRawHeaderLines[i]); + memcpy(pszString, ppszRawHeaderLines[i], (len+1)*sizeof(WCHAR)); + pszString += len+1; + } + *pszString = '\0'; + TRACE("returning data: %s\n", debugstr_wn(lpBuffer, size)); } - *pszString = '\0'; - - TRACE("returning data: %s\n", debugstr_wn((WCHAR*)lpBuffer, size)); - *lpdwBufferLength = size * sizeof(WCHAR); HTTP_FreeTokens(ppszRawHeaderLines); - return TRUE; + return ERROR_SUCCESS; } case HTTP_QUERY_STATUS_TEXT: if (lpwhr->lpszStatusText) @@ -2255,15 +2748,15 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev if (len + 1 > *lpdwBufferLength/sizeof(WCHAR)) { *lpdwBufferLength = (len + 1) * sizeof(WCHAR); - INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); - return FALSE; + return ERROR_INSUFFICIENT_BUFFER; + } + if (lpBuffer) + { + memcpy(lpBuffer, lpwhr->lpszStatusText, (len + 1) * sizeof(WCHAR)); + TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len)); } - memcpy(lpBuffer, lpwhr->lpszStatusText, (len+1)*sizeof(WCHAR)); *lpdwBufferLength = len * sizeof(WCHAR); - - TRACE("returning data: %s\n", debugstr_wn((WCHAR*)lpBuffer, len)); - - return TRUE; + return ERROR_SUCCESS; } break; case HTTP_QUERY_VERSION: @@ -2273,21 +2766,25 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev if (len + 1 > *lpdwBufferLength/sizeof(WCHAR)) { *lpdwBufferLength = (len + 1) * sizeof(WCHAR); - INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); - return FALSE; + return ERROR_INSUFFICIENT_BUFFER; + } + if (lpBuffer) + { + memcpy(lpBuffer, lpwhr->lpszVersion, (len + 1) * sizeof(WCHAR)); + TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len)); } - memcpy(lpBuffer, lpwhr->lpszVersion, (len+1)*sizeof(WCHAR)); *lpdwBufferLength = len * sizeof(WCHAR); - - TRACE("returning data: %s\n", debugstr_wn((WCHAR*)lpBuffer, len)); - - return TRUE; + return ERROR_SUCCESS; } break; + case HTTP_QUERY_CONTENT_ENCODING: + index = HTTP_GetCustomHeaderIndex(lpwhr, header_lookup[lpwhr->gzip_stream ? HTTP_QUERY_CONTENT_TYPE : level], + requested_index,request_only); + break; default: assert (LAST_TABLE_HEADER == (HTTP_QUERY_UNLESS_MODIFIED_SINCE + 1)); - if (level >= 0 && level < LAST_TABLE_HEADER && header_lookup[level]) + if (level < LAST_TABLE_HEADER && header_lookup[level]) index = HTTP_GetCustomHeaderIndex(lpwhr, header_lookup[level], requested_index,request_only); } @@ -2300,22 +2797,18 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) && (~lphttpHdr->wFlags & HDR_ISREQUEST))) { - INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND); - return bSuccess; + return ERROR_HTTP_HEADER_NOT_FOUND; } - if (lpdwIndex) - (*lpdwIndex)++; + if (lpdwIndex && level != HTTP_QUERY_STATUS_CODE) (*lpdwIndex)++; /* coalesce value to requested type */ - if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) + if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER && lpBuffer) { - *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue); - bSuccess = TRUE; - - TRACE(" returning number : %d\n", *(int *)lpBuffer); - } - else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME) + *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue); + TRACE(" returning number: %d\n", *(int *)lpBuffer); + } + else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME && lpBuffer) { time_t tmpTime; struct tm tmpTM; @@ -2324,24 +2817,19 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev tmpTime = ConvertTimeString(lphttpHdr->lpszValue); tmpTM = *gmtime(&tmpTime); - STHook = (SYSTEMTIME *) lpBuffer; - if(STHook==NULL) - return bSuccess; + STHook = (SYSTEMTIME *)lpBuffer; + STHook->wDay = tmpTM.tm_mday; + STHook->wHour = tmpTM.tm_hour; + STHook->wMilliseconds = 0; + STHook->wMinute = tmpTM.tm_min; + STHook->wDayOfWeek = tmpTM.tm_wday; + STHook->wMonth = tmpTM.tm_mon + 1; + STHook->wSecond = tmpTM.tm_sec; + STHook->wYear = tmpTM.tm_year; - STHook->wDay = tmpTM.tm_mday; - STHook->wHour = tmpTM.tm_hour; - STHook->wMilliseconds = 0; - STHook->wMinute = tmpTM.tm_min; - STHook->wDayOfWeek = tmpTM.tm_wday; - STHook->wMonth = tmpTM.tm_mon + 1; - STHook->wSecond = tmpTM.tm_sec; - STHook->wYear = tmpTM.tm_year; - - bSuccess = TRUE; - - TRACE(" returning time : %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n", - STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek, - STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds); + TRACE(" returning time: %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n", + STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek, + STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds); } else if (lphttpHdr->lpszValue) { @@ -2350,17 +2838,16 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev if (len > *lpdwBufferLength) { *lpdwBufferLength = len; - INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); - return bSuccess; + return ERROR_INSUFFICIENT_BUFFER; + } + if (lpBuffer) + { + memcpy(lpBuffer, lphttpHdr->lpszValue, len); + TRACE("! returning string: %s\n", debugstr_w(lpBuffer)); } - - memcpy(lpBuffer, lphttpHdr->lpszValue, len); *lpdwBufferLength = len - sizeof(WCHAR); - bSuccess = TRUE; - - TRACE(" returning string : %s\n", debugstr_w(lpBuffer)); } - return bSuccess; + return ERROR_SUCCESS; } /*********************************************************************** @@ -2374,10 +2861,10 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev * */ BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel, - LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex) + LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex) { - BOOL bSuccess = FALSE; - LPWININETHTTPREQW lpwhr; + http_request_t *lpwhr; + DWORD res; if (TRACE_ON(wininet)) { #define FE(x) { x, #x } @@ -2463,7 +2950,7 @@ BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel, DWORD info = dwInfoLevel & HTTP_QUERY_HEADER_MASK; DWORD i; - TRACE("(%p, 0x%08x)--> %d\n", hHttpRequest, dwInfoLevel, dwInfoLevel); + TRACE("(%p, 0x%08x)--> %d\n", hHttpRequest, dwInfoLevel, info); TRACE(" Attribute:"); for (i = 0; i < (sizeof(query_flags) / sizeof(query_flags[0])); i++) { if (query_flags[i].val == info) { @@ -2489,24 +2976,26 @@ BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel, TRACE("\n"); } - lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest ); + lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest ); if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - goto lend; + res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; + goto lend; } if (lpBuffer == NULL) *lpdwBufferLength = 0; - bSuccess = HTTP_HttpQueryInfoW( lpwhr, dwInfoLevel, - lpBuffer, lpdwBufferLength, lpdwIndex); + res = HTTP_HttpQueryInfoW( lpwhr, dwInfoLevel, + lpBuffer, lpdwBufferLength, lpdwIndex); lend: if( lpwhr ) WININET_Release( &lpwhr->hdr ); - TRACE("%d <--\n", bSuccess); - return bSuccess; + TRACE("%u <--\n", res); + if(res != ERROR_SUCCESS) + SetLastError(res); + return res == ERROR_SUCCESS; } /*********************************************************************** @@ -2577,287 +3066,74 @@ BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel, } /*********************************************************************** - * HttpSendRequestExA (WININET.@) - * - * Sends the specified request to the HTTP server and allows chunked - * transfers. - * - * RETURNS - * Success: TRUE - * Failure: FALSE, call GetLastError() for more information. + * HTTP_GetRedirectURL (internal) */ -BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest, - LPINTERNET_BUFFERSA lpBuffersIn, - LPINTERNET_BUFFERSA lpBuffersOut, - DWORD dwFlags, DWORD_PTR dwContext) +static LPWSTR HTTP_GetRedirectURL(http_request_t *lpwhr, LPCWSTR lpszUrl) { - INTERNET_BUFFERSW BuffersInW; - BOOL rc = FALSE; - DWORD headerlen; - LPWSTR header = NULL; + static WCHAR szHttp[] = {'h','t','t','p',0}; + static WCHAR szHttps[] = {'h','t','t','p','s',0}; + http_session_t *lpwhs = lpwhr->lpHttpSession; + URL_COMPONENTSW urlComponents; + DWORD url_length = 0; + LPWSTR orig_url; + LPWSTR combined_url; - TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn, - lpBuffersOut, dwFlags, dwContext); + urlComponents.dwStructSize = sizeof(URL_COMPONENTSW); + urlComponents.lpszScheme = (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE) ? szHttps : szHttp; + urlComponents.dwSchemeLength = 0; + urlComponents.lpszHostName = lpwhs->lpszHostName; + urlComponents.dwHostNameLength = 0; + urlComponents.nPort = lpwhs->nHostPort; + urlComponents.lpszUserName = lpwhs->lpszUserName; + urlComponents.dwUserNameLength = 0; + urlComponents.lpszPassword = NULL; + urlComponents.dwPasswordLength = 0; + urlComponents.lpszUrlPath = lpwhr->lpszPath; + urlComponents.dwUrlPathLength = 0; + urlComponents.lpszExtraInfo = NULL; + urlComponents.dwExtraInfoLength = 0; - if (lpBuffersIn) + if (!InternetCreateUrlW(&urlComponents, 0, NULL, &url_length) && + (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) + return NULL; + + orig_url = HeapAlloc(GetProcessHeap(), 0, url_length); + + /* convert from bytes to characters */ + url_length = url_length / sizeof(WCHAR) - 1; + if (!InternetCreateUrlW(&urlComponents, 0, orig_url, &url_length)) { - BuffersInW.dwStructSize = sizeof(LPINTERNET_BUFFERSW); - if (lpBuffersIn->lpcszHeader) - { - headerlen = MultiByteToWideChar(CP_ACP,0,lpBuffersIn->lpcszHeader, - lpBuffersIn->dwHeadersLength,0,0); - header = HeapAlloc(GetProcessHeap(),0,headerlen*sizeof(WCHAR)); - if (!(BuffersInW.lpcszHeader = header)) - { - INTERNET_SetLastError(ERROR_OUTOFMEMORY); - return FALSE; - } - BuffersInW.dwHeadersLength = MultiByteToWideChar(CP_ACP, 0, - lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength, - header, headerlen); - } - else - BuffersInW.lpcszHeader = NULL; - BuffersInW.dwHeadersTotal = lpBuffersIn->dwHeadersTotal; - BuffersInW.lpvBuffer = lpBuffersIn->lpvBuffer; - BuffersInW.dwBufferLength = lpBuffersIn->dwBufferLength; - BuffersInW.dwBufferTotal = lpBuffersIn->dwBufferTotal; - BuffersInW.Next = NULL; + HeapFree(GetProcessHeap(), 0, orig_url); + return NULL; } - rc = HttpSendRequestExW(hRequest, lpBuffersIn ? &BuffersInW : NULL, NULL, dwFlags, dwContext); + url_length = 0; + if (!InternetCombineUrlW(orig_url, lpszUrl, NULL, &url_length, ICU_ENCODE_SPACES_ONLY) && + (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) + { + HeapFree(GetProcessHeap(), 0, orig_url); + return NULL; + } + combined_url = HeapAlloc(GetProcessHeap(), 0, url_length * sizeof(WCHAR)); - HeapFree(GetProcessHeap(),0,header); - - return rc; + if (!InternetCombineUrlW(orig_url, lpszUrl, combined_url, &url_length, ICU_ENCODE_SPACES_ONLY)) + { + HeapFree(GetProcessHeap(), 0, orig_url); + HeapFree(GetProcessHeap(), 0, combined_url); + return NULL; + } + HeapFree(GetProcessHeap(), 0, orig_url); + return combined_url; } -/*********************************************************************** - * HttpSendRequestExW (WININET.@) - * - * Sends the specified request to the HTTP server and allows chunked - * transfers - * - * RETURNS - * Success: TRUE - * Failure: FALSE, call GetLastError() for more information. - */ -BOOL WINAPI HttpSendRequestExW(HINTERNET hRequest, - LPINTERNET_BUFFERSW lpBuffersIn, - LPINTERNET_BUFFERSW lpBuffersOut, - DWORD dwFlags, DWORD_PTR dwContext) -{ - BOOL ret = FALSE; - LPWININETHTTPREQW lpwhr; - LPWININETHTTPSESSIONW lpwhs; - LPWININETAPPINFOW hIC; - - TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn, - lpBuffersOut, dwFlags, dwContext); - - lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest ); - - if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) - { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - goto lend; - } - - lpwhs = lpwhr->lpHttpSession; - assert(lpwhs->hdr.htype == WH_HHTTPSESSION); - hIC = lpwhs->lpAppInfo; - assert(hIC->hdr.htype == WH_HINIT); - - if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) - { - WORKREQUEST workRequest; - struct WORKREQ_HTTPSENDREQUESTW *req; - - workRequest.asyncproc = AsyncHttpSendRequestProc; - workRequest.hdr = WININET_AddRef( &lpwhr->hdr ); - req = &workRequest.u.HttpSendRequestW; - if (lpBuffersIn) - { - if (lpBuffersIn->lpcszHeader) - /* FIXME: this should use dwHeadersLength or may not be necessary at all */ - req->lpszHeader = WININET_strdupW(lpBuffersIn->lpcszHeader); - else - req->lpszHeader = NULL; - req->dwHeaderLength = lpBuffersIn->dwHeadersLength; - req->lpOptional = lpBuffersIn->lpvBuffer; - req->dwOptionalLength = lpBuffersIn->dwBufferLength; - req->dwContentLength = lpBuffersIn->dwBufferTotal; - } - else - { - req->lpszHeader = NULL; - req->dwHeaderLength = 0; - req->lpOptional = NULL; - req->dwOptionalLength = 0; - req->dwContentLength = 0; - } - - req->bEndRequest = FALSE; - - INTERNET_AsyncCall(&workRequest); - /* - * This is from windows. - */ - INTERNET_SetLastError(ERROR_IO_PENDING); - } - else - { - if (lpBuffersIn) - ret = HTTP_HttpSendRequestW(lpwhr, lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength, - lpBuffersIn->lpvBuffer, lpBuffersIn->dwBufferLength, - lpBuffersIn->dwBufferTotal, FALSE); - else - ret = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, FALSE); - } - -lend: - if ( lpwhr ) - WININET_Release( &lpwhr->hdr ); - - TRACE("<---\n"); - return ret; -} - -/*********************************************************************** - * HttpSendRequestW (WININET.@) - * - * Sends the specified request to the HTTP server - * - * RETURNS - * TRUE on success - * FALSE on failure - * - */ -BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders, - DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength) -{ - LPWININETHTTPREQW lpwhr; - LPWININETHTTPSESSIONW lpwhs = NULL; - LPWININETAPPINFOW hIC = NULL; - BOOL r; - - TRACE("%p, %s, %i, %p, %i)\n", hHttpRequest, - debugstr_wn(lpszHeaders, dwHeaderLength), dwHeaderLength, lpOptional, dwOptionalLength); - - lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest ); - if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) - { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - r = FALSE; - goto lend; - } - - lpwhs = lpwhr->lpHttpSession; - if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION) - { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - r = FALSE; - goto lend; - } - - hIC = lpwhs->lpAppInfo; - if (NULL == hIC || hIC->hdr.htype != WH_HINIT) - { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - r = FALSE; - goto lend; - } - - if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) - { - WORKREQUEST workRequest; - struct WORKREQ_HTTPSENDREQUESTW *req; - - workRequest.asyncproc = AsyncHttpSendRequestProc; - workRequest.hdr = WININET_AddRef( &lpwhr->hdr ); - req = &workRequest.u.HttpSendRequestW; - if (lpszHeaders) - { - req->lpszHeader = HeapAlloc(GetProcessHeap(), 0, dwHeaderLength * sizeof(WCHAR)); - memcpy(req->lpszHeader, lpszHeaders, dwHeaderLength * sizeof(WCHAR)); - } - else - req->lpszHeader = 0; - req->dwHeaderLength = dwHeaderLength; - req->lpOptional = lpOptional; - req->dwOptionalLength = dwOptionalLength; - req->dwContentLength = dwOptionalLength; - req->bEndRequest = TRUE; - - INTERNET_AsyncCall(&workRequest); - /* - * This is from windows. - */ - INTERNET_SetLastError(ERROR_IO_PENDING); - r = FALSE; - } - else - { - r = HTTP_HttpSendRequestW(lpwhr, lpszHeaders, - dwHeaderLength, lpOptional, dwOptionalLength, - dwOptionalLength, TRUE); - } -lend: - if( lpwhr ) - WININET_Release( &lpwhr->hdr ); - return r; -} - -/*********************************************************************** - * HttpSendRequestA (WININET.@) - * - * Sends the specified request to the HTTP server - * - * RETURNS - * TRUE on success - * FALSE on failure - * - */ -BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders, - DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength) -{ - BOOL result; - LPWSTR szHeaders=NULL; - DWORD nLen=dwHeaderLength; - if(lpszHeaders!=NULL) - { - nLen=MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,NULL,0); - szHeaders=HeapAlloc(GetProcessHeap(),0,nLen*sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,szHeaders,nLen); - } - result=HttpSendRequestW(hHttpRequest, szHeaders, nLen, lpOptional, dwOptionalLength); - HeapFree(GetProcessHeap(),0,szHeaders); - return result; -} - -static BOOL HTTP_GetRequestURL(WININETHTTPREQW *req, LPWSTR buf) -{ - LPHTTPHEADERW host_header; - - static const WCHAR formatW[] = {'h','t','t','p',':','/','/','%','s','%','s',0}; - - host_header = HTTP_GetHeader(req, szHost); - if(!host_header) - return FALSE; - - sprintfW(buf, formatW, host_header->lpszValue, req->lpszPath); /* FIXME */ - return TRUE; -} /*********************************************************************** * HTTP_HandleRedirect (internal) */ -static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl) +static DWORD HTTP_HandleRedirect(http_request_t *lpwhr, LPCWSTR lpszUrl) { - static const WCHAR szContentType[] = {'C','o','n','t','e','n','t','-','T','y','p','e',0}; - static const WCHAR szContentLength[] = {'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0}; - LPWININETHTTPSESSIONW lpwhs = lpwhr->lpHttpSession; - LPWININETAPPINFOW hIC = lpwhs->lpAppInfo; + http_session_t *lpwhs = lpwhr->lpHttpSession; + appinfo_t *hIC = lpwhs->lpAppInfo; BOOL using_proxy = hIC->lpszProxy && hIC->lpszProxy[0]; WCHAR path[INTERNET_MAX_URL_LENGTH]; int index; @@ -2873,55 +3149,6 @@ static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl) WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024]; static WCHAR szHttp[] = {'h','t','t','p',0}; static WCHAR szHttps[] = {'h','t','t','p','s',0}; - DWORD url_length = 0; - LPWSTR orig_url; - LPWSTR combined_url; - - urlComponents.dwStructSize = sizeof(URL_COMPONENTSW); - urlComponents.lpszScheme = (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE) ? szHttps : szHttp; - urlComponents.dwSchemeLength = 0; - urlComponents.lpszHostName = lpwhs->lpszHostName; - urlComponents.dwHostNameLength = 0; - urlComponents.nPort = lpwhs->nHostPort; - urlComponents.lpszUserName = lpwhs->lpszUserName; - urlComponents.dwUserNameLength = 0; - urlComponents.lpszPassword = NULL; - urlComponents.dwPasswordLength = 0; - urlComponents.lpszUrlPath = lpwhr->lpszPath; - urlComponents.dwUrlPathLength = 0; - urlComponents.lpszExtraInfo = NULL; - urlComponents.dwExtraInfoLength = 0; - - if (!InternetCreateUrlW(&urlComponents, 0, NULL, &url_length) && - (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) - return FALSE; - - orig_url = HeapAlloc(GetProcessHeap(), 0, url_length); - - /* convert from bytes to characters */ - url_length = url_length / sizeof(WCHAR) - 1; - if (!InternetCreateUrlW(&urlComponents, 0, orig_url, &url_length)) - { - HeapFree(GetProcessHeap(), 0, orig_url); - return FALSE; - } - - url_length = 0; - if (!InternetCombineUrlW(orig_url, lpszUrl, NULL, &url_length, ICU_ENCODE_SPACES_ONLY) && - (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) - { - HeapFree(GetProcessHeap(), 0, orig_url); - return FALSE; - } - combined_url = HeapAlloc(GetProcessHeap(), 0, url_length * sizeof(WCHAR)); - - if (!InternetCombineUrlW(orig_url, lpszUrl, combined_url, &url_length, ICU_ENCODE_SPACES_ONLY)) - { - HeapFree(GetProcessHeap(), 0, orig_url); - HeapFree(GetProcessHeap(), 0, combined_url); - return FALSE; - } - HeapFree(GetProcessHeap(), 0, orig_url); userName[0] = 0; hostName[0] = 0; @@ -2940,13 +3167,8 @@ static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl) urlComponents.dwUrlPathLength = 2048; urlComponents.lpszExtraInfo = NULL; urlComponents.dwExtraInfoLength = 0; - if(!InternetCrackUrlW(combined_url, strlenW(combined_url), 0, &urlComponents)) - { - HeapFree(GetProcessHeap(), 0, combined_url); - return FALSE; - } - - HeapFree(GetProcessHeap(), 0, combined_url); + if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents)) + return INTERNET_GetLastError(); if (!strncmpW(szHttp, urlComponents.lpszScheme, strlenW(szHttp)) && (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE)) @@ -3000,26 +3222,35 @@ static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl) sprintfW(lpwhs->lpszHostName, fmt, hostName, urlComponents.nPort); } else - lpwhs->lpszHostName = WININET_strdupW(hostName); + lpwhs->lpszHostName = heap_strdupW(hostName); - HTTP_ProcessHeader(lpwhr, szHost, lpwhs->lpszHostName, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDHDR_FLAG_REQ); + HTTP_ProcessHeader(lpwhr, hostW, lpwhs->lpszHostName, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDHDR_FLAG_REQ); HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName); lpwhs->lpszUserName = NULL; if (userName[0]) - lpwhs->lpszUserName = WININET_strdupW(userName); + lpwhs->lpszUserName = heap_strdupW(userName); if (!using_proxy) { if (strcmpiW(lpwhs->lpszServerName, hostName) || lpwhs->nServerPort != urlComponents.nPort) { + DWORD res; + HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName); - lpwhs->lpszServerName = WININET_strdupW(hostName); + lpwhs->lpszServerName = heap_strdupW(hostName); lpwhs->nServerPort = urlComponents.nPort; NETCON_close(&lpwhr->netConnection); - if (!HTTP_ResolveName(lpwhr)) return FALSE; - if (!NETCON_init(&lpwhr->netConnection, lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE)) return FALSE; + if ((res = HTTP_ResolveName(lpwhr)) != ERROR_SUCCESS) + return res; + + res = NETCON_init(&lpwhr->netConnection, lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE); + if (res != ERROR_SUCCESS) + return res; + + lpwhr->read_pos = lpwhr->read_size = 0; + lpwhr->read_chunked = FALSE; } } else @@ -3039,7 +3270,7 @@ static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl) lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed*sizeof(WCHAR)); rc = UrlEscapeW(path, lpwhr->lpszPath, &needed, URL_ESCAPE_SPACES_ONLY); - if (rc) + if (rc != S_OK) { ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(path),rc); strcpyW(lpwhr->lpszPath,path); @@ -3047,14 +3278,14 @@ static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl) } /* Remove custom content-type/length headers on redirects. */ - index = HTTP_GetCustomHeaderIndex(lpwhr, szContentType, 0, TRUE); + index = HTTP_GetCustomHeaderIndex(lpwhr, szContent_Type, 0, TRUE); if (0 <= index) HTTP_DeleteCustomHeader(lpwhr, index); - index = HTTP_GetCustomHeaderIndex(lpwhr, szContentLength, 0, TRUE); + index = HTTP_GetCustomHeaderIndex(lpwhr, szContent_Length, 0, TRUE); if (0 <= index) HTTP_DeleteCustomHeader(lpwhr, index); - return TRUE; + return ERROR_SUCCESS; } /*********************************************************************** @@ -3080,7 +3311,7 @@ static LPWSTR HTTP_build_req( LPCWSTR *list, int len ) return str; } -static BOOL HTTP_SecureProxyConnect(LPWININETHTTPREQW lpwhr) +static DWORD HTTP_SecureProxyConnect(http_request_t *lpwhr) { LPWSTR lpszPath; LPWSTR requestString; @@ -3088,10 +3319,10 @@ static BOOL HTTP_SecureProxyConnect(LPWININETHTTPREQW lpwhr) INT cnt; INT responseLen; char *ascii_req; - BOOL ret; + DWORD res; static const WCHAR szConnect[] = {'C','O','N','N','E','C','T',0}; static const WCHAR szFormat[] = {'%','s',':','%','d',0}; - LPWININETHTTPSESSIONW lpwhs = lpwhr->lpHttpSession; + http_session_t *lpwhs = lpwhr->lpHttpSession; TRACE("\n"); @@ -3110,43 +3341,42 @@ static BOOL HTTP_SecureProxyConnect(LPWININETHTTPREQW lpwhr) TRACE("full request -> %s\n", debugstr_an( ascii_req, len ) ); - ret = NETCON_send( &lpwhr->netConnection, ascii_req, len, 0, &cnt ); + res = NETCON_send( &lpwhr->netConnection, ascii_req, len, 0, &cnt ); HeapFree( GetProcessHeap(), 0, ascii_req ); - if (!ret || cnt < 0) - return FALSE; + if (res != ERROR_SUCCESS) + return res; responseLen = HTTP_GetResponseHeaders( lpwhr, TRUE ); if (!responseLen) - return FALSE; + return ERROR_HTTP_INVALID_HEADER; - return TRUE; + return ERROR_SUCCESS; } -static void HTTP_InsertCookies(LPWININETHTTPREQW lpwhr) +static void HTTP_InsertCookies(http_request_t *lpwhr) { - static const WCHAR szUrlForm[] = {'h','t','t','p',':','/','/','%','s',0}; + static const WCHAR szUrlForm[] = {'h','t','t','p',':','/','/','%','s','%','s',0}; LPWSTR lpszCookies, lpszUrl = NULL; DWORD nCookieSize, size; - LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr,szHost); + LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr, hostW); - size = (strlenW(Host->lpszValue) + strlenW(szUrlForm)) * sizeof(WCHAR); + size = (strlenW(Host->lpszValue) + strlenW(szUrlForm) + strlenW(lpwhr->lpszPath)) * sizeof(WCHAR); if (!(lpszUrl = HeapAlloc(GetProcessHeap(), 0, size))) return; - sprintfW( lpszUrl, szUrlForm, Host->lpszValue ); + sprintfW( lpszUrl, szUrlForm, Host->lpszValue, lpwhr->lpszPath); if (InternetGetCookieW(lpszUrl, NULL, NULL, &nCookieSize)) { int cnt = 0; static const WCHAR szCookie[] = {'C','o','o','k','i','e',':',' ',0}; - static const WCHAR szcrlf[] = {'\r','\n',0}; - size = sizeof(szCookie) + nCookieSize * sizeof(WCHAR) + sizeof(szcrlf); + size = sizeof(szCookie) + nCookieSize * sizeof(WCHAR) + sizeof(szCrLf); if ((lpszCookies = HeapAlloc(GetProcessHeap(), 0, size))) { cnt += sprintfW(lpszCookies, szCookie); InternetGetCookieW(lpszUrl, NULL, lpszCookies + cnt, &nCookieSize); - strcatW(lpszCookies, szcrlf); + strcatW(lpszCookies, szCrLf); - HTTP_HttpAddRequestHeadersW(lpwhr, lpszCookies, strlenW(lpszCookies), HTTP_ADDREQ_FLAG_ADD); + HTTP_HttpAddRequestHeadersW(lpwhr, lpszCookies, strlenW(lpszCookies), HTTP_ADDREQ_FLAG_REPLACE); HeapFree(GetProcessHeap(), 0, lpszCookies); } } @@ -3163,12 +3393,12 @@ static void HTTP_InsertCookies(LPWININETHTTPREQW lpwhr) * FALSE on failure * */ -BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, +static DWORD HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders, DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength, DWORD dwContentLength, BOOL bEndRequest) { INT cnt; - BOOL bSuccess = FALSE; + BOOL redirected = FALSE; LPWSTR requestString = NULL; INT responseLen; BOOL loop_next; @@ -3177,6 +3407,7 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, static const WCHAR szContentLength[] = { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','l','i','\r','\n',0 }; WCHAR contentLengthStr[sizeof szContentLength/2 /* includes \r\n */ + 20 /* int */ ]; + DWORD res; TRACE("--> %p\n", lpwhr); @@ -3184,12 +3415,13 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, /* if the verb is NULL default to GET */ if (!lpwhr->lpszVerb) - lpwhr->lpszVerb = WININET_strdupW(szGET); + lpwhr->lpszVerb = heap_strdupW(szGET); - if (dwContentLength || !strcmpW(lpwhr->lpszVerb, szPost)) + if (dwContentLength || strcmpW(lpwhr->lpszVerb, szGET)) { sprintfW(contentLengthStr, szContentLength, dwContentLength); - HTTP_HttpAddRequestHeadersW(lpwhr, contentLengthStr, -1L, HTTP_ADDREQ_FLAG_ADD_IF_NEW); + HTTP_HttpAddRequestHeadersW(lpwhr, contentLengthStr, -1L, HTTP_ADDREQ_FLAG_REPLACE); + lpwhr->dwBytesToWrite = dwContentLength; } if (lpwhr->lpHttpSession->lpAppInfo->lpszAgent) { @@ -3230,7 +3462,7 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, if (TRACE_ON(wininet)) { - LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr,szHost); + LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr, hostW); TRACE("Going to url %s %s\n", debugstr_w(Host->lpszValue), debugstr_w(lpwhr->lpszPath)); } @@ -3265,11 +3497,11 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, TRACE("Request header -> %s\n", debugstr_w(requestString) ); /* Send the request and store the results */ - if (!HTTP_OpenConnection(lpwhr)) + if ((res = HTTP_OpenConnection(lpwhr)) != ERROR_SUCCESS) goto lend; /* send the request as ASCII, tack on the optional data */ - if( !lpOptional ) + if (!lpOptional || redirected) dwOptionalLength = 0; len = WideCharToMultiByte( CP_ACP, 0, requestString, -1, NULL, 0, NULL, NULL ); @@ -3285,9 +3517,11 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0); - NETCON_send(&lpwhr->netConnection, ascii_req, len, 0, &cnt); + res = NETCON_send(&lpwhr->netConnection, ascii_req, len, 0, &cnt); HeapFree( GetProcessHeap(), 0, ascii_req ); + lpwhr->dwBytesWritten = dwOptionalLength; + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REQUEST_SENT, &len, sizeof(DWORD)); @@ -3296,18 +3530,14 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, { DWORD dwBufferSize; DWORD dwStatusCode; - WCHAR encoding[20]; - static const WCHAR szChunked[] = {'c','h','u','n','k','e','d',0}; INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); - if (cnt < 0) + if (res != ERROR_SUCCESS) goto lend; responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE); - if (responseLen) - bSuccess = TRUE; INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, @@ -3315,61 +3545,58 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, HTTP_ProcessCookies(lpwhr); - dwBufferSize = sizeof(lpwhr->dwContentLength); - if (!HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH, - &lpwhr->dwContentLength,&dwBufferSize,NULL)) - lpwhr->dwContentLength = -1; - - if (lpwhr->dwContentLength == 0) - HTTP_FinishedReading(lpwhr); - - /* Correct the case where both a Content-Length and Transfer-encoding = chunked are set */ - - dwBufferSize = sizeof(encoding); - if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_TRANSFER_ENCODING, encoding, &dwBufferSize, NULL) && - !strcmpiW(encoding, szChunked)) - { - lpwhr->dwContentLength = -1; - } + if (!set_content_length( lpwhr )) HTTP_FinishedReading(lpwhr); dwBufferSize = sizeof(dwStatusCode); - if (!HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, - &dwStatusCode,&dwBufferSize,NULL)) + if (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, + &dwStatusCode,&dwBufferSize,NULL) != ERROR_SUCCESS) dwStatusCode = 0; - if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && bSuccess) + if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && responseLen) { - WCHAR szNewLocation[INTERNET_MAX_URL_LENGTH]; + WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH]; dwBufferSize=sizeof(szNewLocation); if ((dwStatusCode==HTTP_STATUS_REDIRECT || dwStatusCode==HTTP_STATUS_MOVED) && - HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,NULL)) + HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,NULL) == ERROR_SUCCESS) { - HTTP_DrainContent(lpwhr); - INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, - INTERNET_STATUS_REDIRECT, szNewLocation, - dwBufferSize); - bSuccess = HTTP_HandleRedirect(lpwhr, szNewLocation); - if (bSuccess) + if (strcmpW(lpwhr->lpszVerb, szGET) && strcmpW(lpwhr->lpszVerb, szHEAD)) { - HeapFree(GetProcessHeap(), 0, requestString); - loop_next = TRUE; + HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb); + lpwhr->lpszVerb = heap_strdupW(szGET); } + HTTP_DrainContent(lpwhr); + if ((new_url = HTTP_GetRedirectURL( lpwhr, szNewLocation ))) + { + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REDIRECT, + new_url, (strlenW(new_url) + 1) * sizeof(WCHAR)); + res = HTTP_HandleRedirect(lpwhr, new_url); + if (res == ERROR_SUCCESS) + { + HeapFree(GetProcessHeap(), 0, requestString); + loop_next = TRUE; + } + HeapFree( GetProcessHeap(), 0, new_url ); + } + redirected = TRUE; } } - if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTH) && bSuccess) + if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTH) && res == ERROR_SUCCESS) { WCHAR szAuthValue[2048]; dwBufferSize=2048; if (dwStatusCode == HTTP_STATUS_DENIED) { + LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr, hostW); DWORD dwIndex = 0; - while (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_WWW_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex)) + while (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_WWW_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex) == ERROR_SUCCESS) { if (HTTP_DoAuthorization(lpwhr, szAuthValue, &lpwhr->pAuthInfo, lpwhr->lpHttpSession->lpszUserName, - lpwhr->lpHttpSession->lpszPassword)) + lpwhr->lpHttpSession->lpszPassword, + Host->lpszValue)) { + HeapFree(GetProcessHeap(), 0, requestString); loop_next = TRUE; break; } @@ -3378,12 +3605,13 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, if (dwStatusCode == HTTP_STATUS_PROXY_AUTH_REQ) { DWORD dwIndex = 0; - while (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_PROXY_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex)) + while (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_PROXY_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex) == ERROR_SUCCESS) { if (HTTP_DoAuthorization(lpwhr, szAuthValue, &lpwhr->pProxyAuthInfo, lpwhr->lpHttpSession->lpAppInfo->lpszProxyUsername, - lpwhr->lpHttpSession->lpAppInfo->lpszProxyPassword)) + lpwhr->lpHttpSession->lpAppInfo->lpszProxyPassword, + NULL)) { loop_next = TRUE; break; @@ -3393,12 +3621,11 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, } } else - bSuccess = TRUE; + res = ERROR_SUCCESS; } while (loop_next); - /* FIXME: Better check, when we have to create the cache file */ - if(bSuccess && (lpwhr->hdr.dwFlags & INTERNET_FLAG_NEED_FILE)) { + if(res == ERROR_SUCCESS) { WCHAR url[INTERNET_MAX_URL_LENGTH]; WCHAR cacheFileName[MAX_PATH+1]; BOOL b; @@ -3411,7 +3638,10 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, b = CreateUrlCacheEntryW(url, lpwhr->dwContentLength > 0 ? lpwhr->dwContentLength : 0, NULL, cacheFileName, 0); if(b) { - lpwhr->lpszCacheFile = WININET_strdupW(cacheFileName); + HeapFree(GetProcessHeap(), 0, lpwhr->lpszCacheFile); + CloseHandle(lpwhr->hCacheFile); + + lpwhr->lpszCacheFile = heap_strdupW(cacheFileName); lpwhr->hCacheFile = CreateFileW(lpwhr->lpszCacheFile, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(lpwhr->hCacheFile == INVALID_HANDLE_VALUE) { @@ -3429,16 +3659,469 @@ lend: /* TODO: send notification for P3P header */ + if (lpwhr->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC) + { + if (res == ERROR_SUCCESS && lpwhr->dwBytesWritten == lpwhr->dwBytesToWrite) + HTTP_ReceiveRequestData(lpwhr, TRUE); + else + { + iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet; + iar.dwError = res; + + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, + INTERNET_STATUS_REQUEST_COMPLETE, &iar, + sizeof(INTERNET_ASYNC_RESULT)); + } + } + + TRACE("<--\n"); + return res; +} + +/*********************************************************************** + * + * Helper functions for the HttpSendRequest(Ex) functions + * + */ +static void AsyncHttpSendRequestProc(WORKREQUEST *workRequest) +{ + struct WORKREQ_HTTPSENDREQUESTW const *req = &workRequest->u.HttpSendRequestW; + http_request_t *lpwhr = (http_request_t*) workRequest->hdr; + + TRACE("%p\n", lpwhr); + + HTTP_HttpSendRequestW(lpwhr, req->lpszHeader, + req->dwHeaderLength, req->lpOptional, req->dwOptionalLength, + req->dwContentLength, req->bEndRequest); + + HeapFree(GetProcessHeap(), 0, req->lpszHeader); +} + + +static DWORD HTTP_HttpEndRequestW(http_request_t *lpwhr, DWORD dwFlags, DWORD_PTR dwContext) +{ + INT responseLen; + DWORD dwBufferSize; + INTERNET_ASYNC_RESULT iar; + DWORD res = ERROR_SUCCESS; + + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, + INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); + + responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE); + if (!responseLen) + res = ERROR_HTTP_HEADER_NOT_FOUND; + + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, + INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, sizeof(DWORD)); + + /* process cookies here. Is this right? */ + HTTP_ProcessCookies(lpwhr); + + if (!set_content_length( lpwhr )) HTTP_FinishedReading(lpwhr); + + if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT)) + { + DWORD dwCode,dwCodeLength = sizeof(DWORD); + if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, &dwCode, &dwCodeLength, NULL) == ERROR_SUCCESS + && (dwCode == 302 || dwCode == 301 || dwCode == 303)) + { + WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH]; + dwBufferSize=sizeof(szNewLocation); + if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_LOCATION, szNewLocation, &dwBufferSize, NULL) == ERROR_SUCCESS) + { + if (strcmpW(lpwhr->lpszVerb, szGET) && strcmpW(lpwhr->lpszVerb, szHEAD)) + { + HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb); + lpwhr->lpszVerb = heap_strdupW(szGET); + } + HTTP_DrainContent(lpwhr); + if ((new_url = HTTP_GetRedirectURL( lpwhr, szNewLocation ))) + { + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REDIRECT, + new_url, (strlenW(new_url) + 1) * sizeof(WCHAR)); + res = HTTP_HandleRedirect(lpwhr, new_url); + if (res == ERROR_SUCCESS) + res = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, TRUE); + HeapFree( GetProcessHeap(), 0, new_url ); + } + } + } + } + iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet; - iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); + iar.dwError = res; INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar, sizeof(INTERNET_ASYNC_RESULT)); + return res; +} - TRACE("<--\n"); - if (bSuccess) INTERNET_SetLastError(ERROR_SUCCESS); - return bSuccess; +/*********************************************************************** + * HttpEndRequestA (WININET.@) + * + * Ends an HTTP request that was started by HttpSendRequestEx + * + * RETURNS + * TRUE if successful + * FALSE on failure + * + */ +BOOL WINAPI HttpEndRequestA(HINTERNET hRequest, + LPINTERNET_BUFFERSA lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext) +{ + TRACE("(%p, %p, %08x, %08lx)\n", hRequest, lpBuffersOut, dwFlags, dwContext); + + if (lpBuffersOut) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return HttpEndRequestW(hRequest, NULL, dwFlags, dwContext); +} + +static void AsyncHttpEndRequestProc(WORKREQUEST *work) +{ + struct WORKREQ_HTTPENDREQUESTW const *req = &work->u.HttpEndRequestW; + http_request_t *lpwhr = (http_request_t*)work->hdr; + + TRACE("%p\n", lpwhr); + + HTTP_HttpEndRequestW(lpwhr, req->dwFlags, req->dwContext); +} + +/*********************************************************************** + * HttpEndRequestW (WININET.@) + * + * Ends an HTTP request that was started by HttpSendRequestEx + * + * RETURNS + * TRUE if successful + * FALSE on failure + * + */ +BOOL WINAPI HttpEndRequestW(HINTERNET hRequest, + LPINTERNET_BUFFERSW lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext) +{ + http_request_t *lpwhr; + DWORD res; + + TRACE("-->\n"); + + if (lpBuffersOut) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + lpwhr = (http_request_t*) WININET_GetObject( hRequest ); + + if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) + { + SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); + if (lpwhr) + WININET_Release( &lpwhr->hdr ); + return FALSE; + } + lpwhr->hdr.dwFlags |= dwFlags; + + if (lpwhr->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC) + { + WORKREQUEST work; + struct WORKREQ_HTTPENDREQUESTW *request; + + work.asyncproc = AsyncHttpEndRequestProc; + work.hdr = WININET_AddRef( &lpwhr->hdr ); + + request = &work.u.HttpEndRequestW; + request->dwFlags = dwFlags; + request->dwContext = dwContext; + + INTERNET_AsyncCall(&work); + res = ERROR_IO_PENDING; + } + else + res = HTTP_HttpEndRequestW(lpwhr, dwFlags, dwContext); + + WININET_Release( &lpwhr->hdr ); + TRACE("%u <--\n", res); + if(res != ERROR_SUCCESS) + SetLastError(res); + return res == ERROR_SUCCESS; +} + +/*********************************************************************** + * HttpSendRequestExA (WININET.@) + * + * Sends the specified request to the HTTP server and allows chunked + * transfers. + * + * RETURNS + * Success: TRUE + * Failure: FALSE, call GetLastError() for more information. + */ +BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest, + LPINTERNET_BUFFERSA lpBuffersIn, + LPINTERNET_BUFFERSA lpBuffersOut, + DWORD dwFlags, DWORD_PTR dwContext) +{ + INTERNET_BUFFERSW BuffersInW; + BOOL rc = FALSE; + DWORD headerlen; + LPWSTR header = NULL; + + TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn, + lpBuffersOut, dwFlags, dwContext); + + if (lpBuffersIn) + { + BuffersInW.dwStructSize = sizeof(LPINTERNET_BUFFERSW); + if (lpBuffersIn->lpcszHeader) + { + headerlen = MultiByteToWideChar(CP_ACP,0,lpBuffersIn->lpcszHeader, + lpBuffersIn->dwHeadersLength,0,0); + header = HeapAlloc(GetProcessHeap(),0,headerlen*sizeof(WCHAR)); + if (!(BuffersInW.lpcszHeader = header)) + { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + BuffersInW.dwHeadersLength = MultiByteToWideChar(CP_ACP, 0, + lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength, + header, headerlen); + } + else + BuffersInW.lpcszHeader = NULL; + BuffersInW.dwHeadersTotal = lpBuffersIn->dwHeadersTotal; + BuffersInW.lpvBuffer = lpBuffersIn->lpvBuffer; + BuffersInW.dwBufferLength = lpBuffersIn->dwBufferLength; + BuffersInW.dwBufferTotal = lpBuffersIn->dwBufferTotal; + BuffersInW.Next = NULL; + } + + rc = HttpSendRequestExW(hRequest, lpBuffersIn ? &BuffersInW : NULL, NULL, dwFlags, dwContext); + + HeapFree(GetProcessHeap(),0,header); + + return rc; +} + +/*********************************************************************** + * HttpSendRequestExW (WININET.@) + * + * Sends the specified request to the HTTP server and allows chunked + * transfers + * + * RETURNS + * Success: TRUE + * Failure: FALSE, call GetLastError() for more information. + */ +BOOL WINAPI HttpSendRequestExW(HINTERNET hRequest, + LPINTERNET_BUFFERSW lpBuffersIn, + LPINTERNET_BUFFERSW lpBuffersOut, + DWORD dwFlags, DWORD_PTR dwContext) +{ + http_request_t *lpwhr; + http_session_t *lpwhs; + appinfo_t *hIC; + DWORD res; + + TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn, + lpBuffersOut, dwFlags, dwContext); + + lpwhr = (http_request_t*) WININET_GetObject( hRequest ); + + if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) + { + res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; + goto lend; + } + + lpwhs = lpwhr->lpHttpSession; + assert(lpwhs->hdr.htype == WH_HHTTPSESSION); + hIC = lpwhs->lpAppInfo; + assert(hIC->hdr.htype == WH_HINIT); + + if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) + { + WORKREQUEST workRequest; + struct WORKREQ_HTTPSENDREQUESTW *req; + + workRequest.asyncproc = AsyncHttpSendRequestProc; + workRequest.hdr = WININET_AddRef( &lpwhr->hdr ); + req = &workRequest.u.HttpSendRequestW; + if (lpBuffersIn) + { + DWORD size = 0; + + if (lpBuffersIn->lpcszHeader) + { + if (lpBuffersIn->dwHeadersLength == ~0u) + size = (strlenW( lpBuffersIn->lpcszHeader ) + 1) * sizeof(WCHAR); + else + size = lpBuffersIn->dwHeadersLength * sizeof(WCHAR); + + req->lpszHeader = HeapAlloc( GetProcessHeap(), 0, size ); + memcpy( req->lpszHeader, lpBuffersIn->lpcszHeader, size ); + } + else req->lpszHeader = NULL; + + req->dwHeaderLength = size / sizeof(WCHAR); + req->lpOptional = lpBuffersIn->lpvBuffer; + req->dwOptionalLength = lpBuffersIn->dwBufferLength; + req->dwContentLength = lpBuffersIn->dwBufferTotal; + } + else + { + req->lpszHeader = NULL; + req->dwHeaderLength = 0; + req->lpOptional = NULL; + req->dwOptionalLength = 0; + req->dwContentLength = 0; + } + + req->bEndRequest = FALSE; + + INTERNET_AsyncCall(&workRequest); + /* + * This is from windows. + */ + res = ERROR_IO_PENDING; + } + else + { + if (lpBuffersIn) + res = HTTP_HttpSendRequestW(lpwhr, lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength, + lpBuffersIn->lpvBuffer, lpBuffersIn->dwBufferLength, + lpBuffersIn->dwBufferTotal, FALSE); + else + res = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, FALSE); + } + +lend: + if ( lpwhr ) + WININET_Release( &lpwhr->hdr ); + + TRACE("<---\n"); + SetLastError(res); + return res == ERROR_SUCCESS; +} + +/*********************************************************************** + * HttpSendRequestW (WININET.@) + * + * Sends the specified request to the HTTP server + * + * RETURNS + * TRUE on success + * FALSE on failure + * + */ +BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders, + DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength) +{ + http_request_t *lpwhr; + http_session_t *lpwhs = NULL; + appinfo_t *hIC = NULL; + DWORD res = ERROR_SUCCESS; + + TRACE("%p, %s, %i, %p, %i)\n", hHttpRequest, + debugstr_wn(lpszHeaders, dwHeaderLength), dwHeaderLength, lpOptional, dwOptionalLength); + + lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest ); + if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) + { + res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; + goto lend; + } + + lpwhs = lpwhr->lpHttpSession; + if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION) + { + res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; + goto lend; + } + + hIC = lpwhs->lpAppInfo; + if (NULL == hIC || hIC->hdr.htype != WH_HINIT) + { + res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; + goto lend; + } + + if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) + { + WORKREQUEST workRequest; + struct WORKREQ_HTTPSENDREQUESTW *req; + + workRequest.asyncproc = AsyncHttpSendRequestProc; + workRequest.hdr = WININET_AddRef( &lpwhr->hdr ); + req = &workRequest.u.HttpSendRequestW; + if (lpszHeaders) + { + DWORD size; + + if (dwHeaderLength == ~0u) size = (strlenW(lpszHeaders) + 1) * sizeof(WCHAR); + else size = dwHeaderLength * sizeof(WCHAR); + + req->lpszHeader = HeapAlloc(GetProcessHeap(), 0, size); + memcpy(req->lpszHeader, lpszHeaders, size); + } + else + req->lpszHeader = 0; + req->dwHeaderLength = dwHeaderLength; + req->lpOptional = lpOptional; + req->dwOptionalLength = dwOptionalLength; + req->dwContentLength = dwOptionalLength; + req->bEndRequest = TRUE; + + INTERNET_AsyncCall(&workRequest); + /* + * This is from windows. + */ + res = ERROR_IO_PENDING; + } + else + { + res = HTTP_HttpSendRequestW(lpwhr, lpszHeaders, + dwHeaderLength, lpOptional, dwOptionalLength, + dwOptionalLength, TRUE); + } +lend: + if( lpwhr ) + WININET_Release( &lpwhr->hdr ); + + SetLastError(res); + return res == ERROR_SUCCESS; +} + +/*********************************************************************** + * HttpSendRequestA (WININET.@) + * + * Sends the specified request to the HTTP server + * + * RETURNS + * TRUE on success + * FALSE on failure + * + */ +BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders, + DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength) +{ + BOOL result; + LPWSTR szHeaders=NULL; + DWORD nLen=dwHeaderLength; + if(lpszHeaders!=NULL) + { + nLen=MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,NULL,0); + szHeaders=HeapAlloc(GetProcessHeap(),0,nLen*sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,szHeaders,nLen); + } + result=HttpSendRequestW(hHttpRequest, szHeaders, nLen, lpOptional, dwOptionalLength); + HeapFree(GetProcessHeap(),0,szHeaders); + return result; } /*********************************************************************** @@ -3447,9 +4130,9 @@ lend: * Deallocate session handle * */ -static void HTTPSESSION_Destroy(WININETHANDLEHEADER *hdr) +static void HTTPSESSION_Destroy(object_header_t *hdr) { - LPWININETHTTPSESSIONW lpwhs = (LPWININETHTTPSESSIONW) hdr; + http_session_t *lpwhs = (http_session_t*) hdr; TRACE("%p\n", lpwhs); @@ -3462,7 +4145,7 @@ static void HTTPSESSION_Destroy(WININETHANDLEHEADER *hdr) HeapFree(GetProcessHeap(), 0, lpwhs); } -static DWORD HTTPSESSION_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) +static DWORD HTTPSESSION_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) { switch(option) { case INTERNET_OPTION_HANDLE_TYPE: @@ -3479,11 +4162,34 @@ static DWORD HTTPSESSION_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, voi return INET_QueryOption(option, buffer, size, unicode); } -static const HANDLEHEADERVtbl HTTPSESSIONVtbl = { +static DWORD HTTPSESSION_SetOption(object_header_t *hdr, DWORD option, void *buffer, DWORD size) +{ + http_session_t *ses = (http_session_t*)hdr; + + switch(option) { + case INTERNET_OPTION_USERNAME: + { + HeapFree(GetProcessHeap(), 0, ses->lpszUserName); + if (!(ses->lpszUserName = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; + return ERROR_SUCCESS; + } + case INTERNET_OPTION_PASSWORD: + { + HeapFree(GetProcessHeap(), 0, ses->lpszPassword); + if (!(ses->lpszPassword = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; + return ERROR_SUCCESS; + } + default: break; + } + + return ERROR_INTERNET_INVALID_OPTION; +} + +static const object_vtbl_t HTTPSESSIONVtbl = { HTTPSESSION_Destroy, NULL, HTTPSESSION_QueryOption, - NULL, + HTTPSESSION_SetOption, NULL, NULL, NULL, @@ -3502,30 +4208,25 @@ static const HANDLEHEADERVtbl HTTPSESSIONVtbl = { * NULL on failure * */ -HINTERNET HTTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, - INTERNET_PORT nServerPort, LPCWSTR lpszUserName, - LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext, - DWORD dwInternalFlags) +DWORD HTTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName, + INTERNET_PORT nServerPort, LPCWSTR lpszUserName, + LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext, + DWORD dwInternalFlags, HINTERNET *ret) { - LPWININETHTTPSESSIONW lpwhs = NULL; + http_session_t *lpwhs = NULL; HINTERNET handle = NULL; + DWORD res = ERROR_SUCCESS; TRACE("-->\n"); if (!lpszServerName || !lpszServerName[0]) - { - INTERNET_SetLastError(ERROR_INVALID_PARAMETER); - goto lerror; - } + return ERROR_INVALID_PARAMETER; assert( hIC->hdr.htype == WH_HINIT ); - lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPSESSIONW)); - if (NULL == lpwhs) - { - INTERNET_SetLastError(ERROR_OUTOFMEMORY); - goto lerror; - } + lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(http_session_t)); + if (!lpwhs) + return ERROR_OUTOFMEMORY; /* * According to my tests. The name is not resolved until a request is sent @@ -3547,8 +4248,8 @@ HINTERNET HTTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, if (NULL == handle) { ERR("Failed to alloc handle\n"); - INTERNET_SetLastError(ERROR_OUTOFMEMORY); - goto lerror; + res = ERROR_OUTOFMEMORY; + goto lerror; } if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) { @@ -3559,13 +4260,13 @@ HINTERNET HTTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, } if (lpszServerName && lpszServerName[0]) { - lpwhs->lpszServerName = WININET_strdupW(lpszServerName); - lpwhs->lpszHostName = WININET_strdupW(lpszServerName); + lpwhs->lpszServerName = heap_strdupW(lpszServerName); + lpwhs->lpszHostName = heap_strdupW(lpszServerName); } if (lpszUserName && lpszUserName[0]) - lpwhs->lpszUserName = WININET_strdupW(lpszUserName); + lpwhs->lpszUserName = heap_strdupW(lpszUserName); if (lpszPassword && lpszPassword[0]) - lpwhs->lpszPassword = WININET_strdupW(lpszPassword); + lpwhs->lpszPassword = heap_strdupW(lpszPassword); lpwhs->nServerPort = nServerPort; lpwhs->nHostPort = nServerPort; @@ -3587,7 +4288,10 @@ lerror: */ TRACE("%p --> %p (%p)\n", hIC, handle, lpwhs); - return handle; + + if(res == ERROR_SUCCESS) + *ret = handle; + return res; } @@ -3601,48 +4305,58 @@ lerror: * TRUE on success * FALSE on failure */ -static BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr) +static DWORD HTTP_OpenConnection(http_request_t *lpwhr) { - BOOL bSuccess = FALSE; - LPWININETHTTPSESSIONW lpwhs; - LPWININETAPPINFOW hIC = NULL; - char szaddr[32]; + http_session_t *lpwhs; + appinfo_t *hIC = NULL; + char szaddr[INET6_ADDRSTRLEN]; + const void *addr; + DWORD res = ERROR_SUCCESS; TRACE("-->\n"); - if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) + if (lpwhr->hdr.htype != WH_HHTTPREQ) { - INTERNET_SetLastError(ERROR_INVALID_PARAMETER); + res = ERROR_INVALID_PARAMETER; goto lend; } if (NETCON_connected(&lpwhr->netConnection)) - { - bSuccess = TRUE; goto lend; - } - if (!HTTP_ResolveName(lpwhr)) goto lend; + if ((res = HTTP_ResolveName(lpwhr)) != ERROR_SUCCESS) goto lend; lpwhs = lpwhr->lpHttpSession; hIC = lpwhs->lpAppInfo; - inet_ntop(lpwhs->socketAddress.sin_family, &lpwhs->socketAddress.sin_addr, - szaddr, sizeof(szaddr)); + switch (lpwhs->socketAddress.ss_family) + { + case AF_INET: + addr = &((struct sockaddr_in *)&lpwhs->socketAddress)->sin_addr; + break; + case AF_INET6: + addr = &((struct sockaddr_in6 *)&lpwhs->socketAddress)->sin6_addr; + break; + default: + WARN("unsupported family %d\n", lpwhs->socketAddress.ss_family); + return ERROR_INTERNET_NAME_NOT_RESOLVED; + } + inet_ntop(lpwhs->socketAddress.ss_family, addr, szaddr, sizeof(szaddr)); INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER, szaddr, strlen(szaddr)+1); - if (!NETCON_create(&lpwhr->netConnection, lpwhs->socketAddress.sin_family, - SOCK_STREAM, 0)) + res = NETCON_create(&lpwhr->netConnection, lpwhs->socketAddress.ss_family, SOCK_STREAM, 0); + if (res != ERROR_SUCCESS) { - WARN("Socket creation failed: %u\n", INTERNET_GetLastError()); + WARN("Socket creation failed: %u\n", res); goto lend; } - if (!NETCON_connect(&lpwhr->netConnection, (struct sockaddr *)&lpwhs->socketAddress, - sizeof(lpwhs->socketAddress))) + res = NETCON_connect(&lpwhr->netConnection, (struct sockaddr *)&lpwhs->socketAddress, + lpwhs->sa_len); + if(res != ERROR_SUCCESS) goto lend; if (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE) @@ -3653,10 +4367,11 @@ static BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr) * behaviour to be more correct and to not cause any incompatibilities * because using a secure connection through a proxy server is a rare * case that would be hard for anyone to depend on */ - if (hIC->lpszProxy && !HTTP_SecureProxyConnect(lpwhr)) + if (hIC->lpszProxy && (res = HTTP_SecureProxyConnect(lpwhr)) != ERROR_SUCCESS) goto lend; - if (!NETCON_secure_connect(&lpwhr->netConnection, lpwhs->lpszHostName)) + res = NETCON_secure_connect(&lpwhr->netConnection, lpwhs->lpszHostName); + if(res != ERROR_SUCCESS) { WARN("Couldn't connect securely to host\n"); goto lend; @@ -3667,11 +4382,12 @@ static BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr) INTERNET_STATUS_CONNECTED_TO_SERVER, szaddr, strlen(szaddr)+1); - bSuccess = TRUE; - lend: - TRACE("%d <--\n", bSuccess); - return bSuccess; + lpwhr->read_pos = lpwhr->read_size = 0; + lpwhr->read_chunked = FALSE; + + TRACE("%d <--\n", res); + return res; } @@ -3680,7 +4396,7 @@ lend: * * clear out any old response headers */ -static void HTTP_clear_response_headers( LPWININETHTTPREQW lpwhr ) +static void HTTP_clear_response_headers( http_request_t *lpwhr ) { DWORD i; @@ -3707,20 +4423,20 @@ static void HTTP_clear_response_headers( LPWININETHTTPREQW lpwhr ) * TRUE on success * FALSE on error */ -static INT HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear) +static INT HTTP_GetResponseHeaders(http_request_t *lpwhr, BOOL clear) { INT cbreaks = 0; WCHAR buffer[MAX_REPLY_LEN]; DWORD buflen = MAX_REPLY_LEN; BOOL bSuccess = FALSE; INT rc = 0; - static const WCHAR szCrLf[] = {'\r','\n',0}; - static const WCHAR szHundred[] = {'1','0','0',0}; char bufferA[MAX_REPLY_LEN]; - LPWSTR status_code, status_text; + LPWSTR status_code = NULL, status_text = NULL; DWORD cchMaxRawHeaders = 1024; - LPWSTR lpszRawHeaders = HeapAlloc(GetProcessHeap(), 0, (cchMaxRawHeaders+1)*sizeof(WCHAR)); + LPWSTR lpszRawHeaders = NULL; + LPWSTR temp; DWORD cchRawHeaders = 0; + BOOL codeHundred = FALSE; TRACE("-->\n"); @@ -3731,36 +4447,52 @@ static INT HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear) goto lend; do { - /* - * HACK peek at the buffer - */ - buflen = MAX_REPLY_LEN; - NETCON_recv(&lpwhr->netConnection, buffer, buflen, MSG_PEEK, &rc); - + static const WCHAR szHundred[] = {'1','0','0',0}; /* * We should first receive 'HTTP/1.x nnn OK' where nnn is the status code. */ - memset(buffer, 0, MAX_REPLY_LEN); - if (!NETCON_getNextLine(&lpwhr->netConnection, bufferA, &buflen)) + buflen = MAX_REPLY_LEN; + if (!read_line(lpwhr, bufferA, &buflen)) goto lend; + rc += buflen; MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN ); + /* check is this a status code line? */ + if (!strncmpW(buffer, g_szHttp1_0, 4)) + { + /* split the version from the status code */ + status_code = strchrW( buffer, ' ' ); + if( !status_code ) + goto lend; + *status_code++=0; - /* split the version from the status code */ - status_code = strchrW( buffer, ' ' ); - if( !status_code ) + /* split the status code from the status text */ + status_text = strchrW( status_code, ' ' ); + if( !status_text ) + goto lend; + *status_text++=0; + + TRACE("version [%s] status code [%s] status text [%s]\n", + debugstr_w(buffer), debugstr_w(status_code), debugstr_w(status_text) ); + + codeHundred = (!strcmpW(status_code, szHundred)); + } + else if (!codeHundred) + { + WARN("No status line at head of response (%s)\n", debugstr_w(buffer)); + + HeapFree(GetProcessHeap(), 0, lpwhr->lpszVersion); + HeapFree(GetProcessHeap(), 0, lpwhr->lpszStatusText); + + lpwhr->lpszVersion = heap_strdupW(g_szHttp1_0); + lpwhr->lpszStatusText = heap_strdupW(szOK); + + HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders); + lpwhr->lpszRawHeaders = heap_strdupW(szDefaultHeader); + + bSuccess = TRUE; goto lend; - *status_code++=0; - - /* split the status code from the status text */ - status_text = strchrW( status_code, ' ' ); - if( !status_text ) - goto lend; - *status_text++=0; - - TRACE("version [%s] status code [%s] status text [%s]\n", - debugstr_w(buffer), debugstr_w(status_code), debugstr_w(status_text) ); - - } while (!strcmpW(status_code, szHundred)); /* ignore "100 Continue" responses */ + } + } while (codeHundred); /* Add status code */ HTTP_ProcessHeader(lpwhr, szStatus, status_code, @@ -3769,19 +4501,22 @@ static INT HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear) HeapFree(GetProcessHeap(),0,lpwhr->lpszVersion); HeapFree(GetProcessHeap(),0,lpwhr->lpszStatusText); - lpwhr->lpszVersion= WININET_strdupW(buffer); - lpwhr->lpszStatusText = WININET_strdupW(status_text); + lpwhr->lpszVersion = heap_strdupW(buffer); + lpwhr->lpszStatusText = heap_strdupW(status_text); /* Restore the spaces */ *(status_code-1) = ' '; *(status_text-1) = ' '; /* regenerate raw headers */ + lpszRawHeaders = HeapAlloc(GetProcessHeap(), 0, (cchMaxRawHeaders + 1) * sizeof(WCHAR)); + if (!lpszRawHeaders) goto lend; + while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders) - { cchMaxRawHeaders *= 2; - lpszRawHeaders = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR)); - } + temp = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR)); + if (temp == NULL) goto lend; + lpszRawHeaders = temp; memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR)); cchRawHeaders += (buflen-1); memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf)); @@ -3792,33 +4527,35 @@ static INT HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear) do { buflen = MAX_REPLY_LEN; - if (NETCON_getNextLine(&lpwhr->netConnection, bufferA, &buflen)) + if (read_line(lpwhr, bufferA, &buflen)) { LPWSTR * pFieldAndValue; TRACE("got line %s, now interpreting\n", debugstr_a(bufferA)); + + if (!bufferA[0]) break; MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN ); - while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders) - { - cchMaxRawHeaders *= 2; - lpszRawHeaders = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR)); - } - memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR)); - cchRawHeaders += (buflen-1); - memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf)); - cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1; - lpszRawHeaders[cchRawHeaders] = '\0'; - pFieldAndValue = HTTP_InterpretHttpHeader(buffer); - if (!pFieldAndValue) - break; + if (pFieldAndValue) + { + while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders) + cchMaxRawHeaders *= 2; + temp = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR)); + if (temp == NULL) goto lend; + lpszRawHeaders = temp; + memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR)); + cchRawHeaders += (buflen-1); + memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf)); + cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1; + lpszRawHeaders[cchRawHeaders] = '\0'; - HTTP_ProcessHeader(lpwhr, pFieldAndValue[0], pFieldAndValue[1], - HTTP_ADDREQ_FLAG_ADD ); + HTTP_ProcessHeader(lpwhr, pFieldAndValue[0], pFieldAndValue[1], + HTTP_ADDREQ_FLAG_ADD ); - HTTP_FreeTokens(pFieldAndValue); - } + HTTP_FreeTokens(pFieldAndValue); + } + } else { cbreaks++; @@ -3827,6 +4564,19 @@ static INT HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear) } }while(1); + /* make sure the response header is terminated with an empty line. Some apps really + truly care about that empty line being there for some reason. Just add it to the + header. */ + if (cchRawHeaders + strlenW(szCrLf) > cchMaxRawHeaders) + { + cchMaxRawHeaders = cchRawHeaders + strlenW(szCrLf); + temp = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders + 1) * sizeof(WCHAR)); + if (temp == NULL) goto lend; + lpszRawHeaders = temp; + } + + memcpy(&lpszRawHeaders[cchRawHeaders], szCrLf, sizeof(szCrLf)); + HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders); lpwhr->lpszRawHeaders = lpszRawHeaders; TRACE("raw headers: %s\n", debugstr_w(lpszRawHeaders)); @@ -3844,27 +4594,6 @@ lend: } } - -static void strip_spaces(LPWSTR start) -{ - LPWSTR str = start; - LPWSTR end; - - while (*str == ' ' && *str != '\0') - str++; - - if (str != start) - memmove(start, str, sizeof(WCHAR) * (strlenW(str) + 1)); - - end = start + strlenW(start) - 1; - while (end >= start && *end == ' ') - { - *end = '\0'; - end--; - } -} - - /*********************************************************************** * HTTP_InterpretHttpHeader (internal) * @@ -3929,12 +4658,12 @@ static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer) #define COALESCEFLAGS (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON) -static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier) +static DWORD HTTP_ProcessHeader(http_request_t *lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier) { LPHTTPHEADERW lphttpHdr = NULL; - BOOL bSuccess = FALSE; INT index = -1; BOOL request_only = dwModifier & HTTP_ADDHDR_FLAG_REQ; + DWORD res = ERROR_HTTP_INVALID_HEADER; TRACE("--> %s: %s - 0x%08x\n", debugstr_w(field), debugstr_w(value), dwModifier); @@ -3950,9 +4679,7 @@ static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR v if (index >= 0) { if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW) - { - return FALSE; - } + return ERROR_HTTP_INVALID_HEADER; lphttpHdr = &lpwhr->pCustHeaders[index]; } else if (value) @@ -3969,7 +4696,7 @@ static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR v return HTTP_InsertCustomHeader(lpwhr, &hdr); } /* no value to delete */ - else return TRUE; + else return ERROR_SUCCESS; if (dwModifier & HTTP_ADDHDR_FLAG_REQ) lphttpHdr->wFlags |= HDR_ISREQUEST; @@ -3994,7 +4721,7 @@ static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR v return HTTP_InsertCustomHeader(lpwhr, &hdr); } - return TRUE; + return ERROR_SUCCESS; } else if (dwModifier & COALESCEFLAGS) { @@ -4032,16 +4759,16 @@ static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR v memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen*sizeof(WCHAR)); lphttpHdr->lpszValue[len] = '\0'; - bSuccess = TRUE; + res = ERROR_SUCCESS; } else { WARN("HeapReAlloc (%d bytes) failed\n",len+1); - INTERNET_SetLastError(ERROR_OUTOFMEMORY); + res = ERROR_OUTOFMEMORY; } } - TRACE("<-- %d\n",bSuccess); - return bSuccess; + TRACE("<-- %d\n", res); + return res; } @@ -4051,30 +4778,12 @@ static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR v * Called when all content from server has been read by client. * */ -BOOL HTTP_FinishedReading(LPWININETHTTPREQW lpwhr) +static BOOL HTTP_FinishedReading(http_request_t *lpwhr) { - WCHAR szVersion[10]; - WCHAR szConnectionResponse[20]; - DWORD dwBufferSize = sizeof(szVersion); - BOOL keepalive = FALSE; + BOOL keepalive = HTTP_KeepAlive(lpwhr); TRACE("\n"); - /* as per RFC 2068, S8.1.2.1, if the client is HTTP/1.1 then assume that - * the connection is keep-alive by default */ - if (!HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_VERSION, szVersion, - &dwBufferSize, NULL) || - strcmpiW(szVersion, g_szHttp1_1)) - { - keepalive = TRUE; - } - - dwBufferSize = sizeof(szConnectionResponse); - if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_PROXY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) || - HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL)) - { - keepalive = !strcmpiW(szConnectionResponse, szKeepAlive); - } if (!keepalive) { @@ -4093,12 +4802,12 @@ BOOL HTTP_FinishedReading(LPWININETHTTPREQW lpwhr) * Return index of custom header from header array * */ -static INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField, +static INT HTTP_GetCustomHeaderIndex(http_request_t *lpwhr, LPCWSTR lpszField, int requested_index, BOOL request_only) { DWORD index; - TRACE("%s\n", debugstr_w(lpszField)); + TRACE("%s, %d, %d\n", debugstr_w(lpszField), requested_index, request_only); for (index = 0; index < lpwhr->nCustHeaders; index++) { @@ -4130,11 +4839,10 @@ static INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField, * Insert header into array * */ -static BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr) +static DWORD HTTP_InsertCustomHeader(http_request_t *lpwhr, LPHTTPHEADERW lpHdr) { INT count; LPHTTPHEADERW lph = NULL; - BOOL r = FALSE; TRACE("--> %s: %s\n", debugstr_w(lpHdr->lpszField), debugstr_w(lpHdr->lpszValue)); count = lpwhr->nCustHeaders + 1; @@ -4143,22 +4851,17 @@ static BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr else lph = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HTTPHEADERW) * count); - if (NULL != lph) - { - lpwhr->pCustHeaders = lph; - lpwhr->pCustHeaders[count-1].lpszField = WININET_strdupW(lpHdr->lpszField); - lpwhr->pCustHeaders[count-1].lpszValue = WININET_strdupW(lpHdr->lpszValue); - lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags; - lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount; - lpwhr->nCustHeaders++; - r = TRUE; - } - else - { - INTERNET_SetLastError(ERROR_OUTOFMEMORY); - } + if (!lph) + return ERROR_OUTOFMEMORY; - return r; + lpwhr->pCustHeaders = lph; + lpwhr->pCustHeaders[count-1].lpszField = heap_strdupW(lpHdr->lpszField); + lpwhr->pCustHeaders[count-1].lpszValue = heap_strdupW(lpHdr->lpszValue); + lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags; + lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount; + lpwhr->nCustHeaders++; + + return ERROR_SUCCESS; } @@ -4168,7 +4871,7 @@ static BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr * Delete header from array * If this function is called, the indexs may change. */ -static BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, DWORD index) +static BOOL HTTP_DeleteCustomHeader(http_request_t *lpwhr, DWORD index) { if( lpwhr->nCustHeaders <= 0 ) return FALSE; @@ -4193,13 +4896,13 @@ static BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, DWORD index) * Verify the given header is not invalid for the given http request * */ -static BOOL HTTP_VerifyValidHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field) +static BOOL HTTP_VerifyValidHeader(http_request_t *lpwhr, LPCWSTR field) { /* Accept-Encoding is stripped from HTTP/1.0 requests. It is invalid */ if (!strcmpW(lpwhr->lpszVersion, g_szHttp1_0) && !strcmpiW(field, szAccept_Encoding)) - return FALSE; + return ERROR_HTTP_INVALID_HEADER; - return TRUE; + return ERROR_SUCCESS; } /*********************************************************************** diff --git a/reactos/dll/win32/wininet/internet.c b/reactos/dll/win32/wininet/internet.c index bad795ddbd4..45b6aa791f3 100644 --- a/reactos/dll/win32/wininet/internet.c +++ b/reactos/dll/win32/wininet/internet.c @@ -31,6 +31,10 @@ #define MAXHOSTNAME 100 /* from http.c */ +#if defined(__MINGW32__) || defined (_MSC_VER) +#include +#endif + #include #include #include @@ -97,13 +101,27 @@ static CRITICAL_SECTION_DEBUG WININET_cs_debug = }; static CRITICAL_SECTION WININET_cs = { &WININET_cs_debug, -1, 0, 0, 0, 0 }; -static LPWININETHANDLEHEADER *WININET_Handles; +static object_header_t **WININET_Handles; static UINT WININET_dwNextHandle; static UINT WININET_dwMaxHandles; -HINTERNET WININET_AllocHandle( LPWININETHANDLEHEADER info ) +typedef struct { - LPWININETHANDLEHEADER *p; + DWORD dwProxyEnabled; + LPWSTR lpszProxyServer; + LPWSTR lpszProxyBypass; +} proxyinfo_t; + +static const WCHAR szInternetSettings[] = + { 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\', + 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', + 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0 }; +static const WCHAR szProxyServer[] = { 'P','r','o','x','y','S','e','r','v','e','r', 0 }; +static const WCHAR szProxyEnable[] = { 'P','r','o','x','y','E','n','a','b','l','e', 0 }; + +HINTERNET WININET_AllocHandle( object_header_t *info ) +{ + object_header_t **p; UINT handle = 0, num; list_init( &info->children ); @@ -113,7 +131,7 @@ HINTERNET WININET_AllocHandle( LPWININETHANDLEHEADER info ) { num = HANDLE_CHUNK_SIZE; p = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof (UINT)* num); + sizeof (*WININET_Handles)* num); if( !p ) goto end; WININET_Handles = p; @@ -123,7 +141,7 @@ HINTERNET WININET_AllocHandle( LPWININETHANDLEHEADER info ) { num = WININET_dwMaxHandles + HANDLE_CHUNK_SIZE; p = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - WININET_Handles, sizeof (UINT)* num); + WININET_Handles, sizeof (*WININET_Handles)* num); if( !p ) goto end; WININET_Handles = p; @@ -145,16 +163,16 @@ end: return info->hInternet = (HINTERNET) (handle+1); } -LPWININETHANDLEHEADER WININET_AddRef( LPWININETHANDLEHEADER info ) +object_header_t *WININET_AddRef( object_header_t *info ) { ULONG refs = InterlockedIncrement(&info->refs); TRACE("%p -> refcount = %d\n", info, refs ); return info; } -LPWININETHANDLEHEADER WININET_GetObject( HINTERNET hinternet ) +object_header_t *WININET_GetObject( HINTERNET hinternet ) { - LPWININETHANDLEHEADER info = NULL; + object_header_t *info = NULL; UINT handle = (UINT) hinternet; EnterCriticalSection( &WININET_cs ); @@ -170,7 +188,7 @@ LPWININETHANDLEHEADER WININET_GetObject( HINTERNET hinternet ) return info; } -BOOL WININET_Release( LPWININETHANDLEHEADER info ) +BOOL WININET_Release( object_header_t *info ) { ULONG refs = InterlockedDecrement(&info->refs); TRACE( "object %p refcount = %d\n", info, refs ); @@ -182,7 +200,8 @@ BOOL WININET_Release( LPWININETHANDLEHEADER info ) info->vtbl->CloseConnection( info ); } /* Don't send a callback if this is a session handle created with InternetOpenUrl */ - if (info->htype != WH_HHTTPSESSION || !(info->dwInternalFlags & INET_OPENURL)) + if ((info->htype != WH_HHTTPSESSION && info->htype != WH_HFTPSESSION) + || !(info->dwInternalFlags & INET_OPENURL)) { INTERNET_SendCallback(info, info->dwContext, INTERNET_STATUS_HANDLE_CLOSING, &info->hInternet, @@ -200,7 +219,7 @@ BOOL WININET_FreeHandle( HINTERNET hinternet ) { BOOL ret = FALSE; UINT handle = (UINT) hinternet; - LPWININETHANDLEHEADER info = NULL, child, next; + object_header_t *info = NULL, *child, *next; EnterCriticalSection( &WININET_cs ); @@ -224,7 +243,7 @@ BOOL WININET_FreeHandle( HINTERNET hinternet ) if( info ) { /* Free all children as native does */ - LIST_FOR_EACH_ENTRY_SAFE( child, next, &info->children, WININETHANDLEHEADER, entry ) + LIST_FOR_EACH_ENTRY_SAFE( child, next, &info->children, object_header_t, entry ) { TRACE( "freeing child handle %d for parent handle %d\n", (UINT)child->hInternet, handle+1); @@ -285,6 +304,8 @@ BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) case DLL_PROCESS_DETACH: + NETCON_unload(); + URLCacheContainers_DeleteAll(); if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES) @@ -298,6 +319,48 @@ BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) return TRUE; } +/*********************************************************************** + * INTERNET_SaveProxySettings + * + * Stores the proxy settings given by lpwai into the registry + * + * RETURNS + * ERROR_SUCCESS if no error, or error code on fail + */ +static LONG INTERNET_SaveProxySettings( proxyinfo_t *lpwpi ) +{ + HKEY key; + LONG ret; + + if ((ret = RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key ))) + return ret; + + if ((ret = RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE*)&lpwpi->dwProxyEnabled, sizeof(DWORD)))) + { + RegCloseKey( key ); + return ret; + } + + if (lpwpi->lpszProxyServer) + { + if ((ret = RegSetValueExW( key, szProxyServer, 0, REG_SZ, (BYTE*)lpwpi->lpszProxyServer, sizeof(WCHAR) * (lstrlenW(lpwpi->lpszProxyServer) + 1)))) + { + RegCloseKey( key ); + return ret; + } + } + else + { + if ((ret = RegDeleteValueW( key, szProxyServer ))) + { + RegCloseKey( key ); + return ret; + } + } + + RegCloseKey(key); + return ERROR_SUCCESS; +} /*********************************************************************** * InternetInitializeAutoProxyDll (WININET.@) @@ -314,7 +377,7 @@ BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) BOOL WINAPI InternetInitializeAutoProxyDll(DWORD dwReserved) { FIXME("STUB\n"); - INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } @@ -331,37 +394,49 @@ BOOL WINAPI DetectAutoProxyUrl(LPSTR lpszAutoProxyUrl, DWORD dwAutoProxyUrlLength, DWORD dwDetectFlags) { FIXME("STUB\n"); - INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } +static void FreeProxyInfo( proxyinfo_t *lpwpi ) +{ + HeapFree(GetProcessHeap(), 0, lpwpi->lpszProxyServer); + HeapFree(GetProcessHeap(), 0, lpwpi->lpszProxyBypass); +} /*********************************************************************** - * INTERNET_ConfigureProxy + * INTERNET_LoadProxySettings + * + * Loads proxy information from the registry or environment into lpwpi. + * + * The caller should call FreeProxyInfo when done with lpwpi. * * FIXME: * The proxy may be specified in the form 'http=proxy.my.org' * Presumably that means there can be ftp=ftpproxy.my.org too. */ -static BOOL INTERNET_ConfigureProxy( LPWININETAPPINFOW lpwai ) +static LONG INTERNET_LoadProxySettings( proxyinfo_t *lpwpi ) { HKEY key; - DWORD type, len, enabled = 0; + DWORD type, len; LPCSTR envproxy; - static const WCHAR szInternetSettings[] = - { 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\', - 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', - 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0 }; - static const WCHAR szProxyServer[] = { 'P','r','o','x','y','S','e','r','v','e','r', 0 }; - static const WCHAR szProxyEnable[] = { 'P','r','o','x','y','E','n','a','b','l','e', 0 }; + LONG ret; - if (RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key )) return FALSE; + if ((ret = RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key ))) + return ret; - len = sizeof enabled; - if (RegQueryValueExW( key, szProxyEnable, NULL, &type, (BYTE *)&enabled, &len ) || type != REG_DWORD) - RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE *)&enabled, sizeof(REG_DWORD) ); + len = sizeof(DWORD); + if (RegQueryValueExW( key, szProxyEnable, NULL, &type, (BYTE *)&lpwpi->dwProxyEnabled, &len ) || type != REG_DWORD) + { + lpwpi->dwProxyEnabled = 0; + if((ret = RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE *)&lpwpi->dwProxyEnabled, sizeof(DWORD) ))) + { + RegCloseKey( key ); + return ret; + } + } - if (enabled) + if (!(envproxy = getenv( "http_proxy" )) || lpwpi->dwProxyEnabled) { TRACE("Proxy is enabled.\n"); @@ -374,7 +449,7 @@ static BOOL INTERNET_ConfigureProxy( LPWININETAPPINFOW lpwai ) if (!(szProxy = HeapAlloc( GetProcessHeap(), 0, len ))) { RegCloseKey( key ); - return FALSE; + return ERROR_OUTOFMEMORY; } RegQueryValueExW( key, szProxyServer, NULL, &type, (BYTE*)szProxy, &len ); @@ -388,32 +463,56 @@ static BOOL INTERNET_ConfigureProxy( LPWININETAPPINFOW lpwai ) p = strchrW( szProxy, ' ' ); if (p) *p = 0; - lpwai->dwAccessType = INTERNET_OPEN_TYPE_PROXY; - lpwai->lpszProxy = szProxy; + lpwpi->lpszProxyServer = szProxy; - TRACE("http proxy = %s\n", debugstr_w(lpwai->lpszProxy)); + TRACE("http proxy = %s\n", debugstr_w(lpwpi->lpszProxyServer)); } else - ERR("Couldn't read proxy server settings from registry.\n"); + { + TRACE("No proxy server settings in registry.\n"); + lpwpi->lpszProxyServer = NULL; + } } - else if ((envproxy = getenv( "http_proxy" ))) + else if (envproxy) { WCHAR *envproxyW; len = MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, NULL, 0 ); - if (!(envproxyW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR)))) return FALSE; + if (!(envproxyW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR)))) + return ERROR_OUTOFMEMORY; MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, envproxyW, len ); - lpwai->dwAccessType = INTERNET_OPEN_TYPE_PROXY; - lpwai->lpszProxy = envproxyW; + lpwpi->dwProxyEnabled = 1; + lpwpi->lpszProxyServer = envproxyW; - TRACE("http proxy (from environment) = %s\n", debugstr_w(lpwai->lpszProxy)); - enabled = 1; + TRACE("http proxy (from environment) = %s\n", debugstr_w(lpwpi->lpszProxyServer)); } - if (!enabled) TRACE("Proxy is not enabled.\n"); - RegCloseKey( key ); - return (enabled > 0); + + lpwpi->lpszProxyBypass = NULL; + + return ERROR_SUCCESS; +} + +/*********************************************************************** + * INTERNET_ConfigureProxy + */ +static BOOL INTERNET_ConfigureProxy( appinfo_t *lpwai ) +{ + proxyinfo_t wpi; + + if (INTERNET_LoadProxySettings( &wpi )) + return FALSE; + + if (wpi.dwProxyEnabled) + { + lpwai->dwAccessType = INTERNET_OPEN_TYPE_PROXY; + lpwai->lpszProxy = wpi.lpszProxyServer; + return TRUE; + } + + lpwai->dwAccessType = INTERNET_OPEN_TYPE_DIRECT; + return FALSE; } /*********************************************************************** @@ -459,8 +558,8 @@ static void dump_INTERNET_FLAGS(DWORD dwFlags) FE(INTERNET_FLAG_TRANSFER_BINARY) }; #undef FE - int i; - + unsigned int i; + for (i = 0; i < (sizeof(flag) / sizeof(flag[0])); i++) { if (flag[i].val & dwFlags) { TRACE(" %s", flag[i].name); @@ -479,9 +578,9 @@ static void dump_INTERNET_FLAGS(DWORD dwFlags) * Close internet handle * */ -static VOID APPINFO_Destroy(WININETHANDLEHEADER *hdr) +static VOID APPINFO_Destroy(object_header_t *hdr) { - LPWININETAPPINFOW lpwai = (LPWININETAPPINFOW) hdr; + appinfo_t *lpwai = (appinfo_t*)hdr; TRACE("%p\n",lpwai); @@ -493,9 +592,9 @@ static VOID APPINFO_Destroy(WININETHANDLEHEADER *hdr) HeapFree(GetProcessHeap(), 0, lpwai); } -static DWORD APPINFO_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) +static DWORD APPINFO_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) { - LPWININETAPPINFOW ai = (LPWININETAPPINFOW)hdr; + appinfo_t *ai = (appinfo_t*)hdr; switch(option) { case INTERNET_OPTION_HANDLE_TYPE: @@ -516,17 +615,36 @@ static DWORD APPINFO_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b bufsize = *size; if (unicode) { - *size = (strlenW(ai->lpszAgent) + 1) * sizeof(WCHAR); + DWORD len = ai->lpszAgent ? strlenW(ai->lpszAgent) : 0; + + *size = (len + 1) * sizeof(WCHAR); if(!buffer || bufsize < *size) return ERROR_INSUFFICIENT_BUFFER; - strcpyW(buffer, ai->lpszAgent); + if (ai->lpszAgent) + strcpyW(buffer, ai->lpszAgent); + else + *(WCHAR *)buffer = 0; + /* If the buffer is copied, the returned length doesn't include + * the NULL terminator. + */ + *size = len * sizeof(WCHAR); }else { - *size = WideCharToMultiByte(CP_ACP, 0, ai->lpszAgent, -1, NULL, 0, NULL, NULL); + if (ai->lpszAgent) + *size = WideCharToMultiByte(CP_ACP, 0, ai->lpszAgent, -1, NULL, 0, NULL, NULL); + else + *size = 1; if(!buffer || bufsize < *size) return ERROR_INSUFFICIENT_BUFFER; - WideCharToMultiByte(CP_ACP, 0, ai->lpszAgent, -1, buffer, *size, NULL, NULL); + if (ai->lpszAgent) + WideCharToMultiByte(CP_ACP, 0, ai->lpszAgent, -1, buffer, *size, NULL, NULL); + else + *(char *)buffer = 0; + /* If the buffer is copied, the returned length doesn't include + * the NULL terminator. + */ + *size -= 1; } return ERROR_SUCCESS; @@ -543,8 +661,10 @@ static DWORD APPINFO_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b if (ai->lpszProxyBypass) proxyBypassBytesRequired = (lstrlenW(ai->lpszProxyBypass) + 1) * sizeof(WCHAR); if (*size < sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired) - return ERROR_INSUFFICIENT_BUFFER; - + { + *size = sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired; + return ERROR_INSUFFICIENT_BUFFER; + } proxy = (LPWSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOW)); proxy_bypass = (LPWSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired); @@ -574,8 +694,10 @@ static DWORD APPINFO_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b proxyBypassBytesRequired = WideCharToMultiByte(CP_ACP, 0, ai->lpszProxyBypass, -1, NULL, 0, NULL, NULL); if (*size < sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired) + { + *size = sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired; return ERROR_INSUFFICIENT_BUFFER; - + } proxy = (LPSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOA)); proxy_bypass = (LPSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired); @@ -601,7 +723,7 @@ static DWORD APPINFO_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b return INET_QueryOption(option, buffer, size, unicode); } -static const HANDLEHEADERVtbl APPINFOVtbl = { +static const object_vtbl_t APPINFOVtbl = { APPINFO_Destroy, NULL, APPINFO_QueryOption, @@ -627,7 +749,7 @@ static const HANDLEHEADERVtbl APPINFOVtbl = { HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType, LPCWSTR lpszProxy, LPCWSTR lpszProxyBypass, DWORD dwFlags) { - LPWININETAPPINFOW lpwai = NULL; + appinfo_t *lpwai = NULL; HINTERNET handle = NULL; if (TRACE_ON(wininet)) { @@ -658,7 +780,7 @@ HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType, /* Clear any error information */ INTERNET_SetLastError(0); - lpwai = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETAPPINFOW)); + lpwai = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(appinfo_t)); if (NULL == lpwai) { INTERNET_SetLastError(ERROR_OUTOFMEMORY); @@ -681,30 +803,12 @@ HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType, goto lend; } - if (NULL != lpszAgent) - { - lpwai->lpszAgent = HeapAlloc( GetProcessHeap(),0, - (strlenW(lpszAgent)+1)*sizeof(WCHAR)); - if (lpwai->lpszAgent) - lstrcpyW( lpwai->lpszAgent, lpszAgent ); - } + lpwai->lpszAgent = heap_strdupW(lpszAgent); if(dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG) INTERNET_ConfigureProxy( lpwai ); - else if (NULL != lpszProxy) - { - lpwai->lpszProxy = HeapAlloc( GetProcessHeap(), 0, - (strlenW(lpszProxy)+1)*sizeof(WCHAR)); - if (lpwai->lpszProxy) - lstrcpyW( lpwai->lpszProxy, lpszProxy ); - } - - if (NULL != lpszProxyBypass) - { - lpwai->lpszProxyBypass = HeapAlloc( GetProcessHeap(), 0, - (strlenW(lpszProxyBypass)+1)*sizeof(WCHAR)); - if (lpwai->lpszProxyBypass) - lstrcpyW( lpwai->lpszProxyBypass, lpszProxyBypass ); - } + else + lpwai->lpszProxy = heap_strdupW(lpszProxy); + lpwai->lpszProxyBypass = heap_strdupW(lpszProxyBypass); lend: if( lpwai ) @@ -729,33 +833,15 @@ lend: HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType, LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags) { - HINTERNET rc = NULL; - INT len; - WCHAR *szAgent = NULL, *szProxy = NULL, *szBypass = NULL; + WCHAR *szAgent, *szProxy, *szBypass; + HINTERNET rc; TRACE("(%s, 0x%08x, %s, %s, 0x%08x)\n", debugstr_a(lpszAgent), dwAccessType, debugstr_a(lpszProxy), debugstr_a(lpszProxyBypass), dwFlags); - if( lpszAgent ) - { - len = MultiByteToWideChar(CP_ACP, 0, lpszAgent, -1, NULL, 0); - szAgent = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, lpszAgent, -1, szAgent, len); - } - - if( lpszProxy ) - { - len = MultiByteToWideChar(CP_ACP, 0, lpszProxy, -1, NULL, 0); - szProxy = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, lpszProxy, -1, szProxy, len); - } - - if( lpszProxyBypass ) - { - len = MultiByteToWideChar(CP_ACP, 0, lpszProxyBypass, -1, NULL, 0); - szBypass = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, lpszProxyBypass, -1, szBypass, len); - } + szAgent = heap_strdupAtoW(lpszAgent); + szProxy = heap_strdupAtoW(lpszProxy); + szBypass = heap_strdupAtoW(lpszProxyBypass); rc = InternetOpenW(szAgent, dwAccessType, szProxy, szBypass, dwFlags); @@ -779,7 +865,7 @@ HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType, BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError, LPSTR lpszBuffer, LPDWORD lpdwBufferLength) { - LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex); + LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex); TRACE("\n"); @@ -816,7 +902,7 @@ BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError, BOOL WINAPI InternetGetLastResponseInfoW(LPDWORD lpdwError, LPWSTR lpszBuffer, LPDWORD lpdwBufferLength) { - LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex); + LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex); TRACE("\n"); @@ -856,7 +942,7 @@ BOOL WINAPI InternetGetConnectedState(LPDWORD lpdwStatus, DWORD dwReserved) TRACE("(%p, 0x%08x)\n", lpdwStatus, dwReserved); if (lpdwStatus) { - FIXME("always returning LAN connection.\n"); + WARN("always returning LAN connection.\n"); *lpdwStatus = INTERNET_CONNECTION_LAN; } return TRUE; @@ -900,7 +986,7 @@ BOOL WINAPI InternetGetConnectedStateExW(LPDWORD lpdwStatus, LPWSTR lpszConnecti return FALSE; if (lpdwStatus) { - FIXME("always returning LAN connection.\n"); + WARN("always returning LAN connection.\n"); *lpdwStatus = INTERNET_CONNECTION_LAN; } return LoadStringW(WININET_hModule, IDS_LANCONNECTION, lpszConnectionName, dwNameLen); @@ -950,8 +1036,9 @@ HINTERNET WINAPI InternetConnectW(HINTERNET hInternet, LPCWSTR lpszUserName, LPCWSTR lpszPassword, DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext) { - LPWININETAPPINFOW hIC; + appinfo_t *hIC; HINTERNET rc = NULL; + DWORD res = ERROR_SUCCESS; TRACE("(%p, %s, %i, %s, %s, %i, %i, %lx)\n", hInternet, debugstr_w(lpszServerName), nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword), @@ -959,16 +1046,14 @@ HINTERNET WINAPI InternetConnectW(HINTERNET hInternet, if (!lpszServerName) { - INTERNET_SetLastError(ERROR_INVALID_PARAMETER); + SetLastError(ERROR_INVALID_PARAMETER); return NULL; } - /* Clear any error information */ - INTERNET_SetLastError(0); - hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet ); + hIC = (appinfo_t*)WININET_GetObject( hInternet ); if ( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) ) { - INTERNET_SetLastError(ERROR_INVALID_HANDLE); + res = ERROR_INVALID_HANDLE; goto lend; } @@ -977,11 +1062,13 @@ HINTERNET WINAPI InternetConnectW(HINTERNET hInternet, case INTERNET_SERVICE_FTP: rc = FTP_Connect(hIC, lpszServerName, nServerPort, lpszUserName, lpszPassword, dwFlags, dwContext, 0); + if(!rc) + res = INTERNET_GetLastError(); break; case INTERNET_SERVICE_HTTP: - rc = HTTP_Connect(hIC, lpszServerName, nServerPort, - lpszUserName, lpszPassword, dwFlags, dwContext, 0); + res = HTTP_Connect(hIC, lpszServerName, nServerPort, + lpszUserName, lpszPassword, dwFlags, dwContext, 0, &rc); break; case INTERNET_SERVICE_GOPHER: @@ -993,6 +1080,7 @@ lend: WININET_Release( &hIC->hdr ); TRACE("returning %p\n", rc); + SetLastError(res); return rc; } @@ -1013,30 +1101,13 @@ HINTERNET WINAPI InternetConnectA(HINTERNET hInternet, DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext) { HINTERNET rc = NULL; - INT len = 0; - LPWSTR szServerName = NULL; - LPWSTR szUserName = NULL; - LPWSTR szPassword = NULL; - - if (lpszServerName) - { - len = MultiByteToWideChar(CP_ACP, 0, lpszServerName, -1, NULL, 0); - szServerName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, lpszServerName, -1, szServerName, len); - } - if (lpszUserName) - { - len = MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, NULL, 0); - szUserName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, szUserName, len); - } - if (lpszPassword) - { - len = MultiByteToWideChar(CP_ACP, 0, lpszPassword, -1, NULL, 0); - szPassword = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, lpszPassword, -1, szPassword, len); - } + LPWSTR szServerName; + LPWSTR szUserName; + LPWSTR szPassword; + szServerName = heap_strdupAtoW(lpszServerName); + szUserName = heap_strdupAtoW(lpszUserName); + szPassword = heap_strdupAtoW(lpszPassword); rc = InternetConnectW(hInternet, szServerName, nServerPort, szUserName, szPassword, dwService, dwFlags, dwContext); @@ -1081,7 +1152,7 @@ BOOL WINAPI InternetFindNextFileA(HINTERNET hFind, LPVOID lpvFindData) */ BOOL WINAPI InternetFindNextFileW(HINTERNET hFind, LPVOID lpvFindData) { - WININETHANDLEHEADER *hdr; + object_header_t *hdr; DWORD res; TRACE("\n"); @@ -1119,7 +1190,7 @@ BOOL WINAPI InternetFindNextFileW(HINTERNET hFind, LPVOID lpvFindData) */ BOOL WINAPI InternetCloseHandle(HINTERNET hInternet) { - LPWININETHANDLEHEADER lpwh; + object_header_t *lpwh; TRACE("%p\n",hInternet); @@ -1153,11 +1224,14 @@ static void ConvertUrlComponentValue(LPSTR* lppszComponent, LPDWORD dwComponentL DWORD nASCIILength=WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,NULL,0,NULL,NULL); if (*lppszComponent == NULL) { - int nASCIIOffset=WideCharToMultiByte(CP_ACP,0,lpwszStart,lpwszComponent-lpwszStart,NULL,0,NULL,NULL); if (lpwszComponent) - *lppszComponent = (LPSTR)lpszStart+nASCIIOffset; + { + int offset = WideCharToMultiByte(CP_ACP, 0, lpwszStart, lpwszComponent-lpwszStart, NULL, 0, NULL, NULL); + *lppszComponent = (LPSTR)lpszStart + offset; + } else *lppszComponent = NULL; + *dwComponentLen = nASCIILength; } else @@ -1204,7 +1278,7 @@ BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags, InternetCrackUrlW should not include it */ if (dwUrlLength == -1) nLength--; - lpwszUrl=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR)*nLength); + lpwszUrl = HeapAlloc(GetProcessHeap(), 0, nLength * sizeof(WCHAR)); MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,lpwszUrl,nLength); memset(&UCW,0,sizeof(UCW)); @@ -1443,7 +1517,7 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR /* Determine if the URI is absolute. */ while (lpszap - lpszUrl < dwUrlLength) { - if (isalnumW(*lpszap)) + if (isalnumW(*lpszap) || *lpszap == '+' || *lpszap == '.' || *lpszap == '-') { lpszap++; continue; @@ -1465,8 +1539,11 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR lpUC->nPort = INTERNET_INVALID_PORT_NUMBER; /* Parse */ - if (!(lpszParam = memchrW(lpszap, ';', dwUrlLength - (lpszap - lpszUrl)))) + lpszParam = memchrW(lpszap, ';', dwUrlLength - (lpszap - lpszUrl)); + if(!lpszParam) lpszParam = memchrW(lpszap, '?', dwUrlLength - (lpszap - lpszUrl)); + if(!lpszParam) + lpszParam = memchrW(lpszap, '#', dwUrlLength - (lpszap - lpszUrl)); SetUrlComponentValueW(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength, lpszParam, lpszParam ? dwUrlLength-(lpszParam-lpszUrl) : 0); @@ -1564,7 +1641,7 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR } /* If the scheme is "file" and the host is just one letter, it's not a host */ - if(lpUC->nScheme==INTERNET_SCHEME_FILE && (lpszPort-lpszHost)==1) + if(lpUC->nScheme==INTERNET_SCHEME_FILE && lpszPort <= lpszHost+1) { lpszcp=lpszHost; SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, @@ -1617,7 +1694,7 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR * :[//][/path][;][?][#] * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */ - if (lpszcp != 0 && lpszcp - lpszUrl < dwUrlLength && (!lpszParam || lpszcp < lpszParam)) + if (lpszcp != 0 && lpszcp - lpszUrl < dwUrlLength && (!lpszParam || lpszcp <= lpszParam)) { INT len; @@ -1783,7 +1860,7 @@ BOOL WINAPI InternetCanonicalizeUrlW(LPCWSTR lpszUrl, LPWSTR lpszBuffer, /* #################################################### */ static INTERNET_STATUS_CALLBACK set_status_callback( - LPWININETHANDLEHEADER lpwh, INTERNET_STATUS_CALLBACK callback, BOOL unicode) + object_header_t *lpwh, INTERNET_STATUS_CALLBACK callback, BOOL unicode) { INTERNET_STATUS_CALLBACK ret; @@ -1811,10 +1888,10 @@ INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackA( HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB) { INTERNET_STATUS_CALLBACK retVal; - LPWININETHANDLEHEADER lpwh; + object_header_t *lpwh; + + TRACE("%p\n", hInternet); - TRACE("0x%08x\n", (ULONG)hInternet); - if (!(lpwh = WININET_GetObject(hInternet))) return INTERNET_INVALID_STATUS_CALLBACK; @@ -1839,9 +1916,9 @@ INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackW( HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB) { INTERNET_STATUS_CALLBACK retVal; - LPWININETHANDLEHEADER lpwh; + object_header_t *lpwh; - TRACE("0x%08x\n", (ULONG)hInternet); + TRACE("%p\n", hInternet); if (!(lpwh = WININET_GetObject(hInternet))) return INTERNET_INVALID_STATUS_CALLBACK; @@ -1875,8 +1952,8 @@ DWORD WINAPI InternetSetFilePointer(HINTERNET hFile, LONG lDistanceToMove, BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer, DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten) { - LPWININETHANDLEHEADER lpwh; - BOOL retval = FALSE; + object_header_t *lpwh; + BOOL res; TRACE("(%p %p %d %p)\n", hFile, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten); @@ -1888,16 +1965,17 @@ BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer, } if(lpwh->vtbl->WriteFile) { - retval = lpwh->vtbl->WriteFile(lpwh, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten); + res = lpwh->vtbl->WriteFile(lpwh, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten); }else { WARN("No Writefile method.\n"); - SetLastError(ERROR_INVALID_HANDLE); - retval = FALSE; + res = ERROR_INVALID_HANDLE; } WININET_Release( lpwh ); - return retval; + if(res != ERROR_SUCCESS) + SetLastError(res); + return res == ERROR_SUCCESS; } @@ -1914,7 +1992,7 @@ BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer, BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer, DWORD dwNumOfBytesToRead, LPDWORD pdwNumOfBytesRead) { - LPWININETHANDLEHEADER hdr; + object_header_t *hdr; DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; TRACE("%p %p %d %p\n", hFile, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead); @@ -1968,7 +2046,7 @@ BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer, BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext) { - LPWININETHANDLEHEADER hdr; + object_header_t *hdr; DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; TRACE("(%p %p 0x%x 0x%lx)\n", hFile, lpBuffersOut, dwFlags, dwContext); @@ -1994,33 +2072,40 @@ BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffersOu /*********************************************************************** * InternetReadFileExW (WININET.@) - * - * Read data from an open internet file. - * - * PARAMS - * hFile [I] Handle returned by InternetOpenUrl() or HttpOpenRequest(). - * lpBuffersOut [I/O] Buffer. - * dwFlags [I] Flags. - * dwContext [I] Context for callbacks. - * - * RETURNS - * FALSE, last error is set to ERROR_CALL_NOT_IMPLEMENTED - * - * NOTES - * Not implemented in Wine or native either (as of IE6 SP2). - * + * SEE + * InternetReadFileExA() */ BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer, DWORD dwFlags, DWORD_PTR dwContext) { - ERR("(%p, %p, 0x%x, 0x%lx): not implemented in native\n", hFile, lpBuffer, dwFlags, dwContext); + object_header_t *hdr; + DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; - INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + TRACE("(%p %p 0x%x 0x%lx)\n", hFile, lpBuffer, dwFlags, dwContext); + + hdr = WININET_GetObject(hFile); + if (!hdr) { + INTERNET_SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if(hdr->vtbl->ReadFileExW) + res = hdr->vtbl->ReadFileExW(hdr, lpBuffer, dwFlags, dwContext); + + WININET_Release(hdr); + + TRACE("-- %s (%u, bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE", + res, lpBuffer->dwBufferLength); + + if(res != ERROR_SUCCESS) + SetLastError(res); + return res == ERROR_SUCCESS; } DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode) { + static BOOL warn = TRUE; + switch(option) { case INTERNET_OPTION_REQUEST_FLAGS: TRACE("INTERNET_OPTION_REQUEST_FLAGS\n"); @@ -2047,8 +2132,10 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode) return ERROR_SUCCESS; case INTERNET_OPTION_CONNECTED_STATE: - FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n"); - + if (warn) { + FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n"); + warn = FALSE; + } if (*size < sizeof(ULONG)) return ERROR_INSUFFICIENT_BUFFER; @@ -2058,13 +2145,16 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode) return ERROR_SUCCESS; case INTERNET_OPTION_PROXY: { - WININETAPPINFOW ai; + appinfo_t ai; + BOOL ret; TRACE("Getting global proxy info\n"); - memset(&ai, 0, sizeof(WININETAPPINFOW)); + memset(&ai, 0, sizeof(appinfo_t)); INTERNET_ConfigureProxy(&ai); - return APPINFO_QueryOption(&ai.hdr, INTERNET_OPTION_PROXY, buffer, size, unicode); /* FIXME */ + ret = APPINFO_QueryOption(&ai.hdr, INTERNET_OPTION_PROXY, buffer, size, unicode); /* FIXME */ + APPINFO_Destroy(&ai.hdr); + return ret; } case INTERNET_OPTION_MAX_CONNS_PER_SERVER: @@ -2109,23 +2199,48 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode) case INTERNET_OPTION_PER_CONNECTION_OPTION: { INTERNET_PER_CONN_OPTION_LISTW *con = buffer; + INTERNET_PER_CONN_OPTION_LISTA *conA = buffer; DWORD res = ERROR_SUCCESS, i; + proxyinfo_t pi; + LONG ret; + + TRACE("Getting global proxy info\n"); + if((ret = INTERNET_LoadProxySettings(&pi))) + return ret; FIXME("INTERNET_OPTION_PER_CONNECTION_OPTION stub\n"); - if (*size < sizeof(INTERNET_PER_CONN_OPTION_LISTW)) + if (*size < sizeof(INTERNET_PER_CONN_OPTION_LISTW)) { + FreeProxyInfo(&pi); return ERROR_INSUFFICIENT_BUFFER; + } for (i = 0; i < con->dwOptionCount; i++) { INTERNET_PER_CONN_OPTIONW *option = con->pOptions + i; + INTERNET_PER_CONN_OPTIONA *optionA = conA->pOptions + i; switch (option->dwOption) { case INTERNET_PER_CONN_FLAGS: - option->Value.dwValue = PROXY_TYPE_DIRECT; + if(pi.dwProxyEnabled) + option->Value.dwValue = PROXY_TYPE_PROXY; + else + option->Value.dwValue = PROXY_TYPE_DIRECT; break; case INTERNET_PER_CONN_PROXY_SERVER: + if (unicode) + option->Value.pszValue = heap_strdupW(pi.lpszProxyServer); + else + optionA->Value.pszValue = heap_strdupWtoA(pi.lpszProxyServer); + break; + case INTERNET_PER_CONN_PROXY_BYPASS: + if (unicode) + option->Value.pszValue = heap_strdupW(pi.lpszProxyBypass); + else + optionA->Value.pszValue = heap_strdupWtoA(pi.lpszProxyBypass); + break; + case INTERNET_PER_CONN_AUTOCONFIG_URL: case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS: case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL: @@ -2133,8 +2248,7 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode) case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME: case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL: FIXME("Unhandled dwOption %d\n", option->dwOption); - option->Value.dwValue = 0; - res = ERROR_INVALID_PARAMETER; + memset(&option->Value, 0, sizeof(option->Value)); break; default: @@ -2143,9 +2257,14 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode) break; } } + FreeProxyInfo(&pi); return res; } + case INTERNET_OPTION_USER_AGENT: + return ERROR_INTERNET_INCORRECT_HANDLE_TYPE; + case INTERNET_OPTION_POLICY: + return ERROR_INVALID_PARAMETER; } FIXME("Stub for %d\n", option); @@ -2165,7 +2284,7 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode) BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption, LPVOID lpBuffer, LPDWORD lpdwBufferLength) { - LPWININETHANDLEHEADER hdr; + object_header_t *hdr; DWORD res = ERROR_INVALID_HANDLE; TRACE("%p %d %p %p\n", hInternet, dwOption, lpBuffer, lpdwBufferLength); @@ -2198,7 +2317,7 @@ BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption, BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption, LPVOID lpBuffer, LPDWORD lpdwBufferLength) { - LPWININETHANDLEHEADER hdr; + object_header_t *hdr; DWORD res = ERROR_INVALID_HANDLE; TRACE("%p %d %p %p\n", hInternet, dwOption, lpBuffer, lpdwBufferLength); @@ -2232,12 +2351,12 @@ BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption, BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption, LPVOID lpBuffer, DWORD dwBufferLength) { - LPWININETHANDLEHEADER lpwhh; + object_header_t *lpwhh; BOOL ret = TRUE; TRACE("(%p %d %p %d)\n", hInternet, dwOption, lpBuffer, dwBufferLength); - lpwhh = (LPWININETHANDLEHEADER) WININET_GetObject( hInternet ); + lpwhh = (object_header_t*) WININET_GetObject( hInternet ); if(lpwhh && lpwhh->vtbl->SetOption) { DWORD res; @@ -2256,9 +2375,14 @@ BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption, { case INTERNET_OPTION_CALLBACK: { - INTERNET_STATUS_CALLBACK callback = *(INTERNET_STATUS_CALLBACK *)lpBuffer; - ret = (set_status_callback(lpwhh, callback, TRUE) != INTERNET_INVALID_STATUS_CALLBACK); - break; + if (!lpwhh) + { + SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); + return FALSE; + } + WININET_Release(lpwhh); + SetLastError(ERROR_INTERNET_OPTION_NOT_SETTABLE); + return FALSE; } case INTERNET_OPTION_HTTP_VERSION: { @@ -2342,12 +2466,96 @@ BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption, case INTERNET_OPTION_DISABLE_AUTODIAL: FIXME("Option INTERNET_OPTION_DISABLE_AUTODIAL; STUB\n"); break; - case 86: - FIXME("86\n"); + case INTERNET_OPTION_HTTP_DECODING: + FIXME("INTERNET_OPTION_HTTP_DECODING; STUB\n"); + SetLastError(ERROR_INTERNET_INVALID_OPTION); + ret = FALSE; break; + case INTERNET_OPTION_COOKIES_3RD_PARTY: + FIXME("INTERNET_OPTION_COOKIES_3RD_PARTY; STUB\n"); + SetLastError(ERROR_INTERNET_INVALID_OPTION); + ret = FALSE; + break; + case INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY: + FIXME("INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY; STUB\n"); + SetLastError(ERROR_INTERNET_INVALID_OPTION); + ret = FALSE; + break; + case INTERNET_OPTION_CODEPAGE_PATH: + FIXME("INTERNET_OPTION_CODEPAGE_PATH; STUB\n"); + SetLastError(ERROR_INTERNET_INVALID_OPTION); + ret = FALSE; + break; + case INTERNET_OPTION_CODEPAGE_EXTRA: + FIXME("INTERNET_OPTION_CODEPAGE_EXTRA; STUB\n"); + SetLastError(ERROR_INTERNET_INVALID_OPTION); + ret = FALSE; + break; + case INTERNET_OPTION_IDN: + FIXME("INTERNET_OPTION_IDN; STUB\n"); + SetLastError(ERROR_INTERNET_INVALID_OPTION); + ret = FALSE; + break; + case INTERNET_OPTION_POLICY: + SetLastError(ERROR_INVALID_PARAMETER); + ret = FALSE; + break; + case INTERNET_OPTION_PER_CONNECTION_OPTION: { + INTERNET_PER_CONN_OPTION_LISTW *con = lpBuffer; + LONG res; + int i; + proxyinfo_t pi; + + INTERNET_LoadProxySettings(&pi); + + for (i = 0; i < con->dwOptionCount; i++) { + INTERNET_PER_CONN_OPTIONW *option = con->pOptions + i; + + switch (option->dwOption) { + case INTERNET_PER_CONN_PROXY_SERVER: + HeapFree(GetProcessHeap(), 0, pi.lpszProxyServer); + pi.lpszProxyServer = heap_strdupW(option->Value.pszValue); + break; + + case INTERNET_PER_CONN_FLAGS: + if(option->Value.dwValue & PROXY_TYPE_PROXY) + pi.dwProxyEnabled = 1; + else + { + if(option->Value.dwValue != PROXY_TYPE_DIRECT) + FIXME("Unhandled flags: 0x%x\n", option->Value.dwValue); + pi.dwProxyEnabled = 0; + } + break; + + case INTERNET_PER_CONN_AUTOCONFIG_URL: + case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS: + case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL: + case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS: + case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME: + case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL: + case INTERNET_PER_CONN_PROXY_BYPASS: + FIXME("Unhandled dwOption %d\n", option->dwOption); + break; + + default: + FIXME("Unknown dwOption %d\n", option->dwOption); + SetLastError(ERROR_INVALID_PARAMETER); + break; + } + } + + if ((res = INTERNET_SaveProxySettings(&pi))) + SetLastError(res); + + FreeProxyInfo(&pi); + + ret = (res == ERROR_SUCCESS); + break; + } default: FIXME("Option %d STUB\n",dwOption); - INTERNET_SetLastError(ERROR_INTERNET_INVALID_OPTION); + SetLastError(ERROR_INTERNET_INVALID_OPTION); ret = FALSE; break; } @@ -2380,13 +2588,16 @@ BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption, { case INTERNET_OPTION_CALLBACK: { - LPWININETHANDLEHEADER lpwh; - INTERNET_STATUS_CALLBACK callback = *(INTERNET_STATUS_CALLBACK *)lpBuffer; + object_header_t *lpwh; - if (!(lpwh = WININET_GetObject(hInternet))) return FALSE; - r = (set_status_callback(lpwh, callback, FALSE) != INTERNET_INVALID_STATUS_CALLBACK); + if (!(lpwh = WININET_GetObject(hInternet))) + { + INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); + return FALSE; + } WININET_Release(lpwh); - return r; + INTERNET_SetLastError(ERROR_INTERNET_OPTION_NOT_SETTABLE); + return FALSE; } case INTERNET_OPTION_PROXY: { @@ -2418,6 +2629,63 @@ BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption, MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength, wbuffer, wlen ); break; + case INTERNET_OPTION_PER_CONNECTION_OPTION: { + int i; + INTERNET_PER_CONN_OPTION_LISTW *listW; + INTERNET_PER_CONN_OPTION_LISTA *listA = lpBuffer; + wlen = sizeof(INTERNET_PER_CONN_OPTION_LISTW); + wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen ); + listW = wbuffer; + + listW->dwSize = sizeof(INTERNET_PER_CONN_OPTION_LISTW); + if (listA->pszConnection) + { + wlen = MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, NULL, 0 ); + listW->pszConnection = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, listW->pszConnection, wlen ); + } + else + listW->pszConnection = NULL; + listW->dwOptionCount = listA->dwOptionCount; + listW->dwOptionError = listA->dwOptionError; + listW->pOptions = HeapAlloc( GetProcessHeap(), 0, sizeof(INTERNET_PER_CONN_OPTIONW) * listA->dwOptionCount ); + + for (i = 0; i < listA->dwOptionCount; ++i) { + INTERNET_PER_CONN_OPTIONA *optA = listA->pOptions + i; + INTERNET_PER_CONN_OPTIONW *optW = listW->pOptions + i; + + optW->dwOption = optA->dwOption; + + switch (optA->dwOption) { + case INTERNET_PER_CONN_AUTOCONFIG_URL: + case INTERNET_PER_CONN_PROXY_BYPASS: + case INTERNET_PER_CONN_PROXY_SERVER: + case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL: + case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL: + if (optA->Value.pszValue) + { + wlen = MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, NULL, 0 ); + optW->Value.pszValue = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, optW->Value.pszValue, wlen ); + } + else + optW->Value.pszValue = NULL; + break; + case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS: + case INTERNET_PER_CONN_FLAGS: + case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS: + optW->Value.dwValue = optA->Value.dwValue; + break; + case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME: + optW->Value.ftValue = optA->Value.ftValue; + default: + WARN("Unknown PER_CONN dwOption: %d, guessing at conversion to Wide\n", optA->dwOption); + optW->Value.dwValue = optA->Value.dwValue; + break; + } + } + } + break; default: wbuffer = lpBuffer; wlen = dwBufferLength; @@ -2426,7 +2694,29 @@ BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption, r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen); if( lpBuffer != wbuffer ) + { + if (dwOption == INTERNET_OPTION_PER_CONNECTION_OPTION) + { + INTERNET_PER_CONN_OPTION_LISTW *list = wbuffer; + int i; + for (i = 0; i < list->dwOptionCount; ++i) { + INTERNET_PER_CONN_OPTIONW *opt = list->pOptions + i; + switch (opt->dwOption) { + case INTERNET_PER_CONN_AUTOCONFIG_URL: + case INTERNET_PER_CONN_PROXY_BYPASS: + case INTERNET_PER_CONN_PROXY_SERVER: + case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL: + case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL: + HeapFree( GetProcessHeap(), 0, opt->Value.pszValue ); + break; + default: + break; + } + } + HeapFree( GetProcessHeap(), 0, list->pOptions ); + } HeapFree( GetProcessHeap(), 0, wbuffer ); + } return r; } @@ -2451,7 +2741,7 @@ BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption, FIXME("Flags %08x ignored\n", dwFlags); if( dwFlags & ~ISO_VALID_FLAGS ) { - INTERNET_SetLastError( ERROR_INVALID_PARAMETER ); + SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength ); @@ -2475,6 +2765,18 @@ BOOL WINAPI InternetTimeFromSystemTimeA( const SYSTEMTIME* time, DWORD format, L TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size ); + if (!time || !string || format != INTERNET_RFC1123_FORMAT) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (size < INTERNET_RFC1123_BUFSIZE * sizeof(*string)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + ret = InternetTimeFromSystemTimeW( time, format, stringW, sizeof(stringW) ); if (ret) WideCharToMultiByte( CP_ACP, 0, stringW, -1, string, size, NULL, NULL ); @@ -2492,10 +2794,17 @@ BOOL WINAPI InternetTimeFromSystemTimeW( const SYSTEMTIME* time, DWORD format, L TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size ); - if (!time || !string) return FALSE; - - if (format != INTERNET_RFC1123_FORMAT || size < INTERNET_RFC1123_BUFSIZE * sizeof(WCHAR)) + if (!time || !string || format != INTERNET_RFC1123_FORMAT) + { + SetLastError(ERROR_INVALID_PARAMETER); return FALSE; + } + + if (size < INTERNET_RFC1123_BUFSIZE * sizeof(*string)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } sprintfW( string, date, WININET_wkday[time->wDayOfWeek], @@ -2516,16 +2825,12 @@ BOOL WINAPI InternetTimeToSystemTimeA( LPCSTR string, SYSTEMTIME* time, DWORD re { BOOL ret = FALSE; WCHAR *stringW; - int len; TRACE( "%s %p 0x%08x\n", debugstr_a(string), time, reserved ); - len = MultiByteToWideChar( CP_ACP, 0, string, -1, NULL, 0 ); - stringW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - + stringW = heap_strdupAtoW(string); if (stringW) { - MultiByteToWideChar( CP_ACP, 0, string, -1, stringW, len ); ret = InternetTimeToSystemTimeW( stringW, time, reserved ); HeapFree( GetProcessHeap(), 0, stringW ); } @@ -2674,15 +2979,16 @@ BOOL WINAPI InternetCheckConnectionW( LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwRe if (dwFlags & FLAG_ICC_FORCE_CONNECTION) { - struct sockaddr_in sin; + struct sockaddr_storage saddr; + socklen_t sa_len = sizeof(saddr); int fd; - if (!GetAddress(hostW, port, &sin)) + if (!GetAddress(hostW, port, (struct sockaddr *)&saddr, &sa_len)) goto End; - fd = socket(sin.sin_family, SOCK_STREAM, 0); + fd = socket(saddr.ss_family, SOCK_STREAM, 0); if (fd != -1) { - if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) == 0) + if (connect(fd, (struct sockaddr *)&saddr, sa_len) == 0) rc = TRUE; close(fd); } @@ -2731,17 +3037,18 @@ End: */ BOOL WINAPI InternetCheckConnectionA(LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved) { - WCHAR *szUrl; - INT len; + WCHAR *url = NULL; BOOL rc; - len = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0); - if (!(szUrl = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)))) - return FALSE; - MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, szUrl, len); - rc = InternetCheckConnectionW(szUrl, dwFlags, dwReserved); - HeapFree(GetProcessHeap(), 0, szUrl); - + if(lpszUrl) { + url = heap_strdupAtoW(lpszUrl); + if(!url) + return FALSE; + } + + rc = InternetCheckConnectionW(url, dwFlags, dwReserved); + + HeapFree(GetProcessHeap(), 0, url); return rc; } @@ -2754,13 +3061,14 @@ BOOL WINAPI InternetCheckConnectionA(LPCSTR lpszUrl, DWORD dwFlags, DWORD dwRese * RETURNS * handle of connection or NULL on failure */ -static HINTERNET INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUrl, +static HINTERNET INTERNET_InternetOpenUrlW(appinfo_t *hIC, LPCWSTR lpszUrl, LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext) { URL_COMPONENTSW urlComponents; WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024]; WCHAR password[1024], path[2048], extra[1024]; HINTERNET client = NULL, client1 = NULL; + DWORD res; TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders), dwHeadersLength, dwFlags, dwContext); @@ -2805,11 +3113,15 @@ static HINTERNET INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUr else urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT; } + if (urlComponents.nScheme == INTERNET_SCHEME_HTTPS) dwFlags |= INTERNET_FLAG_SECURE; + /* FIXME: should use pointers, not handles, as handles are not thread-safe */ - client = HTTP_Connect(hIC, hostName, urlComponents.nPort, - userName, password, dwFlags, dwContext, INET_OPENURL); - if(client == NULL) + res = HTTP_Connect(hIC, hostName, urlComponents.nPort, + userName, password, dwFlags, dwContext, INET_OPENURL, &client); + if(res != ERROR_SUCCESS) { + INTERNET_SetLastError(res); break; + } if (urlComponents.dwExtraInfoLength) { WCHAR *path_extra; @@ -2844,7 +3156,7 @@ static HINTERNET INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUr /* gopher doesn't seem to be implemented in wine, but it's supposed * to be supported by InternetOpenUrlA. */ default: - INTERNET_SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME); + SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME); break; } @@ -2864,7 +3176,7 @@ static HINTERNET INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUr static void AsyncInternetOpenUrlProc(WORKREQUEST *workRequest) { struct WORKREQ_INTERNETOPENURLW const *req = &workRequest->u.InternetOpenUrlW; - LPWININETAPPINFOW hIC = (LPWININETAPPINFOW) workRequest->hdr; + appinfo_t *hIC = (appinfo_t*) workRequest->hdr; TRACE("%p\n", hIC); @@ -2878,7 +3190,7 @@ HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl, LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext) { HINTERNET ret = NULL; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; if (TRACE_ON(wininet)) { TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hInternet, debugstr_w(lpszUrl), debugstr_w(lpszHeaders), @@ -2889,13 +3201,13 @@ HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl, if (!lpszUrl) { - INTERNET_SetLastError(ERROR_INVALID_PARAMETER); + SetLastError(ERROR_INVALID_PARAMETER); goto lend; } - hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet ); + hIC = (appinfo_t*)WININET_GetObject( hInternet ); if (NULL == hIC || hIC->hdr.htype != WH_HINIT) { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); + SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); goto lend; } @@ -2905,12 +3217,9 @@ HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl, workRequest.asyncproc = AsyncInternetOpenUrlProc; workRequest.hdr = WININET_AddRef( &hIC->hdr ); - req = &workRequest.u.InternetOpenUrlW; - req->lpszUrl = WININET_strdupW(lpszUrl); - if (lpszHeaders) - req->lpszHeaders = WININET_strdupW(lpszHeaders); - else - req->lpszHeaders = 0; + req = &workRequest.u.InternetOpenUrlW; + req->lpszUrl = heap_strdupW(lpszUrl); + req->lpszHeaders = heap_strdupW(lpszHeaders); req->dwHeadersLength = dwHeadersLength; req->dwFlags = dwFlags; req->dwContext = dwContext; @@ -2919,7 +3228,7 @@ HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl, /* * This is from windows. */ - INTERNET_SetLastError(ERROR_IO_PENDING); + SetLastError(ERROR_IO_PENDING); } else { ret = INTERNET_InternetOpenUrlW(hIC, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext); } @@ -2944,20 +3253,16 @@ HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl, LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext) { HINTERNET rc = NULL; - - INT lenUrl; - INT lenHeaders = 0; + DWORD lenHeaders = 0; LPWSTR szUrl = NULL; LPWSTR szHeaders = NULL; TRACE("\n"); if(lpszUrl) { - lenUrl = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0 ); - szUrl = HeapAlloc(GetProcessHeap(), 0, lenUrl*sizeof(WCHAR)); + szUrl = heap_strdupAtoW(lpszUrl); if(!szUrl) return NULL; - MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, szUrl, lenUrl); } if(lpszHeaders) { @@ -3010,7 +3315,7 @@ static LPWITHREADERROR INTERNET_AllocThreadError(void) */ void INTERNET_SetLastError(DWORD dwError) { - LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex); + LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex); if (!lpwite) lpwite = INTERNET_AllocThreadError(); @@ -3031,7 +3336,7 @@ void INTERNET_SetLastError(DWORD dwError) */ DWORD INTERNET_GetLastError(void) { - LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex); + LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex); if (!lpwite) return 0; /* TlsGetValue clears last error, so set it again here */ SetLastError(lpwite->dwError); @@ -3058,8 +3363,13 @@ static DWORD CALLBACK INTERNET_WorkerThreadFunc(LPVOID lpvParam) HeapFree(GetProcessHeap(), 0, lpRequest); workRequest.asyncproc(&workRequest); - WININET_Release( workRequest.hdr ); + + if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES) + { + HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex)); + TlsSetValue(g_dwTlsErrIndex, NULL); + } return TRUE; } @@ -3072,7 +3382,7 @@ static DWORD CALLBACK INTERNET_WorkerThreadFunc(LPVOID lpvParam) * RETURNS * */ -BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest) +DWORD INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest) { BOOL bSuccess; LPWORKREQUEST lpNewRequest; @@ -3081,7 +3391,7 @@ BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest) lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST)); if (!lpNewRequest) - return FALSE; + return ERROR_OUTOFMEMORY; *lpNewRequest = *lpWorkRequest; @@ -3089,10 +3399,10 @@ BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest) if (!bSuccess) { HeapFree(GetProcessHeap(), 0, lpNewRequest); - INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED); + return ERROR_INTERNET_ASYNC_THREAD_FAILED; } - return bSuccess; + return ERROR_SUCCESS; } @@ -3104,7 +3414,7 @@ BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest) */ LPSTR INTERNET_GetResponseBuffer(void) { - LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex); + LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex); if (!lpwite) lpwite = INTERNET_AllocThreadError(); TRACE("\n"); @@ -3193,14 +3503,14 @@ BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile, LPDWORD lpdwNumberOfBytesAvailble, DWORD dwFlags, DWORD_PTR dwContext) { - WININETHANDLEHEADER *hdr; + object_header_t *hdr; DWORD res; TRACE("(%p %p %x %lx)\n", hFile, lpdwNumberOfBytesAvailble, dwFlags, dwContext); hdr = WININET_GetObject( hFile ); if (!hdr) { - INTERNET_SetLastError(ERROR_INVALID_HANDLE); + SetLastError(ERROR_INVALID_HANDLE); return FALSE; } @@ -3451,6 +3761,9 @@ static BOOL calc_url_length(LPURL_COMPONENTSW lpUrlComponents, if (lpUrlComponents->lpszUrlPath) *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath); + if (lpUrlComponents->lpszExtraInfo) + *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, ExtraInfo); + return TRUE; } @@ -3535,7 +3848,7 @@ BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags, if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength) { - INTERNET_SetLastError(ERROR_INVALID_PARAMETER); + SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } @@ -3699,7 +4012,6 @@ BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags, } } - if (lpUrlComponents->lpszUrlPath) { dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath); @@ -3707,6 +4019,13 @@ BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags, lpszUrl += dwLen; } + if (lpUrlComponents->lpszExtraInfo) + { + dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, ExtraInfo); + memcpy(lpszUrl, lpUrlComponents->lpszExtraInfo, dwLen * sizeof(WCHAR)); + lpszUrl += dwLen; + } + *lpszUrl = '\0'; return TRUE; @@ -3732,6 +4051,31 @@ DWORD WINAPI InternetConfirmZoneCrossingW( HWND hWnd, LPWSTR szUrlPrev, LPWSTR s return ERROR_SUCCESS; } +static DWORD zone_preference = 3; + +/*********************************************************************** + * PrivacySetZonePreferenceW (WININET.@) + */ +DWORD WINAPI PrivacySetZonePreferenceW( DWORD zone, DWORD type, DWORD template, LPCWSTR preference ) +{ + FIXME( "%x %x %x %s: stub\n", zone, type, template, debugstr_w(preference) ); + + zone_preference = template; + return 0; +} + +/*********************************************************************** + * PrivacyGetZonePreferenceW (WININET.@) + */ +DWORD WINAPI PrivacyGetZonePreferenceW( DWORD zone, DWORD type, LPDWORD template, + LPWSTR preference, LPDWORD length ) +{ + FIXME( "%x %x %p %p %p: stub\n", zone, type, template, preference, length ); + + if (template) *template = zone_preference; + return 0; +} + DWORD WINAPI InternetDialA( HWND hwndParent, LPSTR lpszConnectoid, DWORD dwFlags, DWORD_PTR* lpdwConnection, DWORD dwReserved ) { diff --git a/reactos/dll/win32/wininet/internet.h b/reactos/dll/win32/wininet/internet.h index 0dcf5a22ce6..e45176bb2c0 100644 --- a/reactos/dll/win32/wininet/internet.h +++ b/reactos/dll/win32/wininet/internet.h @@ -42,12 +42,7 @@ # include #endif -#if defined(__MINGW32__) || defined (_MSC_VER) -#include "ws2tcpip.h" -#ifndef MSG_WAITALL -#define MSG_WAITALL 0 -#endif -#else +#if !defined(__MINGW32__) && !defined(_MSC_VER) #define closesocket close #define ioctlsocket ioctl #endif /* __MINGW32__ */ @@ -62,33 +57,51 @@ typedef struct BOOL useSSL; int socketFD; void *ssl_s; - char *peek_msg; - char *peek_msg_mem; - size_t peek_len; } WININET_NETCONNECTION; -static inline LPWSTR WININET_strdupW( LPCWSTR str ) +static inline LPWSTR heap_strdupW(LPCWSTR str) { - LPWSTR ret = HeapAlloc( GetProcessHeap(), 0, (strlenW(str) + 1)*sizeof(WCHAR) ); - if (ret) strcpyW( ret, str ); + LPWSTR ret = NULL; + + if(str) { + DWORD size; + + size = (strlenW(str)+1)*sizeof(WCHAR); + ret = HeapAlloc(GetProcessHeap(), 0, size); + if(ret) + memcpy(ret, str, size); + } + return ret; } -static inline LPWSTR WININET_strdup_AtoW( LPCSTR str ) +static inline WCHAR *heap_strdupAtoW(const char *str) { - int len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0); - LPWSTR ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - if (ret) - MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len); + LPWSTR ret = NULL; + + if(str) { + DWORD len; + + len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); + ret = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); + if(ret) + MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len); + } + return ret; } -static inline LPSTR WININET_strdup_WtoA( LPCWSTR str ) +static inline char *heap_strdupWtoA(LPCWSTR str) { - int len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL); - LPSTR ret = HeapAlloc( GetProcessHeap(), 0, len ); - if (ret) - WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL); + char *ret = NULL; + + if(str) { + DWORD size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL); + ret = HeapAlloc(GetProcessHeap(), 0, size); + if(ret) + WideCharToMultiByte(CP_ACP, 0, str, -1, ret, size, NULL, NULL); + } + return ret; } @@ -124,24 +137,25 @@ typedef enum #define INET_OPENURL 0x0001 #define INET_CALLBACKW 0x0002 -typedef struct _WININETHANDLEHEADER WININETHANDLEHEADER, *LPWININETHANDLEHEADER; +typedef struct _object_header_t object_header_t; typedef struct { - void (*Destroy)(WININETHANDLEHEADER*); - void (*CloseConnection)(WININETHANDLEHEADER*); - DWORD (*QueryOption)(WININETHANDLEHEADER*,DWORD,void*,DWORD*,BOOL); - DWORD (*SetOption)(WININETHANDLEHEADER*,DWORD,void*,DWORD); - DWORD (*ReadFile)(WININETHANDLEHEADER*,void*,DWORD,DWORD*); - DWORD (*ReadFileExA)(WININETHANDLEHEADER*,INTERNET_BUFFERSA*,DWORD,DWORD_PTR); - BOOL (*WriteFile)(WININETHANDLEHEADER*,const void*,DWORD,DWORD*); - DWORD (*QueryDataAvailable)(WININETHANDLEHEADER*,DWORD*,DWORD,DWORD_PTR); - DWORD (*FindNextFileW)(WININETHANDLEHEADER*,void*); -} HANDLEHEADERVtbl; + void (*Destroy)(object_header_t*); + void (*CloseConnection)(object_header_t*); + DWORD (*QueryOption)(object_header_t*,DWORD,void*,DWORD*,BOOL); + DWORD (*SetOption)(object_header_t*,DWORD,void*,DWORD); + DWORD (*ReadFile)(object_header_t*,void*,DWORD,DWORD*); + DWORD (*ReadFileExA)(object_header_t*,INTERNET_BUFFERSA*,DWORD,DWORD_PTR); + DWORD (*ReadFileExW)(object_header_t*,INTERNET_BUFFERSW*,DWORD,DWORD_PTR); + DWORD (*WriteFile)(object_header_t*,const void*,DWORD,DWORD*); + DWORD (*QueryDataAvailable)(object_header_t*,DWORD*,DWORD,DWORD_PTR); + DWORD (*FindNextFileW)(object_header_t*,void*); +} object_vtbl_t; -struct _WININETHANDLEHEADER +struct _object_header_t { WH_TYPE htype; - const HANDLEHEADERVtbl *vtbl; + const object_vtbl_t *vtbl; HINTERNET hInternet; DWORD dwFlags; DWORD_PTR dwContext; @@ -156,28 +170,29 @@ struct _WININETHANDLEHEADER typedef struct { - WININETHANDLEHEADER hdr; + object_header_t hdr; LPWSTR lpszAgent; LPWSTR lpszProxy; LPWSTR lpszProxyBypass; LPWSTR lpszProxyUsername; LPWSTR lpszProxyPassword; DWORD dwAccessType; -} WININETAPPINFOW, *LPWININETAPPINFOW; +} appinfo_t; typedef struct { - WININETHANDLEHEADER hdr; - WININETAPPINFOW *lpAppInfo; + object_header_t hdr; + appinfo_t *lpAppInfo; LPWSTR lpszHostName; /* the final destination of the request */ LPWSTR lpszServerName; /* the name of the server we directly connect to */ LPWSTR lpszUserName; LPWSTR lpszPassword; INTERNET_PORT nHostPort; /* the final destination port of the request */ INTERNET_PORT nServerPort; /* the port of the server we directly connect to */ - struct sockaddr_in socketAddress; -} WININETHTTPSESSIONW, *LPWININETHTTPSESSIONW; + struct sockaddr_storage socketAddress; + socklen_t sa_len; +} http_session_t; #define HDR_ISREQUEST 0x0001 #define HDR_COMMADELIMITED 0x0002 @@ -194,25 +209,38 @@ typedef struct struct HttpAuthInfo; +typedef struct gzip_stream_t gzip_stream_t; + typedef struct { - WININETHANDLEHEADER hdr; - WININETHTTPSESSIONW *lpHttpSession; + object_header_t hdr; + http_session_t *lpHttpSession; LPWSTR lpszPath; LPWSTR lpszVerb; LPWSTR lpszRawHeaders; WININET_NETCONNECTION netConnection; LPWSTR lpszVersion; LPWSTR lpszStatusText; - DWORD dwContentLength; /* total number of bytes to be read */ - DWORD dwContentRead; /* bytes of the content read so far */ + DWORD dwBytesToWrite; + DWORD dwBytesWritten; HTTPHEADERW *pCustHeaders; DWORD nCustHeaders; HANDLE hCacheFile; LPWSTR lpszCacheFile; struct HttpAuthInfo *pAuthInfo; struct HttpAuthInfo *pProxyAuthInfo; -} WININETHTTPREQW, *LPWININETHTTPREQW; + + CRITICAL_SECTION read_section; /* section to protect the following fields */ + DWORD dwContentLength; /* total number of bytes to be read */ + DWORD dwContentRead; /* bytes of the content read so far */ + BOOL read_chunked; /* are we reading in chunked mode? */ + DWORD read_pos; /* current read position in read_buf */ + DWORD read_size; /* valid data size in read_buf */ + BYTE read_buf[4096]; /* buffer for already read but not returned data */ + + BOOL decoding; + gzip_stream_t *gzip_stream; +} http_request_t; @@ -297,6 +325,12 @@ struct WORKREQ_HTTPSENDREQUESTW BOOL bEndRequest; }; +struct WORKREQ_HTTPENDREQUESTW +{ + DWORD dwFlags; + DWORD_PTR dwContext; +}; + struct WORKREQ_SENDCALLBACK { DWORD_PTR dwContext; @@ -320,10 +354,15 @@ struct WORKREQ_INTERNETREADFILEEXA LPINTERNET_BUFFERSA lpBuffersOut; }; +struct WORKREQ_INTERNETREADFILEEXW +{ + LPINTERNET_BUFFERSW lpBuffersOut; +}; + typedef struct WORKREQ { void (*asyncproc)(struct WORKREQ*); - WININETHANDLEHEADER *hdr; + object_header_t *hdr; union { struct WORKREQ_FTPPUTFILEW FtpPutFileW; @@ -338,77 +377,69 @@ typedef struct WORKREQ struct WORKREQ_FTPRENAMEFILEW FtpRenameFileW; struct WORKREQ_FTPFINDNEXTW FtpFindNextW; struct WORKREQ_HTTPSENDREQUESTW HttpSendRequestW; + struct WORKREQ_HTTPENDREQUESTW HttpEndRequestW; struct WORKREQ_SENDCALLBACK SendCallback; - struct WORKREQ_INTERNETOPENURLW InternetOpenUrlW; + struct WORKREQ_INTERNETOPENURLW InternetOpenUrlW; struct WORKREQ_INTERNETREADFILEEXA InternetReadFileExA; + struct WORKREQ_INTERNETREADFILEEXW InternetReadFileExW; } u; } WORKREQUEST, *LPWORKREQUEST; -HINTERNET WININET_AllocHandle( LPWININETHANDLEHEADER info ); -LPWININETHANDLEHEADER WININET_GetObject( HINTERNET hinternet ); -LPWININETHANDLEHEADER WININET_AddRef( LPWININETHANDLEHEADER info ); -BOOL WININET_Release( LPWININETHANDLEHEADER info ); +HINTERNET WININET_AllocHandle( object_header_t *info ); +object_header_t *WININET_GetObject( HINTERNET hinternet ); +object_header_t *WININET_AddRef( object_header_t *info ); +BOOL WININET_Release( object_header_t *info ); BOOL WININET_FreeHandle( HINTERNET hinternet ); DWORD INET_QueryOption(DWORD,void*,DWORD*,BOOL); time_t ConvertTimeString(LPCWSTR asctime); -HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, +HINTERNET FTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName, INTERNET_PORT nServerPort, LPCWSTR lpszUserName, LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext, DWORD dwInternalFlags); -HINTERNET HTTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, - INTERNET_PORT nServerPort, LPCWSTR lpszUserName, - LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext, - DWORD dwInternalFlags); +DWORD HTTP_Connect(appinfo_t*,LPCWSTR, + INTERNET_PORT nServerPort, LPCWSTR lpszUserName, + LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext, + DWORD dwInternalFlags, HINTERNET*); BOOL GetAddress(LPCWSTR lpszServerName, INTERNET_PORT nServerPort, - struct sockaddr_in *psa); + struct sockaddr *psa, socklen_t *sa_len); void INTERNET_SetLastError(DWORD dwError); DWORD INTERNET_GetLastError(void); -BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest); +DWORD INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest); LPSTR INTERNET_GetResponseBuffer(void); LPSTR INTERNET_GetNextLine(INT nSocket, LPDWORD dwLen); -BOOLAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, - DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength, - DWORD dwContentLength, BOOL bEndRequest); -INTERNETAPI HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs, - LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion, - LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes, - DWORD dwFlags, DWORD_PTR dwContext); -BOOL HTTP_FinishedReading(LPWININETHTTPREQW lpwhr); - -VOID SendAsyncCallback(LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext, +VOID SendAsyncCallback(object_header_t *hdr, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInfo, DWORD dwStatusInfoLength); -VOID INTERNET_SendCallback(LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext, +VOID INTERNET_SendCallback(object_header_t *hdr, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInfo, DWORD dwStatusInfoLength); -LPHTTPHEADERW HTTP_GetHeader(LPWININETHTTPREQW lpwhr, LPCWSTR header); - BOOL NETCON_connected(WININET_NETCONNECTION *connection); -BOOL NETCON_init(WININET_NETCONNECTION *connnection, BOOL useSSL); -BOOL NETCON_create(WININET_NETCONNECTION *connection, int domain, +DWORD NETCON_init(WININET_NETCONNECTION *connnection, BOOL useSSL); +void NETCON_unload(void); +DWORD NETCON_create(WININET_NETCONNECTION *connection, int domain, int type, int protocol); -BOOL NETCON_close(WININET_NETCONNECTION *connection); -BOOL NETCON_connect(WININET_NETCONNECTION *connection, const struct sockaddr *serv_addr, +DWORD NETCON_close(WININET_NETCONNECTION *connection); +DWORD NETCON_connect(WININET_NETCONNECTION *connection, const struct sockaddr *serv_addr, unsigned int addrlen); -BOOL NETCON_secure_connect(WININET_NETCONNECTION *connection, LPCWSTR hostname); -BOOL NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, int flags, +DWORD NETCON_secure_connect(WININET_NETCONNECTION *connection, LPWSTR hostname); +DWORD NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, int flags, int *sent /* out */); -BOOL NETCON_recv(WININET_NETCONNECTION *connection, void *buf, size_t len, int flags, +DWORD NETCON_recv(WININET_NETCONNECTION *connection, void *buf, size_t len, int flags, int *recvd /* out */); BOOL NETCON_query_data_available(WININET_NETCONNECTION *connection, DWORD *available); -BOOL NETCON_getNextLine(WININET_NETCONNECTION *connection, LPSTR lpszBuffer, LPDWORD dwBuffer); LPCVOID NETCON_GetCert(WININET_NETCONNECTION *connection); DWORD NETCON_set_timeout(WININET_NETCONNECTION *connection, BOOL send, int value); +int sock_get_error(int); extern void URLCacheContainers_CreateDefaults(void); extern void URLCacheContainers_DeleteAll(void); diff --git a/reactos/dll/win32/wininet/netconnection.c b/reactos/dll/win32/wininet/netconnection.c index 5d8b4d75534..c2560b5da37 100644 --- a/reactos/dll/win32/wininet/netconnection.c +++ b/reactos/dll/win32/wininet/netconnection.c @@ -23,6 +23,12 @@ #include "config.h" #include "wine/port.h" +#define NONAMELESSUNION + +#if defined(__MINGW32__) || defined (_MSC_VER) +#include +#endif + #include #ifdef HAVE_POLL_H #include @@ -33,10 +39,12 @@ #ifdef HAVE_SYS_TIME_H # include #endif -#include #ifdef HAVE_SYS_SOCKET_H # include #endif +#ifdef HAVE_SYS_FILIO_H +# include +#endif #ifdef HAVE_UNISTD_H # include #endif @@ -55,9 +63,6 @@ #undef FAR #undef DSA #endif -#ifdef HAVE_SYS_SOCKET_H -# include -#endif #include #include @@ -81,7 +86,7 @@ #include "winsock2.h" #define RESPONSE_TIMEOUT 30 /* FROM internet.c */ -#define sock_get_error(x) WSAGetLastError() + WINE_DEFAULT_DEBUG_CHANNEL(wininet); @@ -95,11 +100,23 @@ WINE_DEFAULT_DEBUG_CHANNEL(wininet); #include +static CRITICAL_SECTION init_ssl_cs; +static CRITICAL_SECTION_DEBUG init_ssl_cs_debug = +{ + 0, 0, &init_ssl_cs, + { &init_ssl_cs_debug.ProcessLocksList, + &init_ssl_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": init_ssl_cs") } +}; +static CRITICAL_SECTION init_ssl_cs = { &init_ssl_cs_debug, -1, 0, 0, 0, 0 }; + static void *OpenSSL_ssl_handle; static void *OpenSSL_crypto_handle; static SSL_METHOD *meth; static SSL_CTX *ctx; +static int hostname_idx; +static int error_idx; #define MAKE_FUNCPTR(f) static typeof(f) * p##f @@ -107,6 +124,7 @@ static SSL_CTX *ctx; MAKE_FUNCPTR(SSL_library_init); MAKE_FUNCPTR(SSL_load_error_strings); MAKE_FUNCPTR(SSLv23_method); +MAKE_FUNCPTR(SSL_CTX_free); MAKE_FUNCPTR(SSL_CTX_new); MAKE_FUNCPTR(SSL_new); MAKE_FUNCPTR(SSL_free); @@ -115,46 +133,240 @@ MAKE_FUNCPTR(SSL_connect); MAKE_FUNCPTR(SSL_shutdown); MAKE_FUNCPTR(SSL_write); MAKE_FUNCPTR(SSL_read); +MAKE_FUNCPTR(SSL_pending); +MAKE_FUNCPTR(SSL_get_ex_new_index); +MAKE_FUNCPTR(SSL_get_ex_data); +MAKE_FUNCPTR(SSL_set_ex_data); +MAKE_FUNCPTR(SSL_get_ex_data_X509_STORE_CTX_idx); MAKE_FUNCPTR(SSL_get_verify_result); MAKE_FUNCPTR(SSL_get_peer_certificate); MAKE_FUNCPTR(SSL_CTX_get_timeout); MAKE_FUNCPTR(SSL_CTX_set_timeout); MAKE_FUNCPTR(SSL_CTX_set_default_verify_paths); -MAKE_FUNCPTR(i2d_X509); +MAKE_FUNCPTR(SSL_CTX_set_verify); +MAKE_FUNCPTR(X509_STORE_CTX_get_ex_data); /* OpenSSL's libcrypto functions that we use */ MAKE_FUNCPTR(BIO_new_fp); +MAKE_FUNCPTR(CRYPTO_num_locks); +MAKE_FUNCPTR(CRYPTO_set_id_callback); +MAKE_FUNCPTR(CRYPTO_set_locking_callback); +MAKE_FUNCPTR(ERR_free_strings); MAKE_FUNCPTR(ERR_get_error); MAKE_FUNCPTR(ERR_error_string); +MAKE_FUNCPTR(i2d_X509); +MAKE_FUNCPTR(sk_num); +MAKE_FUNCPTR(sk_value); #undef MAKE_FUNCPTR +static CRITICAL_SECTION *ssl_locks; +static unsigned int num_ssl_locks; + +static unsigned long ssl_thread_id(void) +{ + return GetCurrentThreadId(); +} + +static void ssl_lock_callback(int mode, int type, const char *file, int line) +{ + if (mode & CRYPTO_LOCK) + EnterCriticalSection(&ssl_locks[type]); + else + LeaveCriticalSection(&ssl_locks[type]); +} + +static PCCERT_CONTEXT X509_to_cert_context(X509 *cert) +{ + unsigned char* buffer,*p; + INT len; + BOOL malloced = FALSE; + PCCERT_CONTEXT ret; + + p = NULL; + len = pi2d_X509(cert,&p); + /* + * SSL 0.9.7 and above malloc the buffer if it is null. + * however earlier version do not and so we would need to alloc the buffer. + * + * see the i2d_X509 man page for more details. + */ + if (!p) + { + buffer = HeapAlloc(GetProcessHeap(),0,len); + p = buffer; + len = pi2d_X509(cert,&p); + } + else + { + buffer = p; + malloced = TRUE; + } + + ret = CertCreateCertificateContext(X509_ASN_ENCODING,buffer,len); + + if (malloced) + free(buffer); + else + HeapFree(GetProcessHeap(),0,buffer); + + return ret; +} + +static DWORD netconn_verify_cert(PCCERT_CONTEXT cert, HCERTSTORE store, + WCHAR *server) +{ + BOOL ret; + CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } }; + PCCERT_CHAIN_CONTEXT chain; + char oid_server_auth[] = szOID_PKIX_KP_SERVER_AUTH; + char *server_auth[] = { oid_server_auth }; + DWORD err = ERROR_SUCCESS; + + TRACE("verifying %s\n", debugstr_w(server)); + chainPara.RequestedUsage.Usage.cUsageIdentifier = 1; + chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = server_auth; + if ((ret = CertGetCertificateChain(NULL, cert, NULL, store, &chainPara, 0, + NULL, &chain))) + { + if (chain->TrustStatus.dwErrorStatus) + { + if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID) + err = ERROR_INTERNET_SEC_CERT_DATE_INVALID; + else if (chain->TrustStatus.dwErrorStatus & + CERT_TRUST_IS_UNTRUSTED_ROOT) + err = ERROR_INTERNET_INVALID_CA; + else if ((chain->TrustStatus.dwErrorStatus & + CERT_TRUST_IS_OFFLINE_REVOCATION) || + (chain->TrustStatus.dwErrorStatus & + CERT_TRUST_REVOCATION_STATUS_UNKNOWN)) + err = ERROR_INTERNET_SEC_CERT_NO_REV; + else if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED) + err = ERROR_INTERNET_SEC_CERT_REVOKED; + else if (chain->TrustStatus.dwErrorStatus & + CERT_TRUST_IS_NOT_VALID_FOR_USAGE) + err = ERROR_INTERNET_SEC_INVALID_CERT; + else + err = ERROR_INTERNET_SEC_INVALID_CERT; + } + else + { + CERT_CHAIN_POLICY_PARA policyPara; + SSL_EXTRA_CERT_CHAIN_POLICY_PARA sslExtraPolicyPara; + CERT_CHAIN_POLICY_STATUS policyStatus; + + sslExtraPolicyPara.u.cbSize = sizeof(sslExtraPolicyPara); + sslExtraPolicyPara.dwAuthType = AUTHTYPE_SERVER; + sslExtraPolicyPara.pwszServerName = server; + policyPara.cbSize = sizeof(policyPara); + policyPara.dwFlags = 0; + policyPara.pvExtraPolicyPara = &sslExtraPolicyPara; + ret = CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, + chain, &policyPara, &policyStatus); + /* Any error in the policy status indicates that the + * policy couldn't be verified. + */ + if (ret && policyStatus.dwError) + { + if (policyStatus.dwError == CERT_E_CN_NO_MATCH) + err = ERROR_INTERNET_SEC_CERT_CN_INVALID; + else + err = ERROR_INTERNET_SEC_INVALID_CERT; + } + } + CertFreeCertificateChain(chain); + } + TRACE("returning %08x\n", err); + return err; +} + +static int netconn_secure_verify(int preverify_ok, X509_STORE_CTX *ctx) +{ + SSL *ssl; + WCHAR *server; + BOOL ret = FALSE; + + ssl = pX509_STORE_CTX_get_ex_data(ctx, + pSSL_get_ex_data_X509_STORE_CTX_idx()); + server = pSSL_get_ex_data(ssl, hostname_idx); + if (preverify_ok) + { + HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + + if (store) + { + X509 *cert; + int i; + PCCERT_CONTEXT endCert = NULL; + + ret = TRUE; + for (i = 0; ret && i < psk_num((struct stack_st *)ctx->chain); i++) + { + PCCERT_CONTEXT context; + + cert = (X509 *)psk_value((struct stack_st *)ctx->chain, i); + if ((context = X509_to_cert_context(cert))) + { + if (i == 0) + ret = CertAddCertificateContextToStore(store, context, + CERT_STORE_ADD_ALWAYS, &endCert); + else + ret = CertAddCertificateContextToStore(store, context, + CERT_STORE_ADD_ALWAYS, NULL); + CertFreeCertificateContext(context); + } + } + if (!endCert) ret = FALSE; + if (ret) + { + DWORD_PTR err = netconn_verify_cert(endCert, store, server); + + if (err) + { + pSSL_set_ex_data(ssl, error_idx, (void *)err); + ret = FALSE; + } + } + CertFreeCertificateContext(endCert); + CertCloseStore(store, 0); + } + } + return ret; +} + #endif -BOOL NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL) +DWORD NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL) { connection->useSSL = FALSE; connection->socketFD = -1; if (useSSL) { #if defined(SONAME_LIBSSL) && defined(SONAME_LIBCRYPTO) + int i; + TRACE("using SSL connection\n"); + EnterCriticalSection(&init_ssl_cs); if (OpenSSL_ssl_handle) /* already initialized everything */ - return TRUE; + { + LeaveCriticalSection(&init_ssl_cs); + return ERROR_SUCCESS; + } OpenSSL_ssl_handle = wine_dlopen(SONAME_LIBSSL, RTLD_NOW, NULL, 0); if (!OpenSSL_ssl_handle) { ERR("trying to use a SSL connection, but couldn't load %s. Expect trouble.\n", SONAME_LIBSSL); - INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR); - return FALSE; + LeaveCriticalSection(&init_ssl_cs); + return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; } OpenSSL_crypto_handle = wine_dlopen(SONAME_LIBCRYPTO, RTLD_NOW, NULL, 0); if (!OpenSSL_crypto_handle) { ERR("trying to use a SSL connection, but couldn't load %s. Expect trouble.\n", SONAME_LIBCRYPTO); - INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR); - return FALSE; + LeaveCriticalSection(&init_ssl_cs); + return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; } /* mmm nice ugly macroness */ @@ -163,13 +375,14 @@ BOOL NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL) if (!p##x) \ { \ ERR("failed to load symbol %s\n", #x); \ - INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR); \ - return FALSE; \ + LeaveCriticalSection(&init_ssl_cs); \ + return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; \ } DYNSSL(SSL_library_init); DYNSSL(SSL_load_error_strings); DYNSSL(SSLv23_method); + DYNSSL(SSL_CTX_free); DYNSSL(SSL_CTX_new); DYNSSL(SSL_new); DYNSSL(SSL_free); @@ -178,12 +391,18 @@ BOOL NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL) DYNSSL(SSL_shutdown); DYNSSL(SSL_write); DYNSSL(SSL_read); + DYNSSL(SSL_pending); + DYNSSL(SSL_get_ex_new_index); + DYNSSL(SSL_get_ex_data); + DYNSSL(SSL_set_ex_data); + DYNSSL(SSL_get_ex_data_X509_STORE_CTX_idx); DYNSSL(SSL_get_verify_result); DYNSSL(SSL_get_peer_certificate); DYNSSL(SSL_CTX_get_timeout); DYNSSL(SSL_CTX_set_timeout); DYNSSL(SSL_CTX_set_default_verify_paths); - DYNSSL(i2d_X509); + DYNSSL(SSL_CTX_set_verify); + DYNSSL(X509_STORE_CTX_get_ex_data); #undef DYNSSL #define DYNCRYPTO(x) \ @@ -191,12 +410,19 @@ BOOL NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL) if (!p##x) \ { \ ERR("failed to load symbol %s\n", #x); \ - INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR); \ - return FALSE; \ + LeaveCriticalSection(&init_ssl_cs); \ + return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; \ } DYNCRYPTO(BIO_new_fp); + DYNCRYPTO(CRYPTO_num_locks); + DYNCRYPTO(CRYPTO_set_id_callback); + DYNCRYPTO(CRYPTO_set_locking_callback); + DYNCRYPTO(ERR_free_strings); DYNCRYPTO(ERR_get_error); DYNCRYPTO(ERR_error_string); + DYNCRYPTO(i2d_X509); + DYNCRYPTO(sk_num); + DYNCRYPTO(sk_value); #undef DYNCRYPTO pSSL_library_init(); @@ -204,15 +430,75 @@ BOOL NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL) pBIO_new_fp(stderr, BIO_NOCLOSE); /* FIXME: should use winedebug stuff */ meth = pSSLv23_method(); - connection->peek_msg = NULL; - connection->peek_msg_mem = NULL; + ctx = pSSL_CTX_new(meth); + if (!pSSL_CTX_set_default_verify_paths(ctx)) + { + ERR("SSL_CTX_set_default_verify_paths failed: %s\n", + pERR_error_string(pERR_get_error(), 0)); + LeaveCriticalSection(&init_ssl_cs); + return ERROR_OUTOFMEMORY; + } + hostname_idx = pSSL_get_ex_new_index(0, (void *)"hostname index", + NULL, NULL, NULL); + if (hostname_idx == -1) + { + ERR("SSL_get_ex_new_index failed; %s\n", + pERR_error_string(pERR_get_error(), 0)); + LeaveCriticalSection(&init_ssl_cs); + return ERROR_OUTOFMEMORY; + } + error_idx = pSSL_get_ex_new_index(0, (void *)"error index", + NULL, NULL, NULL); + if (error_idx == -1) + { + ERR("SSL_get_ex_new_index failed; %s\n", + pERR_error_string(pERR_get_error(), 0)); + LeaveCriticalSection(&init_ssl_cs); + return ERROR_OUTOFMEMORY; + } + pSSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, netconn_secure_verify); + + pCRYPTO_set_id_callback(ssl_thread_id); + num_ssl_locks = pCRYPTO_num_locks(); + ssl_locks = HeapAlloc(GetProcessHeap(), 0, num_ssl_locks * sizeof(CRITICAL_SECTION)); + if (!ssl_locks) + { + LeaveCriticalSection(&init_ssl_cs); + return ERROR_OUTOFMEMORY; + } + for (i = 0; i < num_ssl_locks; i++) + InitializeCriticalSection(&ssl_locks[i]); + pCRYPTO_set_locking_callback(ssl_lock_callback); + LeaveCriticalSection(&init_ssl_cs); #else FIXME("can't use SSL, not compiled in.\n"); - INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR); - return FALSE; + return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; #endif } - return TRUE; + return ERROR_SUCCESS; +} + +void NETCON_unload(void) +{ +#if defined(SONAME_LIBSSL) && defined(SONAME_LIBCRYPTO) + if (OpenSSL_crypto_handle) + { + pERR_free_strings(); + wine_dlclose(OpenSSL_crypto_handle, NULL, 0); + } + if (OpenSSL_ssl_handle) + { + if (ctx) + pSSL_CTX_free(ctx); + wine_dlclose(OpenSSL_ssl_handle, NULL, 0); + } + if (ssl_locks) + { + int i; + for (i = 0; i < num_ssl_locks; i++) DeleteCriticalSection(&ssl_locks[i]); + HeapFree(GetProcessHeap(), 0, ssl_locks); + } +#endif } BOOL NETCON_connected(WININET_NETCONNECTION *connection) @@ -223,9 +509,8 @@ BOOL NETCON_connected(WININET_NETCONNECTION *connection) return TRUE; } -#if 0 /* translate a unix error code into a winsock one */ -static int sock_get_error( int err ) +int sock_get_error( int err ) { #if !defined(__MINGW32__) && !defined (_MSC_VER) switch (err) @@ -290,47 +575,39 @@ static int sock_get_error( int err ) #endif return err; } -#endif /****************************************************************************** * NETCON_create * Basically calls 'socket()' */ -BOOL NETCON_create(WININET_NETCONNECTION *connection, int domain, +DWORD NETCON_create(WININET_NETCONNECTION *connection, int domain, int type, int protocol) { #ifdef SONAME_LIBSSL if (connection->useSSL) - return FALSE; + return ERROR_NOT_SUPPORTED; #endif connection->socketFD = socket(domain, type, protocol); if (connection->socketFD == -1) - { - INTERNET_SetLastError(sock_get_error(errno)); - return FALSE; - } - return TRUE; + return sock_get_error(errno); + + return ERROR_SUCCESS; } /****************************************************************************** * NETCON_close * Basically calls 'close()' unless we should use SSL */ -BOOL NETCON_close(WININET_NETCONNECTION *connection) +DWORD NETCON_close(WININET_NETCONNECTION *connection) { int result; - if (!NETCON_connected(connection)) return FALSE; + if (!NETCON_connected(connection)) return ERROR_SUCCESS; #ifdef SONAME_LIBSSL if (connection->useSSL) { - HeapFree(GetProcessHeap(),0,connection->peek_msg_mem); - connection->peek_msg = NULL; - connection->peek_msg_mem = NULL; - connection->peek_len = 0; - pSSL_shutdown(connection->ssl_s); pSSL_free(connection->ssl_s); connection->ssl_s = NULL; @@ -343,52 +620,34 @@ BOOL NETCON_close(WININET_NETCONNECTION *connection) connection->socketFD = -1; if (result == -1) - { - INTERNET_SetLastError(sock_get_error(errno)); - return FALSE; - } - return TRUE; + return sock_get_error(errno); + return ERROR_SUCCESS; } -#ifdef SONAME_LIBSSL -static BOOL check_hostname(X509 *cert, char *hostname) -{ - /* FIXME: implement */ - return TRUE; -} -#endif + /****************************************************************************** * NETCON_secure_connect * Initiates a secure connection over an existing plaintext connection. */ -BOOL NETCON_secure_connect(WININET_NETCONNECTION *connection, LPCWSTR hostname) +DWORD NETCON_secure_connect(WININET_NETCONNECTION *connection, LPWSTR hostname) { + DWORD res = ERROR_NOT_SUPPORTED; #ifdef SONAME_LIBSSL long verify_res; X509 *cert; - int len; - char *hostname_unix; /* can't connect if we are already connected */ if (connection->useSSL) { ERR("already connected\n"); - return FALSE; + return ERROR_INTERNET_CANNOT_CONNECT; } - ctx = pSSL_CTX_new(meth); - if (!pSSL_CTX_set_default_verify_paths(ctx)) - { - ERR("SSL_CTX_set_default_verify_paths failed: %s\n", - pERR_error_string(pERR_get_error(), 0)); - INTERNET_SetLastError(ERROR_OUTOFMEMORY); - return FALSE; - } connection->ssl_s = pSSL_new(ctx); if (!connection->ssl_s) { ERR("SSL_new failed: %s\n", pERR_error_string(pERR_get_error(), 0)); - INTERNET_SetLastError(ERROR_OUTOFMEMORY); + res = ERROR_OUTOFMEMORY; goto fail; } @@ -396,23 +655,25 @@ BOOL NETCON_secure_connect(WININET_NETCONNECTION *connection, LPCWSTR hostname) { ERR("SSL_set_fd failed: %s\n", pERR_error_string(pERR_get_error(), 0)); - INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR); + res = ERROR_INTERNET_SECURITY_CHANNEL_ERROR; goto fail; } if (pSSL_connect(connection->ssl_s) <= 0) { - ERR("SSL_connect failed: %s\n", - pERR_error_string(pERR_get_error(), 0)); - INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR); + res = (DWORD_PTR)pSSL_get_ex_data(connection->ssl_s, error_idx); + if (!res) + res = ERROR_INTERNET_SECURITY_CHANNEL_ERROR; + ERR("SSL_connect failed: %d\n", res); goto fail; } + pSSL_set_ex_data(connection->ssl_s, hostname_idx, hostname); cert = pSSL_get_peer_certificate(connection->ssl_s); if (!cert) { ERR("no certificate for server %s\n", debugstr_w(hostname)); /* FIXME: is this the best error? */ - INTERNET_SetLastError(ERROR_INTERNET_INVALID_CA); + res = ERROR_INTERNET_INVALID_CA; goto fail; } verify_res = pSSL_get_verify_result(connection->ssl_s); @@ -423,25 +684,8 @@ BOOL NETCON_secure_connect(WININET_NETCONNECTION *connection, LPCWSTR hostname) * the moment */ } - len = WideCharToMultiByte(CP_UNIXCP, 0, hostname, -1, NULL, 0, NULL, NULL); - hostname_unix = HeapAlloc(GetProcessHeap(), 0, len); - if (!hostname_unix) - { - INTERNET_SetLastError(ERROR_OUTOFMEMORY); - goto fail; - } - WideCharToMultiByte(CP_UNIXCP, 0, hostname, -1, hostname_unix, len, NULL, NULL); - - if (!check_hostname(cert, hostname_unix)) - { - HeapFree(GetProcessHeap(), 0, hostname_unix); - INTERNET_SetLastError(ERROR_INTERNET_SEC_CERT_CN_INVALID); - goto fail; - } - - HeapFree(GetProcessHeap(), 0, hostname_unix); connection->useSSL = TRUE; - return TRUE; + return ERROR_SUCCESS; fail: if (connection->ssl_s) @@ -451,32 +695,29 @@ fail: connection->ssl_s = NULL; } #endif - return FALSE; + return res; } /****************************************************************************** * NETCON_connect * Connects to the specified address. */ -BOOL NETCON_connect(WININET_NETCONNECTION *connection, const struct sockaddr *serv_addr, +DWORD NETCON_connect(WININET_NETCONNECTION *connection, const struct sockaddr *serv_addr, unsigned int addrlen) { int result; - if (!NETCON_connected(connection)) return FALSE; - result = connect(connection->socketFD, serv_addr, addrlen); if (result == -1) { WARN("Unable to connect to host (%s)\n", strerror(errno)); - INTERNET_SetLastError(sock_get_error(errno)); closesocket(connection->socketFD); connection->socketFD = -1; - return FALSE; + return sock_get_error(errno); } - return TRUE; + return ERROR_SUCCESS; } /****************************************************************************** @@ -484,19 +725,16 @@ BOOL NETCON_connect(WININET_NETCONNECTION *connection, const struct sockaddr *se * Basically calls 'send()' unless we should use SSL * number of chars send is put in *sent */ -BOOL NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, int flags, +DWORD NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, int flags, int *sent /* out */) { - if (!NETCON_connected(connection)) return FALSE; + if (!NETCON_connected(connection)) return ERROR_INTERNET_CONNECTION_ABORTED; if (!connection->useSSL) { *sent = send(connection->socketFD, msg, len, flags); if (*sent == -1) - { - INTERNET_SetLastError(sock_get_error(errno)); - return FALSE; - } - return TRUE; + return sock_get_error(errno); + return ERROR_SUCCESS; } else { @@ -505,10 +743,10 @@ BOOL NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, FIXME("SSL_write doesn't support any flags (%08x)\n", flags); *sent = pSSL_write(connection->ssl_s, msg, len); if (*sent < 1 && len) - return FALSE; - return TRUE; + return ERROR_INTERNET_CONNECTION_ABORTED; + return ERROR_SUCCESS; #else - return FALSE; + return ERROR_NOT_SUPPORTED; #endif } } @@ -518,77 +756,25 @@ BOOL NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, * Basically calls 'recv()' unless we should use SSL * number of chars received is put in *recvd */ -BOOL NETCON_recv(WININET_NETCONNECTION *connection, void *buf, size_t len, int flags, +DWORD NETCON_recv(WININET_NETCONNECTION *connection, void *buf, size_t len, int flags, int *recvd /* out */) { *recvd = 0; - if (!NETCON_connected(connection)) return FALSE; + if (!NETCON_connected(connection)) return ERROR_INTERNET_CONNECTION_ABORTED; if (!len) - return TRUE; + return ERROR_SUCCESS; if (!connection->useSSL) { *recvd = recv(connection->socketFD, buf, len, flags); - if (*recvd == -1) - { - INTERNET_SetLastError(sock_get_error(errno)); - return FALSE; - } - return TRUE; + return *recvd == -1 ? sock_get_error(errno) : ERROR_SUCCESS; } else { #ifdef SONAME_LIBSSL - if (flags & ~(MSG_PEEK|MSG_WAITALL)) - FIXME("SSL_read does not support the following flag: %08x\n", flags); - - /* this ugly hack is all for MSG_PEEK. eww gross */ - if (flags & MSG_PEEK && !connection->peek_msg) - { - connection->peek_msg = connection->peek_msg_mem = HeapAlloc(GetProcessHeap(), 0, (sizeof(char) * len) + 1); - } - else if (flags & MSG_PEEK && connection->peek_msg) - { - if (len < connection->peek_len) - FIXME("buffer isn't big enough. Do the expect us to wrap?\n"); - *recvd = min(len, connection->peek_len); - memcpy(buf, connection->peek_msg, *recvd); - return TRUE; - } - else if (connection->peek_msg) - { - *recvd = min(len, connection->peek_len); - memcpy(buf, connection->peek_msg, *recvd); - connection->peek_len -= *recvd; - connection->peek_msg += *recvd; - if (connection->peek_len == 0) - { - HeapFree(GetProcessHeap(), 0, connection->peek_msg_mem); - connection->peek_msg_mem = NULL; - connection->peek_msg = NULL; - } - /* check if we got enough data from the peek buffer */ - if (!(flags & MSG_WAITALL) || (*recvd == len)) - return TRUE; - /* otherwise, fall through */ - } - *recvd += pSSL_read(connection->ssl_s, (char*)buf + *recvd, len - *recvd); - if (flags & MSG_PEEK) /* must copy stuff into buffer */ - { - connection->peek_len = *recvd; - if (!*recvd) - { - HeapFree(GetProcessHeap(), 0, connection->peek_msg_mem); - connection->peek_msg_mem = NULL; - connection->peek_msg = NULL; - } - else - memcpy(connection->peek_msg, buf, *recvd); - } - if (*recvd < 1 && len) - return FALSE; - return TRUE; + *recvd = pSSL_read(connection->ssl_s, buf, len); + return *recvd > 0 ? ERROR_SUCCESS : ERROR_INTERNET_CONNECTION_ABORTED; #else - return FALSE; + return ERROR_NOT_SUPPORTED; #endif } } @@ -604,13 +790,9 @@ BOOL NETCON_query_data_available(WININET_NETCONNECTION *connection, DWORD *avail if (!NETCON_connected(connection)) return FALSE; -#ifdef SONAME_LIBSSL - if (connection->peek_msg) *available = connection->peek_len; -#endif - -#ifdef FIONREAD if (!connection->useSSL) { +#ifdef FIONREAD int unread; int retval = ioctlsocket(connection->socketFD, FIONREAD, &unread); if (!retval) @@ -618,155 +800,28 @@ BOOL NETCON_query_data_available(WININET_NETCONNECTION *connection, DWORD *avail TRACE("%d bytes of queued, but unread data\n", unread); *available += unread; } - } #endif - return TRUE; -} - -/****************************************************************************** - * NETCON_getNextLine - */ -BOOL NETCON_getNextLine(WININET_NETCONNECTION *connection, LPSTR lpszBuffer, LPDWORD dwBuffer) -{ - - TRACE("\n"); - - if (!NETCON_connected(connection)) return FALSE; - - if (!connection->useSSL) - { - struct timeval tv; - fd_set infd; - BOOL bSuccess = FALSE; - DWORD nRecv = 0; - - FD_ZERO(&infd); - FD_SET(connection->socketFD, &infd); - tv.tv_sec=RESPONSE_TIMEOUT; - tv.tv_usec=0; - - while (nRecv < *dwBuffer) - { - if (select(connection->socketFD+1,&infd,NULL,NULL,&tv) > 0) - { - if (recv(connection->socketFD, &lpszBuffer[nRecv], 1, 0) <= 0) - { - INTERNET_SetLastError(sock_get_error(errno)); - goto lend; - } - - if (lpszBuffer[nRecv] == '\n') - { - bSuccess = TRUE; - break; - } - if (lpszBuffer[nRecv] != '\r') - nRecv++; - } - else - { - INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT); - goto lend; - } - } - - lend: /* FIXME: don't use labels */ - if (bSuccess) - { - lpszBuffer[nRecv++] = '\0'; - *dwBuffer = nRecv; - TRACE(":%u %s\n", nRecv, lpszBuffer); - return TRUE; - } - else - { - return FALSE; - } } else { #ifdef SONAME_LIBSSL - long prev_timeout; - DWORD nRecv = 0; - BOOL success = TRUE; - - prev_timeout = pSSL_CTX_get_timeout(ctx); - pSSL_CTX_set_timeout(ctx, RESPONSE_TIMEOUT); - - while (nRecv < *dwBuffer) - { - int recv = 1; - if (!NETCON_recv(connection, &lpszBuffer[nRecv], 1, 0, &recv)) - { - INTERNET_SetLastError(ERROR_CONNECTION_ABORTED); - success = FALSE; - } - - if (lpszBuffer[nRecv] == '\n') - { - success = TRUE; - break; - } - if (lpszBuffer[nRecv] != '\r') - nRecv++; - } - - pSSL_CTX_set_timeout(ctx, prev_timeout); - if (success) - { - lpszBuffer[nRecv++] = '\0'; - *dwBuffer = nRecv; - TRACE("_SSL:%u %s\n", nRecv, lpszBuffer); - return TRUE; - } - return FALSE; -#else - return FALSE; + *available = pSSL_pending(connection->ssl_s); #endif } + return TRUE; } - LPCVOID NETCON_GetCert(WININET_NETCONNECTION *connection) { #ifdef SONAME_LIBSSL X509* cert; - unsigned char* buffer,*p; - INT len; - BOOL malloced = FALSE; LPCVOID r = NULL; if (!connection->useSSL) return NULL; cert = pSSL_get_peer_certificate(connection->ssl_s); - p = NULL; - len = pi2d_X509(cert,&p); - /* - * SSL 0.9.7 and above malloc the buffer if it is null. - * however earlier version do not and so we would need to alloc the buffer. - * - * see the i2d_X509 man page for more details. - */ - if (!p) - { - buffer = HeapAlloc(GetProcessHeap(),0,len); - p = buffer; - len = pi2d_X509(cert,&p); - } - else - { - buffer = p; - malloced = TRUE; - } - - r = CertCreateCertificateContext(X509_ASN_ENCODING,buffer,len); - - if (malloced) - free(buffer); - else - HeapFree(GetProcessHeap(),0,buffer); - + r = X509_to_cert_context(cert); return r; #else return NULL; @@ -788,7 +843,7 @@ DWORD NETCON_set_timeout(WININET_NETCONNECTION *connection, BOOL send, int value tv.tv_usec = (value % 1000) * 1000; result = setsockopt(connection->socketFD, SOL_SOCKET, - send ? SO_SNDTIMEO : SO_RCVTIMEO, &tv, + send ? SO_SNDTIMEO : SO_RCVTIMEO, (void*)&tv, sizeof(tv)); if (result == -1) diff --git a/reactos/dll/win32/wininet/resource.h b/reactos/dll/win32/wininet/resource.h index 8a6e4d152e2..279c1123db8 100644 --- a/reactos/dll/win32/wininet/resource.h +++ b/reactos/dll/win32/wininet/resource.h @@ -18,6 +18,10 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include +#include + +#define IDD_AUTHDLG 0x399 #define IDD_PROXYDLG 0x400 #define IDC_PROXY 0x401 @@ -25,5 +29,6 @@ #define IDC_USERNAME 0x403 #define IDC_PASSWORD 0x404 #define IDC_SAVEPASSWORD 0x405 +#define IDC_SERVER 0x406 #define IDS_LANCONNECTION 0x500 diff --git a/reactos/dll/win32/wininet/rsrc.rc b/reactos/dll/win32/wininet/rsrc.rc index 5a815116b03..52ea8d4e8d2 100644 --- a/reactos/dll/win32/wininet/rsrc.rc +++ b/reactos/dll/win32/wininet/rsrc.rc @@ -43,24 +43,28 @@ #include "wininet_Bg.rc" #include "wininet_Cs.rc" #include "wininet_Da.rc" -#include "wininet_De.rc" #include "wininet_En.rc" #include "wininet_Eo.rc" #include "wininet_Es.rc" #include "wininet_Fi.rc" -#include "wininet_Fr.rc" #include "wininet_Hu.rc" #include "wininet_It.rc" -#include "wininet_Ja.rc" #include "wininet_Ko.rc" #include "wininet_Nl.rc" -#include "wininet_No.rc" #include "wininet_Pl.rc" +#include "wininet_Sv.rc" +#include "wininet_Uk.rc" +#include "wininet_Tr.rc" + +/* UTF-8 */ +#include "wininet_De.rc" +#include "wininet_Fr.rc" +#include "wininet_Ja.rc" +#include "wininet_Lt.rc" +#include "wininet_No.rc" #include "wininet_Pt.rc" #include "wininet_Ro.rc" #include "wininet_Ru.rc" #include "wininet_Si.rc" -#include "wininet_Sv.rc" -#include "wininet_Uk.rc" -#include "wininet_Tr.rc" #include "wininet_Zh.rc" + diff --git a/reactos/dll/win32/wininet/urlcache.c b/reactos/dll/win32/wininet/urlcache.c index c839419f136..29d26ab0b6b 100644 --- a/reactos/dll/win32/wininet/urlcache.c +++ b/reactos/dll/win32/wininet/urlcache.c @@ -465,7 +465,6 @@ static void URLCacheContainer_CloseIndex(URLCACHECONTAINER * pContainer) static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, LPCWSTR path, LPWSTR mutex_name) { URLCACHECONTAINER * pContainer = HeapAlloc(GetProcessHeap(), 0, sizeof(URLCACHECONTAINER)); - int path_len = strlenW(path); int cache_prefix_len = strlenW(cache_prefix); if (!pContainer) @@ -476,15 +475,13 @@ static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, LPCWSTR path, pContainer->hMapping = NULL; pContainer->file_size = 0; - pContainer->path = HeapAlloc(GetProcessHeap(), 0, (path_len + 1) * sizeof(WCHAR)); + pContainer->path = heap_strdupW(path); if (!pContainer->path) { HeapFree(GetProcessHeap(), 0, pContainer); return FALSE; } - memcpy(pContainer->path, path, (path_len + 1) * sizeof(WCHAR)); - pContainer->cache_prefix = HeapAlloc(GetProcessHeap(), 0, (cache_prefix_len + 1) * sizeof(WCHAR)); if (!pContainer->cache_prefix) { @@ -593,6 +590,9 @@ static DWORD URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl, URLCACHECONTAIN TRACE("searching for prefix for URL: %s\n", debugstr_w(lpwszUrl)); + if(!lpwszUrl) + return ERROR_INVALID_PARAMETER; + LIST_FOR_EACH_ENTRY(pContainer, &UrlContainers, URLCACHECONTAINER, entry) { int prefix_len = strlenW(pContainer->cache_prefix); @@ -609,17 +609,15 @@ static DWORD URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl, URLCACHECONTAIN static DWORD URLCacheContainers_FindContainerA(LPCSTR lpszUrl, URLCACHECONTAINER ** ppContainer) { + LPWSTR url = NULL; DWORD ret; - LPWSTR lpwszUrl; - int url_len = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0); - if (url_len && (lpwszUrl = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(WCHAR)))) - { - MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, lpwszUrl, url_len); - ret = URLCacheContainers_FindContainerW(lpwszUrl, ppContainer); - HeapFree(GetProcessHeap(), 0, lpwszUrl); - return ret; - } - return GetLastError(); + + if (lpszUrl && !(url = heap_strdupAtoW(lpszUrl))) + return ERROR_OUTOFMEMORY; + + ret = URLCacheContainers_FindContainerW(url, ppContainer); + HeapFree(GetProcessHeap(), 0, url); + return ret; } static BOOL URLCacheContainers_Enum(LPCWSTR lpwszSearchPattern, DWORD dwIndex, URLCACHECONTAINER ** ppContainer) @@ -692,6 +690,7 @@ static LPURLCACHE_HEADER URLCacheContainer_LockIndex(URLCACHECONTAINER * pContai * of the memory mapped file */ if (pHeader->dwFileSize != pContainer->file_size) { + UnmapViewOfFile( pHeader ); URLCacheContainer_CloseIndex(pContainer); error = URLCacheContainer_OpenIndex(pContainer); if (error != ERROR_SUCCESS) @@ -1240,17 +1239,15 @@ static BOOL URLCache_FindHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, struct static BOOL URLCache_FindHashW(LPCURLCACHE_HEADER pHeader, LPCWSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry) { LPSTR urlA; - int url_len; BOOL ret; - url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL); - urlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR)); + urlA = heap_strdupWtoA(lpszUrl); if (!urlA) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; } - WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, urlA, url_len, NULL, NULL); + ret = URLCache_FindHash(pHeader, urlA, ppHashEntry); HeapFree(GetProcessHeap(), 0, urlA); return ret; @@ -1451,6 +1448,28 @@ static BOOL URLCache_EnumHashTableEntries(LPCURLCACHE_HEADER pHeader, const HASH return FALSE; } +/*********************************************************************** + * FreeUrlCacheSpaceA (WININET.@) + * + */ +BOOL WINAPI FreeUrlCacheSpaceA(LPCSTR lpszCachePath, DWORD dwSize, DWORD dwFilter) +{ + FIXME("stub!\n"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + + /*********************************************************************** + * FreeUrlCacheSpaceW (WININET.@) + * + */ +BOOL WINAPI FreeUrlCacheSpaceW(LPCWSTR lpszCachePath, DWORD dwSize, DWORD dwFilter) +{ + FIXME("stub!\n"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + /*********************************************************************** * GetUrlCacheEntryInfoExA (WININET.@) * @@ -1482,7 +1501,11 @@ BOOL WINAPI GetUrlCacheEntryInfoExA( return FALSE; } if (dwFlags != 0) + { FIXME("Undocumented flag(s): %x\n", dwFlags); + SetLastError(ERROR_FILE_NOT_FOUND); + return FALSE; + } return GetUrlCacheEntryInfoA(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize); } @@ -1682,7 +1705,11 @@ BOOL WINAPI GetUrlCacheEntryInfoExW( return FALSE; } if (dwFlags != 0) + { FIXME("Undocumented flag(s): %x\n", dwFlags); + SetLastError(ERROR_FILE_NOT_FOUND); + return FALSE; + } return GetUrlCacheEntryInfoW(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize); } @@ -1869,6 +1896,13 @@ BOOL WINAPI RetrieveUrlCacheEntryFileA( } pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry; + if (!pUrlEntry->dwOffsetLocalName) + { + URLCacheContainer_UnlockIndex(pContainer, pHeader); + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl); TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo); @@ -1958,6 +1992,13 @@ BOOL WINAPI RetrieveUrlCacheEntryFileW( } pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry; + if (!pUrlEntry->dwOffsetLocalName) + { + URLCacheContainer_UnlockIndex(pContainer, pHeader); + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl); TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo); @@ -2142,21 +2183,16 @@ BOOL WINAPI CreateUrlCacheEntryA( IN DWORD dwReserved ) { - DWORD len; WCHAR *url_name; WCHAR *file_extension; WCHAR file_name[MAX_PATH]; BOOL bSuccess = FALSE; DWORD dwError = 0; - if ((len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0)) != 0 && - (url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0) + if (lpszUrlName && (url_name = heap_strdupAtoW(lpszUrlName))) { - MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len); - if ((len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0)) != 0 && - (file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0) + if (lpszFileExtension && (file_extension = heap_strdupAtoW(lpszFileExtension))) { - MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len); if (CreateUrlCacheEntryW(url_name, dwExpectedFileSize, file_extension, file_name, dwReserved)) { if (WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL) < MAX_PATH) @@ -2211,7 +2247,11 @@ BOOL WINAPI CreateUrlCacheEntryW( BOOL bFound = FALSE; int count; DWORD error; + HANDLE hFile; + FILETIME ft; + static const WCHAR szWWW[] = {'w','w','w',0}; + static const WCHAR fmt[] = {'%','0','8','X','%','s',0}; TRACE("(%s, 0x%08x, %s, %p, 0x%08x)\n", debugstr_w(lpszUrlName), @@ -2221,11 +2261,7 @@ BOOL WINAPI CreateUrlCacheEntryW( dwReserved); if (dwReserved) - { - ERR("dwReserved != 0\n"); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } + FIXME("dwReserved 0x%08x\n", dwReserved); lpszUrlEnd = lpszUrlName + strlenW(lpszUrlName); @@ -2318,7 +2354,6 @@ BOOL WINAPI CreateUrlCacheEntryW( for (i = 0; i < 255; i++) { static const WCHAR szFormat[] = {'[','%','u',']','%','s',0}; - HANDLE hFile; WCHAR *p; wsprintfW(lpszFileNameNoPath + countnoextension, szFormat, i, szExtension); @@ -2346,6 +2381,18 @@ BOOL WINAPI CreateUrlCacheEntryW( } } + GetSystemTimeAsFileTime(&ft); + wsprintfW(lpszFileNameNoPath + countnoextension, fmt, ft.dwLowDateTime, szExtension); + + TRACE("Trying: %s\n", debugstr_w(lpszFileName)); + hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + CloseHandle(hFile); + return TRUE; + } + + WARN("Could not find a unique filename\n"); return FALSE; } @@ -2447,25 +2494,17 @@ static BOOL CommitUrlCacheEntryInternal( if (!(pHeader = URLCacheContainer_LockIndex(pContainer))) return FALSE; - len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL); - lpszUrlNameA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char)); + lpszUrlNameA = heap_strdupWtoA(lpszUrlName); if (!lpszUrlNameA) { error = GetLastError(); goto cleanup; } - WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, lpszUrlNameA, len, NULL, NULL); - if (lpszFileExtension) + if (lpszFileExtension && !(lpszFileExtensionA = heap_strdupWtoA(lpszFileExtension))) { - len = WideCharToMultiByte(CP_ACP, 0, lpszFileExtension, -1, NULL, 0, NULL, NULL); - lpszFileExtensionA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char)); - if (!lpszFileExtensionA) - { - error = GetLastError(); - goto cleanup; - } - WideCharToMultiByte(CP_ACP, 0, lpszFileExtension, -1, lpszFileExtensionA, len, NULL, NULL); + error = GetLastError(); + goto cleanup; } if (URLCache_FindHash(pHeader, lpszUrlNameA, &pHashEntry)) @@ -2622,7 +2661,6 @@ BOOL WINAPI CommitUrlCacheEntryA( IN LPCSTR lpszOriginalUrl ) { - DWORD len; WCHAR *url_name = NULL; WCHAR *local_file_name = NULL; WCHAR *original_url = NULL; @@ -2638,35 +2676,27 @@ BOOL WINAPI CommitUrlCacheEntryA( debugstr_a(lpszFileExtension), debugstr_a(lpszOriginalUrl)); - len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0); - url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + url_name = heap_strdupAtoW(lpszUrlName); if (!url_name) goto cleanup; - MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len); if (lpszLocalFileName) { - len = MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, NULL, 0); - local_file_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + local_file_name = heap_strdupAtoW(lpszLocalFileName); if (!local_file_name) goto cleanup; - MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, local_file_name, len); } if (lpszFileExtension) { - len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0); - file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + file_extension = heap_strdupAtoW(lpszFileExtension); if (!file_extension) goto cleanup; - MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len); } if (lpszOriginalUrl) { - len = MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, NULL, 0); - original_url = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + original_url = heap_strdupAtoW(lpszOriginalUrl); if (!original_url) goto cleanup; - MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, original_url, len); } bSuccess = CommitUrlCacheEntryInternal(url_name, local_file_name, ExpireTime, LastModifiedTime, @@ -2712,12 +2742,8 @@ BOOL WINAPI CommitUrlCacheEntryW( debugstr_w(lpszFileExtension), debugstr_w(lpszOriginalUrl)); - if (!lpHeaderInfo || - ((len = WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, NULL, 0, NULL, NULL)) != 0 && - (header_info = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR) * len)) != 0)) + if (!lpHeaderInfo || (header_info = heap_strdupWtoA(lpHeaderInfo))) { - if (header_info) - WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, header_info, len, NULL, NULL); if (CommitUrlCacheEntryInternal(lpszUrlName, lpszLocalFileName, ExpireTime, LastModifiedTime, CacheEntryType, (LPBYTE)header_info, len, lpszFileExtension, lpszOriginalUrl)) { @@ -2940,19 +2966,16 @@ BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName) struct _HASH_ENTRY * pHashEntry; CACHEFILE_ENTRY * pEntry; LPSTR urlA; - int url_len; DWORD error; TRACE("(%s)\n", debugstr_w(lpszUrlName)); - url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL); - urlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR)); + urlA = heap_strdupWtoA(lpszUrlName); if (!urlA) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; } - WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, urlA, url_len, NULL, NULL); error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer); if (error != ERROR_SUCCESS) @@ -3133,14 +3156,12 @@ INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern, pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC; if (lpszUrlSearchPattern) { - int len = MultiByteToWideChar(CP_ACP, 0, lpszUrlSearchPattern, -1, NULL, 0); - pEntryHandle->lpszUrlSearchPattern = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + pEntryHandle->lpszUrlSearchPattern = heap_strdupAtoW(lpszUrlSearchPattern); if (!pEntryHandle->lpszUrlSearchPattern) { HeapFree(GetProcessHeap(), 0, pEntryHandle); return NULL; } - MultiByteToWideChar(CP_ACP, 0, lpszUrlSearchPattern, -1, pEntryHandle->lpszUrlSearchPattern, len); } else pEntryHandle->lpszUrlSearchPattern = NULL; @@ -3174,14 +3195,12 @@ INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern, pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC; if (lpszUrlSearchPattern) { - int len = strlenW(lpszUrlSearchPattern); - pEntryHandle->lpszUrlSearchPattern = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); + pEntryHandle->lpszUrlSearchPattern = heap_strdupW(lpszUrlSearchPattern); if (!pEntryHandle->lpszUrlSearchPattern) { HeapFree(GetProcessHeap(), 0, pEntryHandle); return NULL; } - memcpy(pEntryHandle->lpszUrlSearchPattern, lpszUrlSearchPattern, (len + 1) * sizeof(WCHAR)); } else pEntryHandle->lpszUrlSearchPattern = NULL; @@ -3623,10 +3642,26 @@ BOOL WINAPI IsUrlCacheEntryExpiredW( LPCWSTR url, DWORD dwFlags, FILETIME* pftLa /*********************************************************************** * GetDiskInfoA (WININET.@) */ -BOOL WINAPI GetDiskInfoA(PCSTR p0, PDWORD p1, PDWORDLONG p2, PDWORDLONG p3) +BOOL WINAPI GetDiskInfoA(PCSTR path, PDWORD cluster_size, PDWORDLONG free, PDWORDLONG total) { - FIXME("(%p, %p, %p, %p)\n", p0, p1, p2, p3); - return FALSE; + BOOL ret; + ULARGE_INTEGER bytes_free, bytes_total; + + TRACE("(%s, %p, %p, %p)\n", debugstr_a(path), cluster_size, free, total); + + if (!path) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if ((ret = GetDiskFreeSpaceExA(path, NULL, &bytes_total, &bytes_free))) + { + if (cluster_size) *cluster_size = 1; + if (free) *free = bytes_free.QuadPart; + if (total) *total = bytes_total.QuadPart; + } + return ret; } /*********************************************************************** @@ -3637,3 +3672,12 @@ DWORD WINAPI RegisterUrlCacheNotification(LPVOID a, DWORD b, DWORD c, DWORD d, D FIXME("(%p %x %x %x %x %x)\n", a, b, c, d, e, f); return 0; } + +/*********************************************************************** + * IncrementUrlCacheHeaderData (WININET.@) + */ +BOOL WINAPI IncrementUrlCacheHeaderData(DWORD index, LPDWORD data) +{ + FIXME("(%u, %p)\n", index, data); + return FALSE; +} diff --git a/reactos/dll/win32/wininet/utility.c b/reactos/dll/win32/wininet/utility.c index b0d9c9c91c6..66fbecdd653 100644 --- a/reactos/dll/win32/wininet/utility.c +++ b/reactos/dll/win32/wininet/utility.c @@ -25,6 +25,10 @@ #include "config.h" #include "wine/port.h" +#if defined(__MINGW32__) || defined (_MSC_VER) +#include +#endif + #include #include #include @@ -40,6 +44,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(wininet); +#ifndef HAVE_GETADDRINFO + /* critical section to protect non-reentrant gethostbyname() */ static CRITICAL_SECTION cs_gethostbyname; static CRITICAL_SECTION_DEBUG critsect_debug = @@ -50,6 +56,8 @@ static CRITICAL_SECTION_DEBUG critsect_debug = }; static CRITICAL_SECTION cs_gethostbyname = { &critsect_debug, -1, 0, 0, 0, 0 }; +#endif + #define TIME_STRING_LEN 30 time_t ConvertTimeString(LPCWSTR asctime) @@ -137,12 +145,18 @@ time_t ConvertTimeString(LPCWSTR asctime) BOOL GetAddress(LPCWSTR lpszServerName, INTERNET_PORT nServerPort, - struct sockaddr_in *psa) + struct sockaddr *psa, socklen_t *sa_len) { WCHAR *found; char *name; int len, sz; +#ifdef HAVE_GETADDRINFO + struct addrinfo *res, hints; + int ret; +#else struct hostent *phe; + struct sockaddr_in *sin = (struct sockaddr_in *)psa; +#endif TRACE("%s\n", debugstr_w(lpszServerName)); @@ -158,27 +172,75 @@ BOOL GetAddress(LPCWSTR lpszServerName, INTERNET_PORT nServerPort, len = strlenW(lpszServerName); sz = WideCharToMultiByte( CP_UNIXCP, 0, lpszServerName, len, NULL, 0, NULL, NULL ); - name = HeapAlloc(GetProcessHeap(), 0, sz+1); + if (!(name = HeapAlloc( GetProcessHeap(), 0, sz + 1 ))) return FALSE; WideCharToMultiByte( CP_UNIXCP, 0, lpszServerName, len, name, sz, NULL, NULL ); name[sz] = 0; +#ifdef HAVE_GETADDRINFO + memset( &hints, 0, sizeof(struct addrinfo) ); + /* Prefer IPv4 to IPv6 addresses, since some servers do not listen on + * their IPv6 addresses even though they have IPv6 addresses in the DNS. + */ + hints.ai_family = AF_INET; + + ret = getaddrinfo( name, NULL, &hints, &res ); + HeapFree( GetProcessHeap(), 0, name ); + if (ret != 0) + { + TRACE("failed to get IPv4 address of %s (%s), retrying with IPv6\n", debugstr_w(lpszServerName), gai_strerror(ret)); + hints.ai_family = AF_INET6; + ret = getaddrinfo( name, NULL, &hints, &res ); + if (ret != 0) + { + TRACE("failed to get address of %s (%s)\n", debugstr_w(lpszServerName), gai_strerror(ret)); + return FALSE; + } + } + if (*sa_len < res->ai_addrlen) + { + WARN("address too small\n"); + freeaddrinfo( res ); + return FALSE; + } + *sa_len = res->ai_addrlen; + memcpy( psa, res->ai_addr, res->ai_addrlen ); + /* Copy port */ + switch (res->ai_family) + { + case AF_INET: + ((struct sockaddr_in *)psa)->sin_port = htons(nServerPort); + break; + case AF_INET6: + ((struct sockaddr_in6 *)psa)->sin6_port = htons(nServerPort); + break; + } + + freeaddrinfo( res ); +#else EnterCriticalSection( &cs_gethostbyname ); phe = gethostbyname(name); HeapFree( GetProcessHeap(), 0, name ); if (NULL == phe) { - TRACE("Failed to get hostname: (%s)\n", debugstr_w(lpszServerName) ); + TRACE("failed to get address of %s (%d)\n", debugstr_w(lpszServerName), h_errno); LeaveCriticalSection( &cs_gethostbyname ); return FALSE; } - - memset(psa,0,sizeof(struct sockaddr_in)); - memcpy((char *)&psa->sin_addr, phe->h_addr, phe->h_length); - psa->sin_family = phe->h_addrtype; - psa->sin_port = htons(nServerPort); + if (*sa_len < sizeof(struct sockaddr_in)) + { + WARN("address too small\n"); + LeaveCriticalSection( &cs_gethostbyname ); + return FALSE; + } + *sa_len = sizeof(struct sockaddr_in); + memset(sin,0,sizeof(struct sockaddr_in)); + memcpy((char *)&sin->sin_addr, phe->h_addr, phe->h_length); + sin->sin_family = phe->h_addrtype; + sin->sin_port = htons(nServerPort); LeaveCriticalSection( &cs_gethostbyname ); +#endif return TRUE; } @@ -224,7 +286,7 @@ static const char *get_callback_name(DWORD dwInternetStatus) { return "Unknown"; } -VOID INTERNET_SendCallback(LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext, +VOID INTERNET_SendCallback(object_header_t *hdr, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInfo, DWORD dwStatusInfoLength) { @@ -244,11 +306,11 @@ VOID INTERNET_SendCallback(LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext, case INTERNET_STATUS_NAME_RESOLVED: case INTERNET_STATUS_CONNECTING_TO_SERVER: case INTERNET_STATUS_CONNECTED_TO_SERVER: - lpvNewInfo = WININET_strdup_AtoW(lpvStatusInfo); + lpvNewInfo = heap_strdupAtoW(lpvStatusInfo); break; case INTERNET_STATUS_RESOLVING_NAME: case INTERNET_STATUS_REDIRECT: - lpvNewInfo = WININET_strdupW(lpvStatusInfo); + lpvNewInfo = heap_strdupW(lpvStatusInfo); break; } }else { @@ -262,7 +324,7 @@ VOID INTERNET_SendCallback(LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext, break; case INTERNET_STATUS_RESOLVING_NAME: case INTERNET_STATUS_REDIRECT: - lpvNewInfo = WININET_strdup_WtoA(lpvStatusInfo); + lpvNewInfo = heap_strdupWtoA(lpvStatusInfo); break; } } @@ -294,7 +356,7 @@ static void SendAsyncCallbackProc(WORKREQUEST *workRequest) HeapFree(GetProcessHeap(), 0, req->lpvStatusInfo); } -VOID SendAsyncCallback(LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext, +void SendAsyncCallback(object_header_t *hdr, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInfo, DWORD dwStatusInfoLength) { diff --git a/reactos/dll/win32/wininet/wininet.rbuild b/reactos/dll/win32/wininet/wininet.rbuild index 4a83d0b0ac4..45b87b18665 100644 --- a/reactos/dll/win32/wininet/wininet.rbuild +++ b/reactos/dll/win32/wininet/wininet.rbuild @@ -22,6 +22,7 @@ secur32 crypt32 ws2_32 + pseh cookie.c dialogs.c ftp.c diff --git a/reactos/dll/win32/wininet/wininet.spec b/reactos/dll/win32/wininet/wininet.spec index dfbc38c02fc..46dd04334e6 100644 --- a/reactos/dll/win32/wininet/wininet.spec +++ b/reactos/dll/win32/wininet/wininet.spec @@ -1,5 +1,5 @@ 101 stub -noname DoConnectoidsExist -102 stub -noname GetDiskInfoA +102 stdcall -noname GetDiskInfoA(str ptr ptr ptr) 103 stub -noname PerformOperationOverUrlCacheA 104 stub -noname HttpCheckDavComplianceA 105 stub -noname HttpCheckDavComplianceW @@ -9,7 +9,7 @@ 111 stub -noname ExportCookieFileW 112 stub -noname IsProfilesEnabled 116 stub -noname IsDomainlegalCookieDomainA -117 stub -noname IsDomainLegalCookieDomainW +117 stdcall -noname IsDomainLegalCookieDomainW(wstr wstr) 118 stub -noname FindP3PPolicySymbol 120 stub -noname MapResourceToPolicy 121 stub -noname GetP3PPolicy @@ -50,8 +50,8 @@ @ stdcall FindNextUrlCacheGroup(long ptr ptr) @ stub ForceNexusLookup @ stub ForceNexusLookupExW -@ stub FreeUrlCacheSpaceA -@ stub FreeUrlCacheSpaceW +@ stdcall FreeUrlCacheSpaceA(str long long) +@ stdcall FreeUrlCacheSpaceW(wstr long long) @ stdcall FtpCommandA(long long long str ptr ptr) @ stdcall FtpCommandW(long long long wstr ptr ptr) @ stdcall FtpCreateDirectoryA(ptr str) @@ -109,7 +109,7 @@ @ stdcall HttpSendRequestExA(long ptr ptr long long) @ stdcall HttpSendRequestExW(long ptr ptr long long) @ stdcall HttpSendRequestW(ptr wstr long ptr long) -@ stub IncrementUrlCacheHeaderData +@ stdcall IncrementUrlCacheHeaderData(long ptr) @ stub InternetAlgIdToStringA @ stub InternetAlgIdToStringW @ stdcall InternetAttemptConnect(long) @@ -213,10 +213,10 @@ @ stdcall IsUrlCacheEntryExpiredW(wstr long ptr) @ stub LoadUrlCacheContent @ stub ParseX509EncodedCertificateForListBoxEntry -@ stub PrivacyGetZonePreferenceW # (long long ptr ptr ptr) -@ stub PrivacySetZonePreferenceW # (long long long wstr) +@ stdcall PrivacyGetZonePreferenceW(long long ptr ptr ptr) +@ stdcall PrivacySetZonePreferenceW(long long long wstr) @ stdcall ReadUrlCacheEntryStream(ptr long ptr ptr long) -@ stub RegisterUrlCacheNotification +@ stdcall RegisterUrlCacheNotification(ptr long long long long long) @ stdcall ResumeSuspendedDownload(long long) @ stdcall RetrieveUrlCacheEntryFileA(str ptr ptr long) @ stdcall RetrieveUrlCacheEntryFileW(wstr ptr ptr long) diff --git a/reactos/dll/win32/wininet/wininet_Bg.rc b/reactos/dll/win32/wininet/wininet_Bg.rc index 52d797ed751..b25356e074e 100644 --- a/reactos/dll/win32/wininet/wininet_Bg.rc +++ b/reactos/dll/win32/wininet/wininet_Bg.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_BULGARIAN, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/reactos/dll/win32/wininet/wininet_Cs.rc b/reactos/dll/win32/wininet/wininet_Cs.rc index 9ca75397c4f..443c0175190 100644 --- a/reactos/dll/win32/wininet/wininet_Cs.rc +++ b/reactos/dll/win32/wininet/wininet_Cs.rc @@ -19,6 +19,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_CZECH, SUBLANG_DEFAULT /* Czech strings in CP1250 */ diff --git a/reactos/dll/win32/wininet/wininet_Da.rc b/reactos/dll/win32/wininet/wininet_Da.rc index 515dcabd8b3..6b37857ed54 100644 --- a/reactos/dll/win32/wininet/wininet_Da.rc +++ b/reactos/dll/win32/wininet/wininet_Da.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_DANISH, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/reactos/dll/win32/wininet/wininet_De.rc b/reactos/dll/win32/wininet/wininet_De.rc index 9fb6be58c8d..f602a97a97d 100644 --- a/reactos/dll/win32/wininet/wininet_De.rc +++ b/reactos/dll/win32/wininet/wininet_De.rc @@ -1,5 +1,6 @@ /* * Copyright 2004 Henning Gerhardt + * Copyright 2009 André Hentschel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,6 +17,10 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + +#pragma code_page(65001) + LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 @@ -25,8 +30,8 @@ FONT 8, "MS Shell Dlg" { LTEXT "Geben Sie Benutzernamen und Kennwort ein:", -1, 40, 6, 150, 15 LTEXT "Proxy", -1, 40, 26, 50, 10 - LTEXT "Realm", -1, 40, 46, 50, 10 - LTEXT "Ben&utzername", -1, 40, 66, 50, 10 + LTEXT "Bereich", -1, 40, 46, 50, 10 + LTEXT "Ben&utzer", -1, 40, 66, 50, 10 LTEXT "Kenn&wort", -1, 40, 86, 50, 10 LTEXT "" IDC_PROXY, 80, 26, 150, 14, 0 LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 @@ -38,6 +43,26 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "Abbrechen", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP } +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Benutzeranmeldung" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Geben Sie Benutzernamen und Kennwort ein:", -1, 40, 6, 150, 15 + LTEXT "Server", -1, 40, 26, 50, 10 + LTEXT "Bereich", -1, 40, 46, 50, 10 + LTEXT "Benutzer", -1, 40, 66, 50, 10 + LTEXT "Kennwort", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "Dieses &Kennwort speichern (unsicher)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Abbrechen", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "LAN Verbindung" diff --git a/reactos/dll/win32/wininet/wininet_En.rc b/reactos/dll/win32/wininet/wininet_En.rc index 66837dabc8e..d22d249f1cd 100644 --- a/reactos/dll/win32/wininet/wininet_En.rc +++ b/reactos/dll/win32/wininet/wininet_En.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 @@ -38,6 +40,26 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "Cancel", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP } +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Authentication Required" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Please enter your username and password:", -1, 40, 6, 150, 15 + LTEXT "Server", -1, 40, 26, 50, 10 + LTEXT "Realm", -1, 40, 46, 50, 10 + LTEXT "User", -1, 40, 66, 50, 10 + LTEXT "Password", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "&Save this password (insecure)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Cancel", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "LAN Connection" diff --git a/reactos/dll/win32/wininet/wininet_Eo.rc b/reactos/dll/win32/wininet/wininet_Eo.rc index a145e263621..3fa19f37897 100644 --- a/reactos/dll/win32/wininet/wininet_Eo.rc +++ b/reactos/dll/win32/wininet/wininet_Eo.rc @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_ESPERANTO, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/reactos/dll/win32/wininet/wininet_Es.rc b/reactos/dll/win32/wininet/wininet_Es.rc index bbf08aeb2f6..c9ce2cebbe2 100644 --- a/reactos/dll/win32/wininet/wininet_Es.rc +++ b/reactos/dll/win32/wininet/wininet_Es.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_SPANISH, SUBLANG_NEUTRAL IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/reactos/dll/win32/wininet/wininet_Fi.rc b/reactos/dll/win32/wininet/wininet_Fi.rc index 176a00337ce..df5ca723044 100644 --- a/reactos/dll/win32/wininet/wininet_Fi.rc +++ b/reactos/dll/win32/wininet/wininet_Fi.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_FINNISH, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/reactos/dll/win32/wininet/wininet_Fr.rc b/reactos/dll/win32/wininet/wininet_Fr.rc index 0435b8eb711..74ee208a7ee 100644 --- a/reactos/dll/win32/wininet/wininet_Fr.rc +++ b/reactos/dll/win32/wininet/wininet_Fr.rc @@ -3,8 +3,9 @@ * French language support * * Copyright 2003 Mike McCormack for CodeWeavers - * Copyright 2003 Vincent Béron + * Copyright 2003 Vincent Béron * Copyright 2005 Jonathan Ernst + * Copyright 2009 Frédéric Delanoy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -21,29 +22,54 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + +/* UTF-8 */ +#pragma code_page(65001) + LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL -IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 218, 150 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Entrez le mot de passe réseau" +CAPTION "Entrez le mot de passe réseau" FONT 8, "MS Shell Dlg" { - LTEXT "Entrez votre nom d'utilisateur et votre mot de passe :", -1, 40, 6, 150, 15 - LTEXT "Mandataire", -1, 40, 26, 50, 10 - LTEXT "Domaine", -1, 40, 46, 50, 10 - LTEXT "Utilisateur", -1, 40, 66, 50, 10 - LTEXT "Mot de passe", -1, 40, 86, 50, 10 - LTEXT "" IDC_PROXY, 80, 26, 150, 14, 0 - LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 - EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP - EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD - CHECKBOX "&Enregistrer ce mot de passe (risqué)", IDC_SAVEPASSWORD, - 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP - PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON - PUSHBUTTON "Annuler", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP + LTEXT "Entrez votre nom d'utilisateur et votre mot de passe :", -1, 10, 8, 173, 12 + LTEXT "Serveur mandataire", -1, 10, 28, 50, 17 + LTEXT "Domaine", -1, 10, 50, 50, 10 + LTEXT "Utilisateur", -1, 10, 71, 50, 10 + LTEXT "Mot de passe", -1, 10, 90, 50, 10 + LTEXT "" IDC_PROXY, 58, 28, 150, 14, 0 + LTEXT "" IDC_REALM, 58, 48, 150, 14, 0 + EDITTEXT IDC_USERNAME, 58, 68, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 58, 88, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "&Enregistrer ce mot de passe (risqué)", IDC_SAVEPASSWORD, + 58, 108, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 87, 128, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Annuler", IDCANCEL, 147, 128, 56, 14, WS_GROUP | WS_TABSTOP +} + +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 218, 150 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Authentification requise" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Entrez votre nom d'utilisateur et votre mot de passe :", -1, 10, 8, 173, 12 + LTEXT "Serveur", -1, 10, 28, 50, 17 + LTEXT "Domaine", -1, 10, 50, 50, 10 + LTEXT "Utilisateur", -1, 10, 71, 50, 10 + LTEXT "Mot de passe", -1, 10, 90, 50, 10 + LTEXT "" IDC_SERVER, 58, 28, 150, 14, 0 + LTEXT "" IDC_REALM, 58, 48, 150, 14, 0 + EDITTEXT IDC_USERNAME, 58, 68, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 58, 88, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "&Enregistrer ce mot de passe (risqué)", IDC_SAVEPASSWORD, + 58, 108, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 87, 128, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Annuler", IDCANCEL, 147, 128, 56, 14, WS_GROUP | WS_TABSTOP } STRINGTABLE DISCARDABLE { - IDS_LANCONNECTION "Connexion LAN" + IDS_LANCONNECTION "Connexion réseau local (LAN)" } diff --git a/reactos/dll/win32/wininet/wininet_Hu.rc b/reactos/dll/win32/wininet/wininet_Hu.rc index c9704f9080b..b19e03dc007 100644 --- a/reactos/dll/win32/wininet/wininet_Hu.rc +++ b/reactos/dll/win32/wininet/wininet_Hu.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_HUNGARIAN, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/reactos/dll/win32/wininet/wininet_It.rc b/reactos/dll/win32/wininet/wininet_It.rc index 45045460c33..04f71c5f177 100644 --- a/reactos/dll/win32/wininet/wininet_It.rc +++ b/reactos/dll/win32/wininet/wininet_It.rc @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_ITALIAN, SUBLANG_NEUTRAL IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 @@ -40,6 +42,26 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "Annulla", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP } +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Autenticazione richiesta" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Inserire il nome utente e la password:", -1, 40, 6, 150, 15 + LTEXT "Server", -1, 40, 26, 50, 10 + LTEXT "Realm", -1, 40, 46, 50, 10 + LTEXT "Utente", -1, 40, 66, 50, 10 + LTEXT "Password", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "&Memorizza la password (RISCHIOSO)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Annulla", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "Connessione LAN" diff --git a/reactos/dll/win32/wininet/wininet_Ja.rc b/reactos/dll/win32/wininet/wininet_Ja.rc index 615d7be1c86..e179b849254 100644 --- a/reactos/dll/win32/wininet/wininet_Ja.rc +++ b/reactos/dll/win32/wininet/wininet_Ja.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + /* UTF-8 */ #pragma code_page(65001) @@ -45,5 +47,3 @@ STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "LAN 接続" } - -#pragma code_page(default) diff --git a/reactos/dll/win32/wininet/wininet_Ko.rc b/reactos/dll/win32/wininet/wininet_Ko.rc index 26ed4a2fad2..5c2595a9b37 100644 --- a/reactos/dll/win32/wininet/wininet_Ko.rc +++ b/reactos/dll/win32/wininet/wininet_Ko.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/reactos/dll/win32/wininet/wininet_Lt.rc b/reactos/dll/win32/wininet/wininet_Lt.rc new file mode 100644 index 00000000000..cd4bf482e35 --- /dev/null +++ b/reactos/dll/win32/wininet/wininet_Lt.rc @@ -0,0 +1,69 @@ +/* + * Copyright 2009 Aurimas FiÅ¡eras + * + * 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 "resource.h" + +/* UTF-8 */ +#pragma code_page(65001) + +LANGUAGE LANG_LITHUANIAN, SUBLANG_NEUTRAL + +IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Ä®veskite tinklo slaptažodį" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Ä®veskite savo naudotojo vardÄ… ir slaptažodį:", -1, 40, 6, 150, 15 + LTEXT "Ä®galiot. serv.", -1, 40, 26, 50, 10 + LTEXT "Sritis", -1, 40, 46, 50, 10 + LTEXT "Naudotojas", -1, 40, 66, 50, 10 + LTEXT "Slaptažodis", -1, 40, 86, 50, 10 + LTEXT "" IDC_PROXY, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "Ä®&raÅ¡yti šį slaptažodį (nesaugu)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "Gerai", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Atsisakyti", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Reikalingas tapatumo nustatymas" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Ä®veskite savo naudotojo vardÄ… ir slaptažodį:", -1, 40, 6, 150, 15 + LTEXT "Serveris", -1, 40, 26, 50, 10 + LTEXT "Sritis", -1, 40, 46, 50, 10 + LTEXT "Naudotojas", -1, 40, 66, 50, 10 + LTEXT "Slaptažodis", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "Ä®&raÅ¡yti šį slaptažodį (nesaugu)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "Gerai", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Atsisakyti", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + +STRINGTABLE DISCARDABLE +{ + IDS_LANCONNECTION "Vietinio tinklo ryÅ¡ys" +} diff --git a/reactos/dll/win32/wininet/wininet_Nl.rc b/reactos/dll/win32/wininet/wininet_Nl.rc index 16c80ccaad8..f0e891c7e19 100644 --- a/reactos/dll/win32/wininet/wininet_Nl.rc +++ b/reactos/dll/win32/wininet/wininet_Nl.rc @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_DUTCH, SUBLANG_NEUTRAL IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 @@ -40,6 +42,26 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "Annuleren", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP } +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Authenticatie vereist" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Voer uw gebruikersnaam en wachtwoord in:", -1, 40, 6, 150, 15 + LTEXT "Server", -1, 40, 26, 50, 10 + LTEXT "Realm", -1, 40, 46, 50, 10 + LTEXT "Gebruikersnaam", -1, 40, 66, 50, 10 + LTEXT "Wachtwoord", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "&Wachtwoord opslaan (onveilig)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Annuleren", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "LAN Verbinding" diff --git a/reactos/dll/win32/wininet/wininet_No.rc b/reactos/dll/win32/wininet/wininet_No.rc index fb885e9030d..1dfa544e4aa 100644 --- a/reactos/dll/win32/wininet/wininet_No.rc +++ b/reactos/dll/win32/wininet/wininet_No.rc @@ -1,5 +1,5 @@ /* - * Copyright 2005 Alexander N. Sørnes + * Copyright 2005-2009 Alexander N. Sørnes * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,6 +16,10 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + +#pragma code_page(65001) + LANGUAGE LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 @@ -25,7 +29,7 @@ FONT 8, "MS Shell Dlg" { LTEXT "Skriv inn brukernavnet og passordet ditt:", -1, 40, 6, 150, 15 LTEXT "Mellomtjener", -1, 40, 26, 50, 10 - LTEXT "Område", -1, 40, 46, 50, 10 + LTEXT "OmrÃ¥de", -1, 40, 46, 50, 10 LTEXT "Bruker", -1, 40, 66, 50, 10 LTEXT "Passord", -1, 40, 86, 50, 10 LTEXT "" IDC_PROXY, 80, 26, 150, 14, 0 @@ -38,6 +42,26 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "Avbryt", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP } +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "PÃ¥logging" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Oppgi brukernavn og passord:", -1, 40, 6, 150, 15 + LTEXT "Tjener", -1, 40, 26, 50, 10 + LTEXT "OmrÃ¥de", -1, 40, 46, 50, 10 + LTEXT "Bruker", -1, 40, 66, 50, 10 + LTEXT "Passord", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "Lagre pa&ssordet (sikkerhetsrisiko)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Avbryt", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "Lokal nettverksforbindelse" diff --git a/reactos/dll/win32/wininet/wininet_Pl.rc b/reactos/dll/win32/wininet/wininet_Pl.rc index 7ddb399a584..0c76d5335aa 100644 --- a/reactos/dll/win32/wininet/wininet_Pl.rc +++ b/reactos/dll/win32/wininet/wininet_Pl.rc @@ -17,6 +17,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_POLISH, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/reactos/dll/win32/wininet/wininet_Pt.rc b/reactos/dll/win32/wininet/wininet_Pt.rc index 57dd625a740..95e06e6d6e8 100644 --- a/reactos/dll/win32/wininet/wininet_Pt.rc +++ b/reactos/dll/win32/wininet/wininet_Pt.rc @@ -1,6 +1,7 @@ /* * Copyright 2003 Marcelo Duarte - * Copyright 2006-2007 Américo José Melo + * Copyright 2006-2007 Américo José Melo + * Copyright 2009 Ricardo Filipe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,6 +18,10 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + +#pragma code_page(65001) + LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 @@ -24,10 +29,10 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Entrar Senha da Rede" FONT 8, "MS Shell Dlg" { - LTEXT "Por favor, entre com o nome de usuário e a senha:", -1, 40, 6, 150, 15 + LTEXT "Por favor, entre com o nome de usuário e a senha:", -1, 40, 6, 150, 15 LTEXT "Proxy", -1, 40, 26, 50, 10 LTEXT "Realm", -1, 40, 46, 50, 10 - LTEXT "Usuário", -1, 40, 66, 50, 10 + LTEXT "Usuário", -1, 40, 66, 50, 10 LTEXT "Senha", -1, 40, 86, 50, 10 LTEXT "" IDC_PROXY, 80, 26, 150, 14, 0 LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 @@ -61,17 +66,36 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "Cancelar", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP } +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Autenticação necessária" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Por favor insira o seu nome de utilizador e palavra-passe:", -1, 40, 6, 150, 15 + LTEXT "Servidor", -1, 40, 26, 50, 10 + LTEXT "Reino", -1, 40, 46, 50, 10 + LTEXT "Utilizador", -1, 40, 66, 50, 10 + LTEXT "Palavra-passe", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "&Guardar esta palavra-passe (inseguro)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Cancelar", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN STRINGTABLE DISCARDABLE { - IDS_LANCONNECTION "Conexão LAN" + IDS_LANCONNECTION "Conexão LAN" } LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE STRINGTABLE DISCARDABLE { - IDS_LANCONNECTION "Ligação LAN" + IDS_LANCONNECTION "Ligação LAN" } diff --git a/reactos/dll/win32/wininet/wininet_Ro.rc b/reactos/dll/win32/wininet/wininet_Ro.rc index 367bbb5955a..13403eec1a6 100644 --- a/reactos/dll/win32/wininet/wininet_Ro.rc +++ b/reactos/dll/win32/wininet/wininet_Ro.rc @@ -17,6 +17,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_ROMANIAN, SUBLANG_NEUTRAL #pragma code_page(65001) @@ -28,7 +30,7 @@ FONT 8, "MS Shell Dlg" { LTEXT "IntroduceÈ›i numele de utilizator È™i parola:", -1, 40, 6, 150, 15 LTEXT "Proxy", -1, 40, 26, 50, 10 - LTEXT "Realm", -1, 40, 46, 50, 10 + LTEXT "Domeniu", -1, 40, 46, 50, 10 LTEXT "Utilizator", -1, 40, 66, 50, 10 LTEXT "Parolă", -1, 40, 86, 50, 10 LTEXT "" IDC_PROXY, 80, 26, 150, 14, 0 @@ -41,9 +43,27 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "Renunță", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP } +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Autentificare necesară" +FONT 8, "MS Shell Dlg" +{ + LTEXT "IntroduceÈ›i numele de utilizator È™i parola:", -1, 40, 6, 150, 15 + LTEXT "Server", -1, 40, 26, 50, 10 + LTEXT "Domeniu", -1, 40, 46, 50, 10 + LTEXT "Utilizator", -1, 40, 66, 50, 10 + LTEXT "Parolă", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "&Salvează această parolă (nesigur)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Renunță", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "Conexiune LAN" } - -#pragma code_page(default) diff --git a/reactos/dll/win32/wininet/wininet_Ru.rc b/reactos/dll/win32/wininet/wininet_Ru.rc index d75985ba1b7..8d35fe40aab 100644 --- a/reactos/dll/win32/wininet/wininet_Ru.rc +++ b/reactos/dll/win32/wininet/wininet_Ru.rc @@ -18,29 +18,54 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + +/* UTF-8 */ +#pragma code_page(65001) + LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Ââîä ñåòåâîãî ïàðîëÿ" +CAPTION "Ввод Ñетевого паролÑ" FONT 8, "MS Shell Dlg" { - LTEXT "Ââåäèòå èìÿ ïîëüçîâàòåëÿ è ïàðîëü:", -1, 40, 6, 150, 15 - LTEXT "Ïðîêñè", -1, 40, 26, 50, 10 - LTEXT "Äîìåí", -1, 40, 46, 50, 10 - LTEXT "Ïîëüçîâàòåëü", -1, 40, 66, 50, 10 - LTEXT "Ïàðîëü", -1, 40, 86, 50, 10 + LTEXT "Введите Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸ пароль:", -1, 40, 6, 150, 15 + LTEXT "ПрокÑи", -1, 40, 26, 50, 10 + LTEXT "Домен", -1, 40, 46, 50, 10 + LTEXT "Пользователь", -1, 40, 66, 50, 10 + LTEXT "Пароль", -1, 40, 86, 50, 10 LTEXT "" IDC_PROXY, 80, 26, 150, 14, 0 LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD - CHECKBOX "&Ñîõðàíèòü ýòîò ïàðîëü (íåáåçîïàñíî)", IDC_SAVEPASSWORD, + CHECKBOX "&Сохранить Ñтот пароль (небезопаÑно)", IDC_SAVEPASSWORD, 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON - PUSHBUTTON "Îòìåíà", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP + PUSHBUTTON "Отмена", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "ТребуетÑÑ Ð¸Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Введите Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸ пароль:", -1, 40, 6, 150, 15 + LTEXT "Сервер", -1, 40, 26, 50, 10 + LTEXT "Домен", -1, 40, 46, 50, 10 + LTEXT "Пользователь", -1, 40, 66, 50, 10 + LTEXT "Пароль", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "&Сохранить Ñтот пароль (небезопаÑно)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Отмена", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP } STRINGTABLE DISCARDABLE { - IDS_LANCONNECTION "Ñåòåâîå ïîäêëþ÷åíèå" + IDS_LANCONNECTION "Сетевое подключение" } diff --git a/reactos/dll/win32/wininet/wininet_Si.rc b/reactos/dll/win32/wininet/wininet_Si.rc index 93ac9e1f33b..b5bf2914328 100644 --- a/reactos/dll/win32/wininet/wininet_Si.rc +++ b/reactos/dll/win32/wininet/wininet_Si.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + #pragma code_page(65001) LANGUAGE LANG_SLOVENIAN, SUBLANG_DEFAULT @@ -44,5 +46,3 @@ STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "LAN povezava" } - -#pragma code_page(default) diff --git a/reactos/dll/win32/wininet/wininet_Sv.rc b/reactos/dll/win32/wininet/wininet_Sv.rc index 6d71f2ef842..8d3291ec750 100644 --- a/reactos/dll/win32/wininet/wininet_Sv.rc +++ b/reactos/dll/win32/wininet/wininet_Sv.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_SWEDISH, SUBLANG_NEUTRAL IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/reactos/dll/win32/wininet/wininet_Tr.rc b/reactos/dll/win32/wininet/wininet_Tr.rc index dd796777236..8d26cf21694 100644 --- a/reactos/dll/win32/wininet/wininet_Tr.rc +++ b/reactos/dll/win32/wininet/wininet_Tr.rc @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_TURKISH, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/reactos/dll/win32/wininet/wininet_Uk.rc b/reactos/dll/win32/wininet/wininet_Uk.rc index be58bb621f2..94a9611888b 100644 --- a/reactos/dll/win32/wininet/wininet_Uk.rc +++ b/reactos/dll/win32/wininet/wininet_Uk.rc @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_UKRAINIAN, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/reactos/dll/win32/wininet/wininet_Zh.rc b/reactos/dll/win32/wininet/wininet_Zh.rc index 4406bd87c1a..e2e36ded277 100644 --- a/reactos/dll/win32/wininet/wininet_Zh.rc +++ b/reactos/dll/win32/wininet/wininet_Zh.rc @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + /* Chinese text is encoded in UTF-8 */ #pragma code_page(65001) @@ -74,5 +76,3 @@ STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "局域網連接" } - -#pragma code_page(default) From e5956bc6938c8232e8ee3614eb667320c7f156c4 Mon Sep 17 00:00:00 2001 From: Christoph von Wittich Date: Mon, 15 Mar 2010 11:45:17 +0000 Subject: [PATCH 24/61] [FAULTREP] import faultrep.dll from wine 1.1.40 svn path=/trunk/; revision=46203 --- reactos/baseaddress.rbuild | 1 + reactos/boot/bootdata/packages/reactos.dff | 1 + reactos/dll/win32/faultrep/faultrep.c | 130 +++++++++++++++++++++ reactos/dll/win32/faultrep/faultrep.rbuild | 9 ++ reactos/dll/win32/faultrep/faultrep.spec | 14 +++ reactos/dll/win32/win32.rbuild | 3 + 6 files changed, 158 insertions(+) create mode 100644 reactos/dll/win32/faultrep/faultrep.c create mode 100644 reactos/dll/win32/faultrep/faultrep.rbuild create mode 100644 reactos/dll/win32/faultrep/faultrep.spec diff --git a/reactos/baseaddress.rbuild b/reactos/baseaddress.rbuild index 6099bf8c332..cacc80f77f3 100644 --- a/reactos/baseaddress.rbuild +++ b/reactos/baseaddress.rbuild @@ -3,6 +3,7 @@ + diff --git a/reactos/boot/bootdata/packages/reactos.dff b/reactos/boot/bootdata/packages/reactos.dff index e5fb874f849..75db78068b1 100644 --- a/reactos/boot/bootdata/packages/reactos.dff +++ b/reactos/boot/bootdata/packages/reactos.dff @@ -286,6 +286,7 @@ dll\win32\dwmapi\dwmapi.dll 1 dll\win32\devmgr\devmgr.dll 1 dll\win32\dhcpcsvc\dhcpcsvc.dll 1 dll\win32\dnsapi\dnsapi.dll 1 +dll\win32\faultrep\faultrep.dll 1 dll\win32\fmifs\fmifs.dll 1 dll\win32\fusion\fusion.dll 1 dll\win32\gdi32\gdi32.dll 1 diff --git a/reactos/dll/win32/faultrep/faultrep.c b/reactos/dll/win32/faultrep/faultrep.c new file mode 100644 index 00000000000..d4bd7131bbb --- /dev/null +++ b/reactos/dll/win32/faultrep/faultrep.c @@ -0,0 +1,130 @@ +/* Fault report handling + * + * Copyright 2007 Peter Dons Tychsen + * + * 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 + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "winreg.h" +#include "wine/debug.h" +#include "wine/unicode.h" + +#include "errorrep.h" + +WINE_DEFAULT_DEBUG_CHANNEL(faultrep); + +static const WCHAR SZ_EXCLUSIONLIST_KEY[] = { + 'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\', + 'P','C','H','e','a','l','t','h','\\', + 'E','r','r','o','r','R','e','p','o','r','t','i','n','g','\\', + 'E','x','c','l','u','s','i','o','n','L','i','s','t', 0}; + +/************************************************************************* + * AddERExcludedApplicationW [FAULTREP.@] + * + * Adds an application to a list of applications for which fault reports + * shouldn't be generated + * + * PARAMS + * lpAppFileName [I] The filename of the application executable + * + * RETURNS + * TRUE on success, FALSE of failure + * + * NOTES + * Wine doesn't use this data but stores it in the registry (in the same place + * as Windows would) in case it will be useful in a future version + * + * According to MSDN this function should succeed even if the user has no write + * access to HKLM. This probably means that there is no error checking. + */ +BOOL WINAPI AddERExcludedApplicationW(LPCWSTR lpAppFileName) +{ + WCHAR *bslash; + DWORD value = 1; + HKEY hkey; + + TRACE("(%s)\n", wine_dbgstr_w(lpAppFileName)); + bslash = strrchrW(lpAppFileName, '\\'); + if (bslash != NULL) + lpAppFileName = bslash + 1; + if (*lpAppFileName == '\0') + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (!RegCreateKeyW(HKEY_LOCAL_MACHINE, SZ_EXCLUSIONLIST_KEY, &hkey)) + { + RegSetValueExW(hkey, lpAppFileName, 0, REG_DWORD, (LPBYTE)&value, sizeof(value)); + RegCloseKey(hkey); + } + + return TRUE; +} + +/************************************************************************* + * AddERExcludedApplicationA [FAULTREP.@] + * + * See AddERExcludedApplicationW + */ +BOOL WINAPI AddERExcludedApplicationA(LPCSTR lpAppFileName) +{ + int len = MultiByteToWideChar(CP_ACP, 0, lpAppFileName, -1, NULL, 0); + WCHAR *wstr; + BOOL ret; + + TRACE("(%s)\n", wine_dbgstr_a(lpAppFileName)); + if (len == 0) + return FALSE; + wstr = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len); + MultiByteToWideChar(CP_ACP, 0, lpAppFileName, -1, wstr, len); + ret = AddERExcludedApplicationW(wstr); + HeapFree(GetProcessHeap(), 0, wstr); + return ret; +} + +/************************************************************************* + * ReportFault [FAULTREP.@] + */ +EFaultRepRetVal WINAPI ReportFault(LPEXCEPTION_POINTERS pep, DWORD dwOpt) +{ + FIXME("%p 0x%x stub\n", pep, dwOpt); + return frrvOk; +} + +/*********************************************************************** + * DllMain. + */ +BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved) +{ + switch(reason) + { + case DLL_WINE_PREATTACH: + return FALSE; + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(inst); + break; + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} diff --git a/reactos/dll/win32/faultrep/faultrep.rbuild b/reactos/dll/win32/faultrep/faultrep.rbuild new file mode 100644 index 00000000000..aeeb3afeca5 --- /dev/null +++ b/reactos/dll/win32/faultrep/faultrep.rbuild @@ -0,0 +1,9 @@ + + + . + include/reactos/wine + + wine + advapi32 + faultrep.c + diff --git a/reactos/dll/win32/faultrep/faultrep.spec b/reactos/dll/win32/faultrep/faultrep.spec new file mode 100644 index 00000000000..77e543fa779 --- /dev/null +++ b/reactos/dll/win32/faultrep/faultrep.spec @@ -0,0 +1,14 @@ +@ stdcall AddERExcludedApplicationA(str) +@ stdcall AddERExcludedApplicationW(wstr) +@ stub CreateMinidumpA +@ stub CreateMinidumpW +@ stub ReportEREvent +@ stub ReportEREventDW +@ stdcall ReportFault(ptr long) +@ stub ReportFaultDWM +@ stub ReportFaultFromQueue +@ stub ReportFaultToQueue +@ stub ReportHang +@ stub ReportKernelFaultA +@ stub ReportKernelFaultDWW +@ stub ReportKernelFaultW diff --git a/reactos/dll/win32/win32.rbuild b/reactos/dll/win32/win32.rbuild index c68742612de..9ff3319d54f 100644 --- a/reactos/dll/win32/win32.rbuild +++ b/reactos/dll/win32/win32.rbuild @@ -103,6 +103,9 @@ + + + From 7754d319f36adb993b109d8d6443d7ef1a201fb8 Mon Sep 17 00:00:00 2001 From: Dmitry Gorbachev Date: Mon, 15 Mar 2010 12:40:57 +0000 Subject: [PATCH 25/61] =?UTF-8?q?Update=20Firefox=203=20URLs.=20Maciej=20B?= =?UTF-8?q?ia=C5=82as,=20bug=20#5251.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit svn path=/trunk/; revision=46204 --- reactos/base/applications/rapps/rapps/firefox3.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/reactos/base/applications/rapps/rapps/firefox3.txt b/reactos/base/applications/rapps/rapps/firefox3.txt index d4d2272179a..072eee6407b 100644 --- a/reactos/base/applications/rapps/rapps/firefox3.txt +++ b/reactos/base/applications/rapps/rapps/firefox3.txt @@ -8,35 +8,35 @@ Description = The most popular and one of the best free Web Browsers out there. Size = 7.1M Category = 5 URLSite = http://www.mozilla.com/en-US/ -URLDownload = http://releases.mozilla.org/pub/mozilla.org/firefox/releases/latest-3.0/win32/en-US/Firefox%20Setup%203.0.17.exe +URLDownload = http://releases.mozilla.org/pub/mozilla.org/firefox/releases/latest-3.0/win32/en-US/Firefox%20Setup%203.0.18.exe CDPath = none [Section.0407] Description = Der populärste und einer der besten freien Webbrowser. Size = 6.9M URLSite = http://www.mozilla-europe.org/de/ -URLDownload = http://releases.mozilla.org/pub/mozilla.org/firefox/releases/latest-3.0/win32/de/Firefox%20Setup%203.0.17.exe +URLDownload = http://releases.mozilla.org/pub/mozilla.org/firefox/releases/latest-3.0/win32/de/Firefox%20Setup%203.0.18.exe [Section.040a] Description = El más popular y uno de los mejores navegadores web gratuitos que hay. Size = 7.0M URLSite = http://www.mozilla-europe.org/es/ -URLDownload = http://releases.mozilla.org/pub/mozilla.org/firefox/releases/latest-3.0/win32/es-ES/Firefox%20Setup%203.0.17.exe +URLDownload = http://releases.mozilla.org/pub/mozilla.org/firefox/releases/latest-3.0/win32/es-ES/Firefox%20Setup%203.0.18.exe [Section.0414] Description = Mest populære og best ogsÃ¥ gratis nettleserene der ute. Size = 6.9M URLSite = http://www.mozilla-europe.org/no/ -URLDownload = http://releases.mozilla.org/pub/mozilla.org/firefox/releases/latest-3.0/win32/nb-NO/Firefox%20Setup%203.0.17.exe +URLDownload = http://releases.mozilla.org/pub/mozilla.org/firefox/releases/latest-3.0/win32/nb-NO/Firefox%20Setup%203.0.18.exe [Section.0415] Description = Najpopularniejsza i jedna z najlepszych darmowych przeglÄ…darek internetowych. Size = 7.8M URLSite = http://www.mozilla-europe.org/pl/ -URLDownload = http://releases.mozilla.org/pub/mozilla.org/firefox/releases/latest-3.0/win32/pl/Firefox%20Setup%203.0.17.exe +URLDownload = http://releases.mozilla.org/pub/mozilla.org/firefox/releases/latest-3.0/win32/pl/Firefox%20Setup%203.0.18.exe [Section.0419] Description = Один из Ñамых популÑрных и лучших беÑплатных браузеров. Size = 7.4M URLSite = http://www.mozilla-europe.org/ru/ -URLDownload = http://releases.mozilla.org/pub/mozilla.org/firefox/releases/latest-3.0/win32/ru/Firefox%20Setup%203.0.17.exe +URLDownload = http://releases.mozilla.org/pub/mozilla.org/firefox/releases/latest-3.0/win32/ru/Firefox%20Setup%203.0.18.exe From 59b9f20eeeba2fa1c592deb7cf441c68b00eba9c Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Mon, 15 Mar 2010 13:11:31 +0000 Subject: [PATCH 26/61] [KSPROXY] - Implement ISpecifyPropertyPages interface for CInputPin - Implement IKsInterfaceHandler::KsSetPin, IKsInterfaceHandler::KsProcessMediaSamples, IKsInterfaceHandler::KsCompleteIo svn path=/trunk/; revision=46205 --- reactos/dll/directx/ksproxy/input_pin.cpp | 31 +- reactos/dll/directx/ksproxy/interface.cpp | 384 +++++++++++++++++++++- reactos/dll/directx/ksproxy/precomp.h | 1 + 3 files changed, 395 insertions(+), 21 deletions(-) diff --git a/reactos/dll/directx/ksproxy/input_pin.cpp b/reactos/dll/directx/ksproxy/input_pin.cpp index 857b3cc687e..e922b2e156a 100644 --- a/reactos/dll/directx/ksproxy/input_pin.cpp +++ b/reactos/dll/directx/ksproxy/input_pin.cpp @@ -52,11 +52,11 @@ class CInputPin : public IPin, public IKsControl, public IKsObject, public IKsPinEx, - public IMemInputPin + public IMemInputPin, + public ISpecifyPropertyPages /* public IQualityControl, public IKsPinPipe, - public ISpecifyPropertyPages, public IStreamBuilder, public IKsPinFactory, public IKsAggregateControl @@ -98,6 +98,9 @@ public: HRESULT STDMETHODCALLTYPE EndFlush(); HRESULT STDMETHODCALLTYPE NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + // ISpecifyPropertyPages + HRESULT STDMETHODCALLTYPE GetPages(CAUUID *pPages); + //IKsObject methods HANDLE STDMETHODCALLTYPE KsGetObjectHandle(); @@ -205,7 +208,12 @@ CInputPin::QueryInterface( reinterpret_cast(*Output)->AddRef(); return NOERROR; } - + else if (IsEqualGUID(refiid, IID_ISpecifyPropertyPages)) + { + *Output = (ISpecifyPropertyPages*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } WCHAR Buffer[MAX_PATH]; LPOLESTR lpstr; @@ -217,6 +225,23 @@ CInputPin::QueryInterface( return E_NOINTERFACE; } +//------------------------------------------------------------------- +// ISpecifyPropertyPages +// + +HRESULT +STDMETHODCALLTYPE +CInputPin::GetPages(CAUUID *pPages) +{ + if (!pPages) + return E_POINTER; + + pPages->cElems = 0; + pPages->pElems = NULL; + + return S_OK; +} + //------------------------------------------------------------------- // IMemInputPin // diff --git a/reactos/dll/directx/ksproxy/interface.cpp b/reactos/dll/directx/ksproxy/interface.cpp index 4289cd1fc11..7b6b0d9961b 100644 --- a/reactos/dll/directx/ksproxy/interface.cpp +++ b/reactos/dll/directx/ksproxy/interface.cpp @@ -35,14 +35,27 @@ public: HRESULT STDMETHODCALLTYPE KsProcessMediaSamples(IKsDataTypeHandler *KsDataTypeHandler, IMediaSample** SampleList, PLONG SampleCount, KSIOOPERATION IoOperation, PKSSTREAM_SEGMENT *StreamSegment); HRESULT STDMETHODCALLTYPE KsCompleteIo(PKSSTREAM_SEGMENT StreamSegment); - CKsInterfaceHandler() : m_Ref(0), m_Handle(NULL){}; + CKsInterfaceHandler() : m_Ref(0), m_Handle(NULL), m_Pin(0){}; virtual ~CKsInterfaceHandler(){}; protected: LONG m_Ref; HANDLE m_Handle; + IKsPinEx * m_Pin; }; +typedef struct +{ + KSSTREAM_SEGMENT StreamSegment; + IMediaSample * MediaSample[64]; + + ULONG SampleCount; + ULONG ExtendedSize; + PKSSTREAM_HEADER StreamHeader; + OVERLAPPED Overlapped; +}KSSTREAM_SEGMENT_EXT, *PKSSTREAM_SEGMENT_EXT; + + HRESULT STDMETHODCALLTYPE CKsInterfaceHandler::QueryInterface( @@ -66,22 +79,43 @@ CKsInterfaceHandler::KsSetPin( { HRESULT hr; IKsObject * KsObject; + IKsPinEx * Pin; - // check if IKsObject is supported - hr = KsPin->QueryInterface(IID_IKsObject, (void**)&KsObject); - + // get IKsPinEx interface + hr = KsPin->QueryInterface(IID_IKsPinEx, (void**)&Pin); if (SUCCEEDED(hr)) { - // get pin handle - m_Handle = KsObject->KsGetObjectHandle(); + // check if IKsObject is supported + hr = KsPin->QueryInterface(IID_IKsObject, (void**)&KsObject); - // release IKsObject interface - KsObject->Release(); - - if (!m_Handle) + if (SUCCEEDED(hr)) { - // expected a file handle - return E_UNEXPECTED; + // get pin handle + m_Handle = KsObject->KsGetObjectHandle(); + + // release IKsObject interface + KsObject->Release(); + + if (!m_Handle) + { + // expected a file handle + hr = E_UNEXPECTED; + Pin->Release(); + } + else + { + if (m_Pin) + { + // release old interface + m_Pin->Release(); + } + m_Pin = Pin; + } + } + else + { + //release IKsPinEx interface + Pin->Release(); } } @@ -96,19 +130,333 @@ CKsInterfaceHandler::KsProcessMediaSamples( IMediaSample** SampleList, PLONG SampleCount, KSIOOPERATION IoOperation, - PKSSTREAM_SEGMENT *StreamSegment) + PKSSTREAM_SEGMENT *OutStreamSegment) { - OutputDebugString("UNIMPLEMENTED\n"); - return E_NOTIMPL; + PKSSTREAM_SEGMENT_EXT StreamSegment; + ULONG ExtendedSize, Index, BytesReturned; + HRESULT hr = S_OK; + + OutputDebugString("CKsInterfaceHandler::KsProcessMediaSamples\n"); + + // sanity check + assert(*SampleCount); + + if (*SampleCount == 0 || *SampleCount < 0) + return E_FAIL; + + // zero stream segment + *OutStreamSegment = NULL; + + // allocate stream segment + StreamSegment = (PKSSTREAM_SEGMENT_EXT)CoTaskMemAlloc(sizeof(KSSTREAM_SEGMENT_EXT)); + if (!StreamSegment) + return E_OUTOFMEMORY; + + // zero stream segment + ZeroMemory(StreamSegment, sizeof(KSSTREAM_SEGMENT_EXT)); + + //allocate event + StreamSegment->StreamSegment.CompletionEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + if (!StreamSegment->StreamSegment.CompletionEvent) + { + // failed to create event + CoTaskMemFree(StreamSegment); + return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError()); + } + + // increase our own reference count + AddRef(); + + // setup stream segment + StreamSegment->StreamSegment.KsDataTypeHandler = KsDataTypeHandler; + StreamSegment->StreamSegment.KsInterfaceHandler = (IKsInterfaceHandler*)this; + StreamSegment->StreamSegment.IoOperation = IoOperation; + StreamSegment->Overlapped.hEvent = StreamSegment->StreamSegment.CompletionEvent; + + + // ge extension size + ExtendedSize = 0; + if (KsDataTypeHandler) + { + // query extension size + KsDataTypeHandler->KsQueryExtendedSize(&ExtendedSize); + + if (ExtendedSize) + { + // increment reference count + KsDataTypeHandler->AddRef(); + } + else + { + // no need for the datatype handler + StreamSegment->StreamSegment.KsDataTypeHandler = NULL; + } + } + + StreamSegment->ExtendedSize = ExtendedSize; + StreamSegment->SampleCount = (ULONG)*SampleCount; + + // calculate stream header size count + ULONG StreamHeaderSize = StreamSegment->SampleCount * (sizeof(KSSTREAM_HEADER) + ExtendedSize); + + // allocate stream header + StreamSegment->StreamHeader = (PKSSTREAM_HEADER)CoTaskMemAlloc(StreamHeaderSize); + if (!StreamSegment->StreamHeader) + { + // not enough memory + CloseHandle(StreamSegment->StreamSegment.CompletionEvent); + + if (StreamSegment->StreamSegment.KsDataTypeHandler) + StreamSegment->StreamSegment.KsDataTypeHandler->Release(); + + // free stream segment + CoTaskMemFree(StreamSegment); + + //release our reference count + Release(); + return E_OUTOFMEMORY; + } + + // zero stream headers + ZeroMemory(StreamSegment->StreamHeader, StreamHeaderSize); + + PKSSTREAM_HEADER CurStreamHeader = StreamSegment->StreamHeader; + + // initialize all stream headers + for(Index = 0; Index < StreamSegment->SampleCount; Index++) + { + if (ExtendedSize) + { + // initialize extended size + hr = KsDataTypeHandler->KsPrepareIoOperation(SampleList[Index], (CurStreamHeader + 1), IoOperation); + // sanity check + assert(hr == NOERROR); + } + + // query for IMediaSample2 interface + IMediaSample2 * MediaSample; + AM_SAMPLE2_PROPERTIES Properties; + + hr = SampleList[Index]->QueryInterface(IID_IMediaSample2, (void**)&MediaSample); + if (SUCCEEDED(hr)) + { + //get properties + + hr = MediaSample->GetProperties(sizeof(AM_SAMPLE2_PROPERTIES), (BYTE*)&Properties); + + //release IMediaSample2 interface + MediaSample->Release(); + if (FAILED(hr)) + OutputDebugStringW(L"CKsInterfaceHandler::KsProcessMediaSamples MediaSample::GetProperties failed\n"); + } + else + { + OutputDebugStringW(L"CKsInterfaceHandler::KsProcessMediaSamples MediaSample:: only IMediaSample supported\n"); + // get properties + hr = SampleList[Index]->GetPointer((BYTE**)&Properties.pbBuffer); + assert(hr == NOERROR); + hr = SampleList[Index]->GetTime(&Properties.tStart, &Properties.tStop); + assert(hr == NOERROR); + + Properties.dwSampleFlags = 0; + + if (SampleList[Index]->IsDiscontinuity() == S_OK) + Properties.dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY; + + if (SampleList[Index]->IsPreroll() == S_OK) + Properties.dwSampleFlags |= AM_SAMPLE_PREROLL; + + if (SampleList[Index]->IsSyncPoint() == S_OK) + Properties.dwSampleFlags |= AM_SAMPLE_SPLICEPOINT; + } + + WCHAR Buffer[100]; + swprintf(Buffer, L"BufferLength %lu Property Buffer %p ExtendedSize %u lActual %u\n", Properties.cbBuffer, Properties.pbBuffer, ExtendedSize, Properties.lActual); + OutputDebugStringW(Buffer); + + CurStreamHeader->Size = sizeof(KSSTREAM_HEADER) + ExtendedSize; + CurStreamHeader->PresentationTime.Denominator = 1; + CurStreamHeader->PresentationTime.Numerator = 1; + CurStreamHeader->FrameExtent = Properties.cbBuffer; + CurStreamHeader->Data = Properties.pbBuffer; + + if (IoOperation == KsIoOperation_Write) + { + // set flags + CurStreamHeader->OptionsFlags = Properties.dwSampleFlags; + CurStreamHeader->DataUsed = Properties.lActual; + // increment reference count + SampleList[Index]->AddRef(); + } + + // store sample in stream segment + StreamSegment->MediaSample[Index] = SampleList[Index]; + + // move to next header + CurStreamHeader = (PKSSTREAM_HEADER)((ULONG_PTR)CurStreamHeader + CurStreamHeader->Size); + } + + // submit to device + m_Pin->KsIncrementPendingIoCount(); + + if (DeviceIoControl(m_Handle, + IoOperation == KsIoOperation_Write ? IOCTL_KS_WRITE_STREAM : IOCTL_KS_READ_STREAM, + NULL, 0, + StreamSegment->StreamHeader, + StreamHeaderSize, + &BytesReturned, + &StreamSegment->Overlapped)) + { + // signal completion + SetEvent(StreamSegment->StreamSegment.CompletionEvent); + hr = S_OK; + *OutStreamSegment = (PKSSTREAM_SEGMENT)StreamSegment; + } + else + { + if (GetLastError() == ERROR_IO_PENDING) + { + *OutStreamSegment = (PKSSTREAM_SEGMENT)StreamSegment; + hr = S_OK; + } + } + return hr; } HRESULT STDMETHODCALLTYPE CKsInterfaceHandler::KsCompleteIo( - PKSSTREAM_SEGMENT StreamSegment) + PKSSTREAM_SEGMENT InStreamSegment) { - OutputDebugString("UNIMPLEMENTED\n"); - return E_NOTIMPL; + PKSSTREAM_SEGMENT_EXT StreamSegment; + PKSSTREAM_HEADER CurStreamHeader; + DWORD dwError = ERROR_SUCCESS, BytesReturned; + BOOL bOverlapped; + ULONG Index; + HRESULT hr; + IMediaSample2 * MediaSample; + AM_SAMPLE2_PROPERTIES Properties; + REFERENCE_TIME Start, Stop; + + OutputDebugStringW(L"CKsInterfaceHandler::KsCompleteIo\n"); + + // get private stream segment + StreamSegment = (PKSSTREAM_SEGMENT_EXT)InStreamSegment; + + // get result + bOverlapped = GetOverlappedResult(m_Handle, &StreamSegment->Overlapped, &BytesReturned, FALSE); + dwError = GetLastError(); + + CurStreamHeader = StreamSegment->StreamHeader; + + //iterate through all stream headers + for(Index = 0; Index < StreamSegment->SampleCount; Index++) + { + if (!bOverlapped) + { + // operation failed + m_Pin->KsNotifyError(StreamSegment->MediaSample[Index], MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwError)); + } + + // query IMediaSample2 interface + hr = StreamSegment->MediaSample[Index]->QueryInterface(IID_IMediaSample2, (void**)&MediaSample); + if (SUCCEEDED(hr)) + { + // media sample properties + hr = MediaSample->GetProperties(sizeof(AM_SAMPLE2_PROPERTIES), (BYTE*)&Properties); + if (SUCCEEDED(hr)) + { + //update media sample properties + Properties.dwTypeSpecificFlags = CurStreamHeader->TypeSpecificFlags; + Properties.dwSampleFlags |= (CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TIMEDISCONTINUITY); + + MediaSample->SetProperties(sizeof(AM_SAMPLE2_PROPERTIES), (BYTE*)&Properties); + } + // release IMediaSample2 interface + MediaSample->Release(); + } + + // was an extended header used + if (StreamSegment->ExtendedSize) + { + // unprepare stream header extension + StreamSegment->StreamSegment.KsDataTypeHandler->KsCompleteIoOperation(StreamSegment->MediaSample[Index], (CurStreamHeader + 1), StreamSegment->StreamSegment.IoOperation, bOverlapped == FALSE); + } + + Start = 0; + Stop = 0; + if (bOverlapped && StreamSegment->StreamSegment.IoOperation == KsIoOperation_Read) + { + // update common media sample details + StreamSegment->MediaSample[Index]->SetSyncPoint((CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_SPLICEPOINT)); + StreamSegment->MediaSample[Index]->SetPreroll((CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_PREROLL)); + StreamSegment->MediaSample[Index]->SetDiscontinuity((CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY)); + + if (CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TIMEVALID) + { + // use valid timestamp + Start = CurStreamHeader->PresentationTime.Time; + + if (CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DURATIONVALID) + { + Stop = CurStreamHeader->PresentationTime.Time + CurStreamHeader->Duration; + } + } + } + + // now set time + hr = StreamSegment->MediaSample[Index]->SetTime(&Start, &Stop); + if (FAILED(hr)) + { + // use start time + StreamSegment->MediaSample[Index]->SetTime(&Start, &Start); + } + + // set valid data length + StreamSegment->MediaSample[Index]->SetActualDataLength(CurStreamHeader->DataUsed); + + if (StreamSegment->StreamSegment.IoOperation == KsIoOperation_Read) + { + if (bOverlapped) + { + // deliver sample + m_Pin->KsDeliver(StreamSegment->MediaSample[Index], CurStreamHeader->OptionsFlags); + } + } + else if (StreamSegment->StreamSegment.IoOperation == KsIoOperation_Write) + { + // release media sample reference + StreamSegment->MediaSample[Index]->Release(); + } + + CurStreamHeader = (PKSSTREAM_HEADER)((ULONG_PTR)CurStreamHeader + CurStreamHeader->Size); + } + + // delete stream headers + CoTaskMemFree(StreamSegment->StreamHeader); + + if (StreamSegment->StreamSegment.KsDataTypeHandler) + { + // release reference + StreamSegment->StreamSegment.KsDataTypeHandler->Release(); + } + + // decrement pending i/o count + m_Pin->KsDecrementPendingIoCount(); + + //notify of completion + m_Pin->KsMediaSamplesCompleted(InStreamSegment); + + //destroy stream segment + CoTaskMemFree(StreamSegment); + + //release reference to ourselves + Release(); + + // done + // Event handle is closed by caller + return S_OK; } HRESULT diff --git a/reactos/dll/directx/ksproxy/precomp.h b/reactos/dll/directx/ksproxy/precomp.h index 59e2b23779b..839878ee985 100644 --- a/reactos/dll/directx/ksproxy/precomp.h +++ b/reactos/dll/directx/ksproxy/precomp.h @@ -165,3 +165,4 @@ CKsNode_Constructor( LPVOID * ppv); extern const GUID IID_IKsObject; +extern const GUID IID_IKsPinEx; From 7a57ed58196c25a90ff8168465e8786218920701 Mon Sep 17 00:00:00 2001 From: Christoph von Wittich Date: Mon, 15 Mar 2010 15:44:35 +0000 Subject: [PATCH 27/61] [ADVAPI32] sync ParseStringSidToSid with wine 1.1.40 svn path=/trunk/; revision=46207 --- reactos/dll/win32/advapi32/sec/sid.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/reactos/dll/win32/advapi32/sec/sid.c b/reactos/dll/win32/advapi32/sec/sid.c index 6dac3dac683..ed466a58914 100644 --- a/reactos/dll/win32/advapi32/sec/sid.c +++ b/reactos/dll/win32/advapi32/sec/sid.c @@ -805,6 +805,9 @@ static BOOL ParseStringSidToSid(LPCWSTR StringSid, PSID pSid, LPDWORD cBytes) return FALSE; } + while (*StringSid == ' ') + StringSid++; + *cBytes = ComputeStringSidSize(StringSid); if (!pisid) /* Simply compute the size */ { From 531fab28a4b3d6d66ae20e01baa1bfb493f1cefc Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Mon, 15 Mar 2010 16:22:41 +0000 Subject: [PATCH 28/61] [KSPROXY] - Implement IKsDataTypeHandler::KsIsMediaTypeInRanges, IKsDataTypeHandler::KsSetMediaType - Instantiate the IKsInterfaceHandler for the CInputPin svn path=/trunk/; revision=46208 --- reactos/dll/directx/ksproxy/datatype.cpp | 118 ++++++++++++++++++--- reactos/dll/directx/ksproxy/input_pin.cpp | 55 ++++++++-- reactos/dll/directx/ksproxy/interface.cpp | 5 +- reactos/dll/directx/ksproxy/ksproxy.cpp | 2 +- reactos/dll/directx/ksproxy/output_pin.cpp | 46 ++++++-- reactos/dll/directx/ksproxy/precomp.h | 1 + reactos/dll/directx/ksproxy/proxy.cpp | 40 ++++++- 7 files changed, 229 insertions(+), 38 deletions(-) diff --git a/reactos/dll/directx/ksproxy/datatype.cpp b/reactos/dll/directx/ksproxy/datatype.cpp index 3d132890dfd..5006b68a121 100644 --- a/reactos/dll/directx/ksproxy/datatype.cpp +++ b/reactos/dll/directx/ksproxy/datatype.cpp @@ -42,12 +42,25 @@ public: HRESULT STDMETHODCALLTYPE KsQueryExtendedSize(OUT ULONG* ExtendedSize); HRESULT STDMETHODCALLTYPE KsSetMediaType(IN const AM_MEDIA_TYPE* AmMediaType); - CKsDataTypeHandler() : m_Ref(0){}; - virtual ~CKsDataTypeHandler(){}; + CKsDataTypeHandler() : m_Ref(0), m_Type(0){}; + virtual ~CKsDataTypeHandler() + { + if (m_Type) + { + if (m_Type->pbFormat) + CoTaskMemFree(m_Type->pbFormat); + + if (m_Type->pUnk) + m_Type->pUnk->Release(); + + CoTaskMemFree(m_Type); + } + + }; protected: - //CMediaType * m_Type; LONG m_Ref; + AM_MEDIA_TYPE * m_Type; }; @@ -85,8 +98,68 @@ STDMETHODCALLTYPE CKsDataTypeHandler::KsIsMediaTypeInRanges( IN PVOID DataRanges) { - OutputDebugString("UNIMPLEMENTED\n"); - return E_NOTIMPL; + PKSMULTIPLE_ITEM DataList; + PKSDATARANGE DataRange; + ULONG Index; + HRESULT hr = S_FALSE; + + OutputDebugStringW(L"CKsDataTypeHandler::KsIsMediaTypeInRanges\n"); + + DataList = (PKSMULTIPLE_ITEM)DataRanges; + DataRange = (PKSDATARANGE)(DataList + 1); + + for(Index = 0; Index < DataList->Count; Index++) + { + BOOL bMatch = FALSE; + + if (DataRange->FormatSize >= sizeof(KSDATARANGE)) + { + bMatch = IsEqualGUID(DataRange->MajorFormat, GUID_NULL); + } + + if (!bMatch && DataRange->FormatSize >= sizeof(KSDATARANGE_AUDIO)) + { + bMatch = IsEqualGUID(DataRange->MajorFormat, MEDIATYPE_Audio); + } + + if (bMatch) + { + if (IsEqualGUID(DataRange->SubFormat, m_Type->subtype) || + IsEqualGUID(DataRange->SubFormat, GUID_NULL)) + { + if (IsEqualGUID(DataRange->Specifier, m_Type->formattype) || + IsEqualGUID(DataRange->Specifier, GUID_NULL)) + { + if (!IsEqualGUID(m_Type->formattype, FORMAT_WaveFormatEx) && !IsEqualGUID(DataRange->Specifier, FORMAT_WaveFormatEx)) + { + //found match + hr = S_OK; + break; + } + + if (DataRange->FormatSize >= sizeof(KSDATARANGE_AUDIO) && m_Type->cbFormat >= sizeof(WAVEFORMATEX)) + { + LPWAVEFORMATEX Format = (LPWAVEFORMATEX)m_Type->pbFormat; + PKSDATARANGE_AUDIO AudioRange = (PKSDATARANGE_AUDIO)DataRange; + + if (Format->nSamplesPerSec >= AudioRange->MinimumSampleFrequency && + Format->nSamplesPerSec <= AudioRange->MaximumSampleFrequency && + Format->wBitsPerSample >= AudioRange->MinimumSampleFrequency && + Format->wBitsPerSample <= AudioRange->MaximumBitsPerSample && + Format->nChannels <= AudioRange->MaximumChannels) + { + // found match + hr = S_OK; + break; + } + } + } + } + } + + DataRange = (PKSDATARANGE)(((ULONG_PTR)DataRange + DataRange->FormatSize + 7) & ~7); + } + return S_OK; } HRESULT @@ -106,7 +179,6 @@ CKsDataTypeHandler::KsQueryExtendedSize( { /* no header extension required */ *ExtendedSize = 0; - return NOERROR; } @@ -115,19 +187,38 @@ STDMETHODCALLTYPE CKsDataTypeHandler::KsSetMediaType( IN const AM_MEDIA_TYPE* AmMediaType) { -#if 0 + OutputDebugString("CKsDataTypeHandler::KsSetMediaType\n"); + if (m_Type) { /* media type can only be set once */ return E_FAIL; } -#endif - /* - * TODO: allocate CMediaType and copy parameters - */ - OutputDebugString("UNIMPLEMENTED\n"); - return E_NOTIMPL; + m_Type = (AM_MEDIA_TYPE*)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); + if (!m_Type) + return E_OUTOFMEMORY; + + CopyMemory(m_Type, AmMediaType, sizeof(AM_MEDIA_TYPE)); + + if (m_Type->cbFormat) + { + m_Type->pbFormat = (BYTE*)CoTaskMemAlloc(m_Type->cbFormat); + + if (!m_Type->pbFormat) + { + CoTaskMemFree(m_Type); + return E_OUTOFMEMORY; + } + + CopyMemory(m_Type->pbFormat, AmMediaType->pbFormat, m_Type->cbFormat); + } + + if (m_Type->pUnk) + m_Type->pUnk->AddRef(); + + + return S_OK; } HRESULT @@ -138,7 +229,6 @@ CKsDataTypeHandler_Constructor ( LPVOID * ppv) { OutputDebugStringW(L"CKsDataTypeHandler_Constructor\n"); - CKsDataTypeHandler * handler = new CKsDataTypeHandler(); if (!handler) diff --git a/reactos/dll/directx/ksproxy/input_pin.cpp b/reactos/dll/directx/ksproxy/input_pin.cpp index e922b2e156a..50fe22665bb 100644 --- a/reactos/dll/directx/ksproxy/input_pin.cpp +++ b/reactos/dll/directx/ksproxy/input_pin.cpp @@ -143,7 +143,7 @@ public: HRESULT STDMETHODCALLTYPE CheckFormat(const AM_MEDIA_TYPE *pmt); HRESULT STDMETHODCALLTYPE CreatePin(const AM_MEDIA_TYPE *pmt); HRESULT STDMETHODCALLTYPE CreatePinHandle(PKSPIN_MEDIUM Medium, PKSPIN_INTERFACE Interface, const AM_MEDIA_TYPE *pmt); - CInputPin(IBaseFilter * ParentFilter, LPCWSTR PinName, HANDLE hFilter, ULONG PinId, KSPIN_COMMUNICATION Communication) : m_Ref(0), m_ParentFilter(ParentFilter), m_PinName(PinName), m_hFilter(hFilter), m_hPin(INVALID_HANDLE_VALUE), m_PinId(PinId), m_MemAllocator(0), m_IoCount(0), m_Communication(Communication), m_Pin(0), m_ReadOnly(0){}; + CInputPin(IBaseFilter * ParentFilter, LPCWSTR PinName, HANDLE hFilter, ULONG PinId, KSPIN_COMMUNICATION Communication) : m_Ref(0), m_ParentFilter(ParentFilter), m_PinName(PinName), m_hFilter(hFilter), m_hPin(INVALID_HANDLE_VALUE), m_PinId(PinId), m_MemAllocator(0), m_IoCount(0), m_Communication(Communication), m_Pin(0), m_ReadOnly(0), m_InterfaceHandler(0){}; virtual ~CInputPin(){}; protected: @@ -159,6 +159,7 @@ protected: KSPIN_INTERFACE m_Interface; KSPIN_MEDIUM m_Medium; IPin * m_Pin; + IKsInterfaceHandler * m_InterfaceHandler; BOOL m_ReadOnly; }; @@ -666,16 +667,17 @@ CInputPin::ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt) if (m_Pin) { + // already connected return VFW_E_ALREADY_CONNECTED; } // first check format hr = CheckFormat(pmt); if (FAILED(hr)) + { + // format is not supported return hr; - - if (FAILED(CheckFormat(pmt))) - return hr; + } hr = CreatePin(pmt); if (FAILED(hr)) @@ -683,9 +685,8 @@ CInputPin::ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt) return hr; } - //FIXME create pin - m_Pin = pConnector; - m_Pin->AddRef(); + m_Pin = pConnector; + m_Pin->AddRef(); return S_OK; } @@ -925,6 +926,7 @@ CInputPin::CreatePin( PKSMULTIPLE_ITEM InterfaceList; PKSPIN_MEDIUM Medium; PKSPIN_INTERFACE Interface; + IKsInterfaceHandler * InterfaceHandler; HRESULT hr; // query for pin medium @@ -963,8 +965,43 @@ CInputPin::CreatePin( Interface = &StandardPinInterface; } - // now create pin - hr = CreatePinHandle(Medium, Interface, pmt); + if (m_Communication != KSPIN_COMMUNICATION_BRIDGE && m_Communication != KSPIN_COMMUNICATION_NONE) + { + // now load the IKsInterfaceHandler plugin + hr = CoCreateInstance(Interface->Set, NULL, CLSCTX_INPROC_SERVER, IID_IKsInterfaceHandler, (void**)&InterfaceHandler); + if (FAILED(hr)) + { + // failed to load interface handler plugin + OutputDebugStringW(L"CInputPin::CreatePin failed to load InterfaceHandlerPlugin\n"); + CoTaskMemFree(MediumList); + CoTaskMemFree(InterfaceList); + + return hr; + } + + // now set the pin + hr = InterfaceHandler->KsSetPin((IKsPin*)this); + if (FAILED(hr)) + { + // failed to load interface handler plugin + OutputDebugStringW(L"CInputPin::CreatePin failed to initialize InterfaceHandlerPlugin\n"); + InterfaceHandler->Release(); + CoTaskMemFree(MediumList); + CoTaskMemFree(InterfaceList); + return hr; + } + + // store interface handler + m_InterfaceHandler = InterfaceHandler; + + // now create pin + hr = CreatePinHandle(Medium, Interface, pmt); + if (FAILED(hr)) + { + m_InterfaceHandler->Release(); + m_InterfaceHandler = InterfaceHandler; + } + } // free medium / interface / dataformat CoTaskMemFree(MediumList); diff --git a/reactos/dll/directx/ksproxy/interface.cpp b/reactos/dll/directx/ksproxy/interface.cpp index 7b6b0d9961b..930f7e00b73 100644 --- a/reactos/dll/directx/ksproxy/interface.cpp +++ b/reactos/dll/directx/ksproxy/interface.cpp @@ -247,12 +247,9 @@ CKsInterfaceHandler::KsProcessMediaSamples( //release IMediaSample2 interface MediaSample->Release(); - if (FAILED(hr)) - OutputDebugStringW(L"CKsInterfaceHandler::KsProcessMediaSamples MediaSample::GetProperties failed\n"); } else { - OutputDebugStringW(L"CKsInterfaceHandler::KsProcessMediaSamples MediaSample:: only IMediaSample supported\n"); // get properties hr = SampleList[Index]->GetPointer((BYTE**)&Properties.pbBuffer); assert(hr == NOERROR); @@ -272,7 +269,7 @@ CKsInterfaceHandler::KsProcessMediaSamples( } WCHAR Buffer[100]; - swprintf(Buffer, L"BufferLength %lu Property Buffer %p ExtendedSize %u lActual %u\n", Properties.cbBuffer, Properties.pbBuffer, ExtendedSize, Properties.lActual); + swprintf(Buffer, L"BufferLength %lu Property Buffer %p ExtendedSize %u lActual %u\n", Properties.cbBuffer, Properties.pbBuffer, ExtendedSize, Properties.lActual); OutputDebugStringW(Buffer); CurStreamHeader->Size = sizeof(KSSTREAM_HEADER) + ExtendedSize; diff --git a/reactos/dll/directx/ksproxy/ksproxy.cpp b/reactos/dll/directx/ksproxy/ksproxy.cpp index 237b0390427..f79a154574b 100644 --- a/reactos/dll/directx/ksproxy/ksproxy.cpp +++ b/reactos/dll/directx/ksproxy/ksproxy.cpp @@ -13,10 +13,10 @@ const GUID CLSID_KsClockForwarder = {0x877e4351, 0x6fea, 0x11d0, {0xb8, 0x63, 0x00, 0xaa, 0x00, 0xa2, 0x16, 0xa1}}; const GUID CLSID_KsQualityForwarder = {0xe05592e4, 0xc0b5, 0x11d0, {0xa4, 0x39, 0x00, 0xa0, 0xc9, 0x22, 0x31, 0x96}}; -const GUID CLSID_KsIBasicAudioInterfaceHandler = {0xb9f8ac3e, 0x0f71, 0x11d2, {0xb7, 0x2c, 0x00, 0xc0, 0x4f, 0xb6, 0xbd, 0x3d}}; #ifndef _MSC_VER +const GUID CLSID_KsIBasicAudioInterfaceHandler = {0xb9f8ac3e, 0x0f71, 0x11d2, {0xb7, 0x2c, 0x00, 0xc0, 0x4f, 0xb6, 0xbd, 0x3d}}; const GUID KSPROPSETID_Pin = {0x8C134960, 0x51AD, 0x11CF, {0x87, 0x8A, 0x94, 0xF8, 0x01, 0xC1, 0x00, 0x00}}; const GUID KSINTERFACESETID_Standard = {STATIC_KSINTERFACESETID_Standard}; const GUID CLSID_Proxy = {0x17CCA71B, 0xECD7, 0x11D0, {0xB9, 0x08, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}}; diff --git a/reactos/dll/directx/ksproxy/output_pin.cpp b/reactos/dll/directx/ksproxy/output_pin.cpp index 98b2f63c0df..b17fffa84bd 100644 --- a/reactos/dll/directx/ksproxy/output_pin.cpp +++ b/reactos/dll/directx/ksproxy/output_pin.cpp @@ -21,6 +21,7 @@ class COutputPin : public IPin, // public IKsPinPipe, public IKsControl /* + public IAMBufferNegotiation, public IQualityControl, public IKsPinEx, public IKsAggregateControl @@ -142,51 +143,55 @@ COutputPin::QueryInterface( if (IsEqualGUID(refiid, IID_IUnknown) || IsEqualGUID(refiid, IID_IPin)) { + OutputDebugStringW(L"COutputPin::QueryInterface IID_IPin\n"); *Output = PVOID(this); reinterpret_cast(*Output)->AddRef(); return NOERROR; } else if (IsEqualGUID(refiid, IID_IKsObject)) { + OutputDebugStringW(L"COutputPin::QueryInterface IID_IKsObject\n"); *Output = (IKsObject*)(this); reinterpret_cast(*Output)->AddRef(); return NOERROR; } else if (IsEqualGUID(refiid, IID_IKsPropertySet)) { + OutputDebugStringW(L"COutputPin::QueryInterface IID_IKsPropertySet\n"); + DebugBreak(); *Output = (IKsPropertySet*)(this); reinterpret_cast(*Output)->AddRef(); return NOERROR; } else if (IsEqualGUID(refiid, IID_IKsControl)) { + OutputDebugStringW(L"COutputPin::QueryInterface IID_IKsControl\n"); *Output = (IKsControl*)(this); reinterpret_cast(*Output)->AddRef(); return NOERROR; } +#if 0 else if (IsEqualGUID(refiid, IID_IStreamBuilder)) { *Output = (IStreamBuilder*)(this); reinterpret_cast(*Output)->AddRef(); return NOERROR; } +#endif else if (IsEqualGUID(refiid, IID_IKsPinFactory)) { + OutputDebugStringW(L"COutputPin::QueryInterface IID_IKsPinFactory\n"); *Output = (IKsPinFactory*)(this); reinterpret_cast(*Output)->AddRef(); return NOERROR; } else if (IsEqualGUID(refiid, IID_ISpecifyPropertyPages)) { + OutputDebugStringW(L"COutputPin::QueryInterface IID_ISpecifyPropertyPages\n"); *Output = (ISpecifyPropertyPages*)(this); reinterpret_cast(*Output)->AddRef(); return NOERROR; } - else if (IsEqualGUID(refiid, IID_IBaseFilter)) - { - OutputDebugStringW(L"COutputPin::QueryInterface query IID_IBaseFilter\n"); - DebugBreak(); - } WCHAR Buffer[MAX_PATH]; LPOLESTR lpstr; @@ -226,6 +231,7 @@ STDMETHODCALLTYPE COutputPin::KsPinFactory( ULONG* PinFactory) { + OutputDebugStringW(L"COutputPin::KsPinFactory\n"); *PinFactory = m_PinId; return S_OK; } @@ -241,6 +247,7 @@ COutputPin::Render( IPin *ppinOut, IGraphBuilder *pGraph) { + OutputDebugStringW(L"COutputPin::Render\n"); return S_OK; } @@ -250,6 +257,7 @@ COutputPin::Backout( IPin *ppinOut, IGraphBuilder *pGraph) { + OutputDebugStringW(L"COutputPin::Backout\n"); return S_OK; } //------------------------------------------------------------------- @@ -259,6 +267,7 @@ HANDLE STDMETHODCALLTYPE COutputPin::KsGetObjectHandle() { + OutputDebugStringW(L"COutputPin::KsGetObjectHandle\n"); assert(m_hPin); return m_hPin; } @@ -276,6 +285,7 @@ COutputPin::KsProperty( ULONG* BytesReturned) { assert(m_hPin != 0); + OutputDebugStringW(L"COutputPin::KsProperty\n"); return KsSynchronousDeviceControl(m_hPin, IOCTL_KS_PROPERTY, (PVOID)Property, PropertyLength, (PVOID)PropertyData, DataLength, BytesReturned); } @@ -289,6 +299,7 @@ COutputPin::KsMethod( ULONG* BytesReturned) { assert(m_hPin != 0); + OutputDebugStringW(L"COutputPin::KsMethod\n"); return KsSynchronousDeviceControl(m_hPin, IOCTL_KS_METHOD, (PVOID)Method, MethodLength, (PVOID)MethodData, DataLength, BytesReturned); } @@ -303,6 +314,8 @@ COutputPin::KsEvent( { assert(m_hPin != 0); + OutputDebugStringW(L"COutputPin::KsEvent\n"); + if (EventLength) return KsSynchronousDeviceControl(m_hPin, IOCTL_KS_ENABLE_EVENT, (PVOID)Event, EventLength, (PVOID)EventData, DataLength, BytesReturned); else @@ -325,6 +338,8 @@ COutputPin::Set( { ULONG BytesReturned; + OutputDebugStringW(L"COutputPin::Set\n"); + if (cbInstanceData) { PKSPROPERTY Property = (PKSPROPERTY)CoTaskMemAlloc(sizeof(KSPROPERTY) + cbInstanceData); @@ -367,6 +382,8 @@ COutputPin::Get( { ULONG BytesReturned; + OutputDebugStringW(L"COutputPin::Get\n"); + if (cbInstanceData) { PKSPROPERTY Property = (PKSPROPERTY)CoTaskMemAlloc(sizeof(KSPROPERTY) + cbInstanceData); @@ -406,6 +423,8 @@ COutputPin::QuerySupported( KSPROPERTY Property; ULONG BytesReturned; + OutputDebugStringW(L"COutputPin::QuerySupported\n"); + Property.Set = guidPropSet; Property.Id = dwPropID; Property.Flags = KSPROPERTY_TYPE_SETSUPPORT; @@ -470,12 +489,15 @@ HRESULT STDMETHODCALLTYPE COutputPin::ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt) { + OutputDebugStringW(L"COutputPin::ReceiveConnection\n"); return E_UNEXPECTED; } HRESULT STDMETHODCALLTYPE COutputPin::Disconnect( void) { + OutputDebugStringW(L"COutputPin::Disconnect\n"); + if (!m_Pin) { // pin was not connected @@ -495,6 +517,8 @@ HRESULT STDMETHODCALLTYPE COutputPin::ConnectedTo(IPin **pPin) { + OutputDebugStringW(L"COutputPin::ConnectedTo\n"); + if (!pPin) return E_POINTER; @@ -520,6 +544,8 @@ HRESULT STDMETHODCALLTYPE COutputPin::QueryPinInfo(PIN_INFO *pInfo) { + OutputDebugStringW(L"COutputPin::QueryPinInfo\n"); + wcscpy(pInfo->achName, m_PinName); pInfo->dir = PINDIR_OUTPUT; pInfo->pFilter = m_ParentFilter; @@ -531,6 +557,8 @@ HRESULT STDMETHODCALLTYPE COutputPin::QueryDirection(PIN_DIRECTION *pPinDir) { + OutputDebugStringW(L"COutputPin::QueryDirection\n"); + if (pPinDir) { *pPinDir = PINDIR_OUTPUT; @@ -543,6 +571,8 @@ HRESULT STDMETHODCALLTYPE COutputPin::QueryId(LPWSTR *Id) { + OutputDebugStringW(L"COutputPin::QueryId\n"); + *Id = (LPWSTR)CoTaskMemAlloc((wcslen(m_PinName)+1)*sizeof(WCHAR)); if (!*Id) return E_OUTOFMEMORY; @@ -580,10 +610,10 @@ COutputPin::EnumMediaTypes(IEnumMediaTypes **ppEnum) // query media type count hr = KsGetMediaTypeCount(hFilter, m_PinId, &MediaTypeCount); if (FAILED(hr) || !MediaTypeCount) - { + { OutputDebugStringW(L"COutputPin::EnumMediaTypes failed1\n"); return hr; - } + } // allocate media types MediaTypes = (AM_MEDIA_TYPE*)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * MediaTypeCount); @@ -605,7 +635,7 @@ COutputPin::EnumMediaTypes(IEnumMediaTypes **ppEnum) { // failed CoTaskMemFree(MediaTypes); - OutputDebugStringW(L"COutputPin::EnumMediaTypes failed2\n"); + OutputDebugStringW(L"COutputPin::EnumMediaTypes failed\n"); return hr; } } diff --git a/reactos/dll/directx/ksproxy/precomp.h b/reactos/dll/directx/ksproxy/precomp.h index 839878ee985..21cd4eb2e27 100644 --- a/reactos/dll/directx/ksproxy/precomp.h +++ b/reactos/dll/directx/ksproxy/precomp.h @@ -19,6 +19,7 @@ #include #include #include +#include //#include diff --git a/reactos/dll/directx/ksproxy/proxy.cpp b/reactos/dll/directx/ksproxy/proxy.cpp index 5acea85a036..371176f2437 100644 --- a/reactos/dll/directx/ksproxy/proxy.cpp +++ b/reactos/dll/directx/ksproxy/proxy.cpp @@ -1509,6 +1509,7 @@ STDMETHODCALLTYPE CKsProxy::SetRate( double dRate) { + OutputDebugStringW(L"CKsProxy::SetRate\n"); return E_NOTIMPL; } @@ -1517,6 +1518,7 @@ STDMETHODCALLTYPE CKsProxy::GetRate( double *pdRate) { + OutputDebugStringW(L"CKsProxy::GetRate\n"); return E_NOTIMPL; } @@ -1619,6 +1621,7 @@ CKsProxy::KsProperty( ULONG* BytesReturned) { assert(m_hDevice != 0); + OutputDebugStringW(L"CKsProxy::KsProperty\n"); return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)Property, PropertyLength, (PVOID)PropertyData, DataLength, BytesReturned); } @@ -1632,6 +1635,7 @@ CKsProxy::KsMethod( ULONG* BytesReturned) { assert(m_hDevice != 0); + OutputDebugStringW(L"CKsProxy::KsMethod\n"); return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_METHOD, (PVOID)Method, MethodLength, (PVOID)MethodData, DataLength, BytesReturned); } @@ -1645,7 +1649,7 @@ CKsProxy::KsEvent( ULONG* BytesReturned) { assert(m_hDevice != 0); - + OutputDebugStringW(L"CKsProxy::KsEvent\n"); if (EventLength) return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_ENABLE_EVENT, (PVOID)Event, EventLength, (PVOID)EventData, DataLength, BytesReturned); else @@ -1668,6 +1672,8 @@ CKsProxy::Set( { ULONG BytesReturned; + OutputDebugStringW(L"CKsProxy::Set\n"); + if (cbInstanceData) { PKSPROPERTY Property = (PKSPROPERTY)CoTaskMemAlloc(sizeof(KSPROPERTY) + cbInstanceData); @@ -1710,6 +1716,8 @@ CKsProxy::Get( { ULONG BytesReturned; + OutputDebugStringW(L"CKsProxy::Get\n"); + if (cbInstanceData) { PKSPROPERTY Property = (PKSPROPERTY)CoTaskMemAlloc(sizeof(KSPROPERTY) + cbInstanceData); @@ -1749,6 +1757,8 @@ CKsProxy::QuerySupported( KSPROPERTY Property; ULONG BytesReturned; + OutputDebugStringW(L"CKsProxy::QuerySupported\n"); + Property.Set = guidPropSet; Property.Id = dwPropID; Property.Flags = KSPROPERTY_TYPE_SETSUPPORT; @@ -1930,6 +1940,9 @@ HRESULT STDMETHODCALLTYPE CKsProxy::DeviceInfo(CLSID *pclsidInterfaceClass, LPWSTR *pwszSymbolicLink) { + + OutputDebugStringW(L"CKsProxy::DeviceInfo\n"); + if (!m_DevicePath) { // object not initialized @@ -1953,6 +1966,8 @@ HRESULT STDMETHODCALLTYPE CKsProxy::Reassociate(void) { + OutputDebugStringW(L"CKsProxy::Reassociate\n"); + if (!m_DevicePath || m_hDevice) { // file path not available @@ -1974,6 +1989,8 @@ HRESULT STDMETHODCALLTYPE CKsProxy::Disassociate(void) { + OutputDebugStringW(L"CKsProxy::Disassociate\n"); + if (!m_hDevice) return E_HANDLE; @@ -1990,6 +2007,7 @@ HANDLE STDMETHODCALLTYPE CKsProxy::KsGetClockHandle() { + OutputDebugStringW(L"CKsProxy::KsGetClockHandle\n"); return m_hClock; } @@ -2002,6 +2020,7 @@ HANDLE STDMETHODCALLTYPE CKsProxy::KsGetObjectHandle() { + OutputDebugStringW(L"CKsProxy::KsGetObjectHandle\n"); return m_hDevice; } @@ -2012,6 +2031,7 @@ HRESULT STDMETHODCALLTYPE CKsProxy::InitNew( void) { + OutputDebugStringW(L"CKsProxy::InitNew\n"); return S_OK; } @@ -2384,6 +2404,7 @@ CKsProxy::Load(IPropertyBag *pPropBag, IErrorLog *pErrorLog) HDEVINFO hList; SP_DEVICE_INTERFACE_DATA DeviceInterfaceData; + OutputDebugStringW(L"CKsProxy::Load\n"); // read device path varName.vt = VT_BSTR; @@ -2396,6 +2417,10 @@ CKsProxy::Load(IPropertyBag *pPropBag, IErrorLog *pErrorLog) return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError()); } + OutputDebugStringW(L"DevicePath: "); + OutputDebugStringW(varName.bstrVal); + OutputDebugStringW(L"\n"); + // create device list hList = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL); if (hList == INVALID_HANDLE_VALUE) @@ -2463,6 +2488,7 @@ HRESULT STDMETHODCALLTYPE CKsProxy::Save(IPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties) { + OutputDebugStringW(L"CKsProxy::Save\n"); return E_NOTIMPL; } @@ -2532,7 +2558,7 @@ CKsProxy::SetSyncSource( PIN_DIRECTION PinDir; // Plug In Distributor: IKsClock - + OutputDebugStringW(L"CKsProxy::SetSyncSource\n"); // FIXME // need locks @@ -2624,6 +2650,8 @@ STDMETHODCALLTYPE CKsProxy::GetSyncSource( IReferenceClock **pClock) { + OutputDebugStringW(L"CKsProxy::GetSyncSource\n"); + if (!pClock) return E_POINTER; @@ -2639,6 +2667,7 @@ STDMETHODCALLTYPE CKsProxy::EnumPins( IEnumPins **ppEnum) { + OutputDebugStringW(L"CKsProxy::EnumPins\n"); return CEnumPins_fnConstructor(m_Pins, IID_IEnumPins, (void**)ppEnum); } @@ -2649,6 +2678,8 @@ CKsProxy::FindPin( { ULONG PinId; + OutputDebugStringW(L"CKsProxy::FindPin\n"); + if (!ppPin) return E_POINTER; @@ -2683,6 +2714,8 @@ CKsProxy::QueryFilterInfo( if (!pInfo) return E_POINTER; + OutputDebugStringW(L"CKsProxy::QueryFilterInfo\n"); + pInfo->achName[0] = L'\0'; pInfo->pGraph = m_pGraph; @@ -2698,6 +2731,8 @@ CKsProxy::JoinFilterGraph( IFilterGraph *pGraph, LPCWSTR pName) { + OutputDebugStringW(L"CKsProxy::JoinFilterGraph\n"); + if (pGraph) { // joining filter graph @@ -2718,6 +2753,7 @@ STDMETHODCALLTYPE CKsProxy::QueryVendorInfo( LPWSTR *pVendorInfo) { + OutputDebugStringW(L"CKsProxy::QueryVendorInfo\n"); return StringFromCLSID(CLSID_Proxy, pVendorInfo); } From 34d9c5fc14b921a5ad53dc2a8282e153deae03a7 Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Mon, 15 Mar 2010 16:23:45 +0000 Subject: [PATCH 29/61] - Fix build svn path=/trunk/; revision=46209 --- reactos/dll/directx/ksproxy/input_pin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reactos/dll/directx/ksproxy/input_pin.cpp b/reactos/dll/directx/ksproxy/input_pin.cpp index 50fe22665bb..40d339ef894 100644 --- a/reactos/dll/directx/ksproxy/input_pin.cpp +++ b/reactos/dll/directx/ksproxy/input_pin.cpp @@ -159,8 +159,8 @@ protected: KSPIN_INTERFACE m_Interface; KSPIN_MEDIUM m_Medium; IPin * m_Pin; - IKsInterfaceHandler * m_InterfaceHandler; BOOL m_ReadOnly; + IKsInterfaceHandler * m_InterfaceHandler; }; HRESULT From 48cc443d59500447fcd7bd04d454e59f358655c6 Mon Sep 17 00:00:00 2001 From: Dmitry Gorbachev Date: Mon, 15 Mar 2010 17:03:37 +0000 Subject: [PATCH 30/61] Update log2lines to ver. 2.2. Jan Roeloffzen, bug #4342. svn path=/trunk/; revision=46211 --- reactos/tools/log2lines/cache.c | 16 ++++- reactos/tools/log2lines/cache.h | 1 + reactos/tools/log2lines/cmd.c | 60 ++++++++++++++++-- reactos/tools/log2lines/config.h | 5 ++ reactos/tools/log2lines/help.c | 22 ++++++- reactos/tools/log2lines/image.c | 5 +- reactos/tools/log2lines/list.c | 5 ++ reactos/tools/log2lines/list.h | 6 +- reactos/tools/log2lines/log2lines.c | 38 ++++++----- reactos/tools/log2lines/log2lines.mak | 5 ++ reactos/tools/log2lines/match.c | 91 +++++++++++++++++++++++++++ reactos/tools/log2lines/match.h | 5 ++ reactos/tools/log2lines/options.c | 16 ++++- reactos/tools/log2lines/options.h | 2 + reactos/tools/log2lines/revision.c | 8 +-- reactos/tools/log2lines/stat.c | 2 + reactos/tools/log2lines/util.c | 16 ++--- reactos/tools/log2lines/util.h | 3 +- reactos/tools/log2lines/version.h | 2 +- 19 files changed, 267 insertions(+), 41 deletions(-) create mode 100644 reactos/tools/log2lines/match.c create mode 100644 reactos/tools/log2lines/match.h diff --git a/reactos/tools/log2lines/cache.c b/reactos/tools/log2lines/cache.c index fd5bcc2c303..d8faa8d9537 100644 --- a/reactos/tools/log2lines/cache.c +++ b/reactos/tools/log2lines/cache.c @@ -4,6 +4,7 @@ * * - Image directory caching */ + #include #include #include @@ -65,6 +66,14 @@ unpack_iso(char *dir, char *iso) return res; } +int +cleanable(char *path) +{ + if (strcmp(basename(path),DEF_OPT_DIR) == 0) + return 1; + return 0; +} + int check_directory(int force) { @@ -135,7 +144,10 @@ check_directory(int force) cache_name = malloc(MAX_PATH); tmp_name = malloc(MAX_PATH); strcpy(cache_name, opt_dir); - strcat(cache_name, PATH_STR CACHEFILE); + if (cleanable(opt_dir)) + strcat(cache_name, ALT_PATH_STR CACHEFILE); + else + strcat(cache_name, PATH_STR CACHEFILE); strcpy(tmp_name, cache_name); strcat(tmp_name, "~"); return 0; @@ -271,4 +283,4 @@ create_cache(int force, int skipImageBase) return 0; } - +/* EOF */ diff --git a/reactos/tools/log2lines/cache.h b/reactos/tools/log2lines/cache.h index e34290fabae..0acdd4c0f68 100644 --- a/reactos/tools/log2lines/cache.h +++ b/reactos/tools/log2lines/cache.h @@ -10,5 +10,6 @@ int check_directory(int force); int read_cache(void); int create_cache(int force, int skipImageBase); +int cleanable(char *path); /* EOF */ diff --git a/reactos/tools/log2lines/cmd.c b/reactos/tools/log2lines/cmd.c index 72877dcb822..ca7afaa8749 100644 --- a/reactos/tools/log2lines/cmd.c +++ b/reactos/tools/log2lines/cmd.c @@ -4,6 +4,7 @@ * * - Cli for escape commands */ + #include #include #include @@ -17,7 +18,7 @@ /* When you edit the cmd line and/or use the history instead of just typing, * a bunch of editing BS and space characters * is inserted, so the string looks right on the console but still - * starts with the original string: + * contains the original string, plus other garbage: */ static char *backSpaceEdit(char *s) @@ -142,6 +143,39 @@ handle_switch_pstr(FILE *outFile, char **psw, char *arg, char *desc) return changed; } +static int +handle_address_cmd(FILE *outFile, char *arg) +{ + PLIST_MEMBER plm; + char Image[NAMESIZE]; + DWORD Offset; + int cnt; + char *s; + + if(( s = strchr(arg, ':') )) + { + *s = ' '; + if ( (cnt = sscanf(arg,"%20s %lx", Image, &Offset)) == 2) + { + if (( plm = entry_lookup(&cache, Image) )) + { + if (plm->RelBase != INVALID_BASE) + esclog(outFile, "Address: 0x%lx\n", plm->RelBase + Offset) + else + esclog(outFile, "Relocated base missing for '%s' ('mod' will update)\n", Image); + } + else + esclog(outFile, "Image '%s' not found\n", Image); + } + else + esclog(outFile, "usage: `a :\n"); + } + else + esclog(outFile, "':' expected\n"); + + return 1; +} + char handle_escape_cmd(FILE *outFile, char *Line, char *path, char *LineOut) { @@ -177,12 +211,15 @@ handle_escape_cmd(FILE *outFile, char *Line, char *path, char *LineOut) opt_cli = 1; switch (cmd) { + case 'a': + handle_address_cmd(outFile, arg); + break; case 'h': usage(1); break; case 'b': if (handle_switch(outFile, &opt_buffered, arg, "-b Logfile buffering")) - set_LogFile(logFile); //re-open same logfile + set_LogFile(&logFile); //re-open same logfile break; case 'c': handle_switch(outFile, &opt_console, NULL, "-c Console option"); @@ -191,8 +228,18 @@ handle_escape_cmd(FILE *outFile, char *Line, char *path, char *LineOut) handle_switch_str(outFile, opt_dir, NULL, "-d Directory option"); break; case 'l': - if (handle_switch_str(outFile, opt_logFile, arg, "-l logfile")) - set_LogFile(logFile); //open new logfile + if (handle_switch_str(outFile, opt_logFile, arg, "-l logfile") || (strcmp(opt_mod,"a")!=0)) + { + opt_mod = "a"; + set_LogFile(&logFile); //open new logfile + } + break; + case 'L': + if (handle_switch_str(outFile, opt_logFile, arg, "-L logfile") || (strcmp(opt_mod,"w")!=0)) + { + opt_mod = "w"; + set_LogFile(&logFile); //open new logfile + } break; case 'm': handle_switch(outFile, &opt_Mark, arg, "-m mark (*)"); @@ -212,8 +259,10 @@ handle_escape_cmd(FILE *outFile, char *Line, char *path, char *LineOut) break; case 'R': changed = handle_switch_pstr(outFile, &opt_Revision, arg, NULL); + opt_Revision_check = 0; if (opt_Revision) { + opt_Revision_check = 1; if (strstr(opt_Revision, "check") == opt_Revision) { esclog(outFile, "-R is \"%s\" (%s)\n", opt_Revision, changed ? "changed":"unchanged"); @@ -253,6 +302,7 @@ handle_escape_cmd(FILE *outFile, char *Line, char *path, char *LineOut) { handle_switch(outFile, &opt_undo, "1", "-u Undo"); handle_switch(outFile, &opt_redo, "1", "-U Undo and reprocess"); + opt_Revision_check = 1; } esclog(outFile, "-S Sources option is %d+%d,\"%s\"\n", opt_Source, opt_SrcPlus, opt_SourcesPath); esclog(outFile, "(Setting source tree not implemented)\n"); @@ -289,3 +339,5 @@ handle_escape_cmd(FILE *outFile, char *Line, char *path, char *LineOut) return KDBG_ESC_CHAR; //handled escaped command } + +/* EOF */ diff --git a/reactos/tools/log2lines/config.h b/reactos/tools/log2lines/config.h index d39c646a3d9..d1c73898e94 100644 --- a/reactos/tools/log2lines/config.h +++ b/reactos/tools/log2lines/config.h @@ -26,6 +26,11 @@ "%s x -y -r %s" PATH_STR "reactos" PATH_STR "reactos.cab -o%s" \ PATH_STR "reactos" PATH_STR "reactos > " DEV_NULL +/* When we can't use a normal path, because it gets cleaned, + * fallback to name mangling: + */ +#define ALT_PATH_STR "#" + #define LINESIZE 1024 #define NAMESIZE 80 diff --git a/reactos/tools/log2lines/help.c b/reactos/tools/log2lines/help.c index 37e6bf400f8..c036d4857c7 100644 --- a/reactos/tools/log2lines/help.c +++ b/reactos/tools/log2lines/help.c @@ -4,6 +4,7 @@ * * - Help text and functions */ + #include #include "version.h" @@ -51,6 +52,9 @@ char *verboseUsage = " -l \n" " : Append copy to specified logFile.\n" " Default: no logFile\n\n" +" -L \n" +" : (Over)write copy to specified logFile.\n" +" Default: no logFile\n\n" " -m Prefix (mark) each translated line with '* '.\n\n" " -M Prefix (mark) each NOT translated line with '? '.\n" " ( Only for lines of the form: )\n\n" @@ -112,7 +116,7 @@ char *verboseUsage = " For a reliable result, these sources should be up to date with\n" " the tested revision (or try '-R check').\n" " Can be combined with -tTR.\n" -" Implies -U (For retrieving source info).\n\n" +" Implies -U (For retrieving source info) and -R check.\n\n" " -t Translate twice. The address itself and for (address-1).\n" " Show extra filename, func and linenumber between [..] if they differ\n" " So if only the linenumbers differ, then only show the extra\n" @@ -139,7 +143,10 @@ char *verboseUsage = " Options accepting a string as argument can be cleared by the value '" KDBG_ESC_OFF "'.\n" " Some ClI commands are read only or not (entirely) implemented.\n" " If no value is provided, the current one is printed.\n" -" There are only a few extra ClI commands or with different behaviour:\n" +" There are a few extra ClI commands or with different behaviour:\n" +" - `a ::\n" +" - Outputs absolute address e.g. for setting breakpoints.\n" +" - Do a 'mod' first to retrieve relocation info.\n" " - `h : shows this helptext (without exiting)\n" " - `q : quits log2lines\n" " - `R regscan : the output is printed immediately (do a 'bt' first)\n" @@ -233,7 +240,14 @@ char *verboseUsage = " | L2L- -l logfile is \"new.log\" (changed)\n" " kdb:> `l off\n" " | L2L- -l logfile is "" (changed)\n" -" kdb:>\n" +" kdb:>\n\n" +" Set a breakpoint with help of 'mod' and '`a':\n" +" \n" +" kdb:> mod (for kernel tracing usually only needed once)\n" +" -- mod output with reloc info\n" +" kdb:> `a msi.dll:2e35d\n" +" | L2L- Address: 0x00096ca0\n" +" kdb:> bpx 0x00096ca0\n\n" "\n"; void @@ -246,3 +260,5 @@ usage(int verbose) else fprintf(stderr, "Try log2lines -h\n"); } + +/* EOF */ diff --git a/reactos/tools/log2lines/image.c b/reactos/tools/log2lines/image.c index f94abcb59c8..bae302b8d51 100644 --- a/reactos/tools/log2lines/image.c +++ b/reactos/tools/log2lines/image.c @@ -4,11 +4,12 @@ * * - Image functions for symbol info */ -#include + #include #include #include +#include "compat.h" #include "util.h" #include "options.h" #include "log2lines.h" @@ -163,3 +164,5 @@ get_ImageBase(char *fname, size_t *ImageBase) fclose(fr); return 0; } + +/* EOF */ diff --git a/reactos/tools/log2lines/list.c b/reactos/tools/log2lines/list.c index 4491d079252..3fdd22b564d 100644 --- a/reactos/tools/log2lines/list.c +++ b/reactos/tools/log2lines/list.c @@ -9,6 +9,7 @@ #include #include +#include "config.h" #include "compat.h" #include "list.h" #include "util.h" @@ -162,6 +163,8 @@ cache_entry_create(char *Line) l2l_dbg(1, "ImageBase field missing\n"); return entry_delete(pentry); } + pentry->RelBase = INVALID_BASE; + pentry->Size = 0; return pentry; } @@ -212,3 +215,5 @@ sources_entry_create(PLIST list, char *path, char *prefix) return pentry; } + +/* EOF */ diff --git a/reactos/tools/log2lines/list.h b/reactos/tools/log2lines/list.h index 4406a41be8f..fa426d4c0c0 100644 --- a/reactos/tools/log2lines/list.h +++ b/reactos/tools/log2lines/list.h @@ -6,14 +6,16 @@ typedef struct entry_struct char *name; char *path; size_t ImageBase; + size_t RelBase; + size_t Size; struct entry_struct *pnext; -} LIST_MEMBER,*PLIST_MEMBER; +} LIST_MEMBER, *PLIST_MEMBER; typedef struct list_struct { PLIST_MEMBER phead; PLIST_MEMBER ptail; -} LIST,*PLIST; +} LIST, *PLIST; PLIST_MEMBER entry_lookup(PLIST list, char *name); PLIST_MEMBER entry_delete(PLIST_MEMBER pentry); diff --git a/reactos/tools/log2lines/log2lines.c b/reactos/tools/log2lines/log2lines.c index 1ad94f2fb0e..c00cfd378b5 100644 --- a/reactos/tools/log2lines/log2lines.c +++ b/reactos/tools/log2lines/log2lines.c @@ -19,10 +19,13 @@ #include "log2lines.h" #include "help.h" #include "cmd.h" +#include "match.h" -static FILE *stdIn = NULL; -static FILE *stdOut = NULL; +static FILE *dbgIn = NULL; +static FILE *dbgOut = NULL; +static FILE *conIn = NULL; +static FILE *conOut = NULL; static const char *kdbg_prompt = KDBG_PROMPT; static const char *kdbg_cont = KDBG_CONT; @@ -443,15 +446,18 @@ translate_files(FILE *inFile, FILE *outFile) { if (p == p_eos) { - //kdbg prompt, so already echoed char by char + // kdbg prompt, so already echoed char by char memset(Line, '\0', LINESIZE); translate_char(c, outFile); } else { - translate_line(outFile, Line, path, LineOut); - translate_char(c, outFile); - report(outFile); + if (match_line(outFile, Line)) + { + translate_line(outFile, Line, path, LineOut); + translate_char(c, outFile); + report(outFile); + } } } } @@ -562,8 +568,10 @@ main(int argc, const char **argv) int res = 0; int optCount = 0; - stdIn = stdin; - stdOut = stdout; + dbgIn = stdin; + conOut = stdout; + (void)conIn; + (void)dbgOut; memset(&cache, 0, sizeof(LIST)); memset(&sources, 0, sizeof(LIST)); @@ -596,7 +604,7 @@ main(int argc, const char **argv) read_cache(); l2l_dbg(4, "Cache read complete\n"); - if (set_LogFile(logFile)) + if (set_LogFile(&logFile)) return 2; l2l_dbg(4, "opt_logFile processed\n"); @@ -604,9 +612,9 @@ main(int argc, const char **argv) { l2l_dbg(3, "Command line: \"%s\"\n",opt_Pipe); - if (!(stdIn = POPEN(opt_Pipe, "r"))) + if (!(dbgIn = POPEN(opt_Pipe, "r"))) { - stdIn = stdin; //restore + dbgIn = stdin; //restore l2l_dbg(0, "Could not popen '%s' (%s)\n", opt_Pipe, strerror(errno)); free(opt_Pipe); opt_Pipe = NULL; } @@ -631,7 +639,7 @@ main(int argc, const char **argv) l2l_dbg(2, "translating %s %s\n", exefile, offset); translate_file(exefile, my_atoi(offset), Line); printf("%s\n", Line); - report(stdOut); + report(conOut); } else { @@ -649,14 +657,16 @@ main(int argc, const char **argv) } else { // translate logging from stdin - translate_files(stdIn, stdOut); + translate_files(dbgIn, conOut); } if (logFile) fclose(logFile); if (opt_Pipe) - PCLOSE(stdIn); + PCLOSE(dbgIn); return res; } + +/* EOF */ diff --git a/reactos/tools/log2lines/log2lines.mak b/reactos/tools/log2lines/log2lines.mak index 358fd83d4e8..d19d6c09a9a 100644 --- a/reactos/tools/log2lines/log2lines.mak +++ b/reactos/tools/log2lines/log2lines.mak @@ -31,6 +31,7 @@ LOG2LINES_SOURCES = \ $(LOG2LINES_BASE_)stat.c \ $(LOG2LINES_BASE_)revision.c \ $(LOG2LINES_BASE_)cmd.c \ + $(LOG2LINES_BASE_)match.c \ $(LOG2LINES_BASE_)log2lines.c \ $(RSYM_BASE_)rsym_common.c @@ -88,6 +89,10 @@ $(LOG2LINES_INT_)cmd.o: $(LOG2LINES_BASE_)cmd.c | $(LOG2LINES_INT) $(ECHO_HOSTCC) ${host_gcc} $(LOG2LINES_HOST_CFLAGS) -c $< -o $@ +$(LOG2LINES_INT_)match.o: $(LOG2LINES_BASE_)match.c | $(LOG2LINES_INT) + $(ECHO_HOSTCC) + ${host_gcc} $(LOG2LINES_HOST_CFLAGS) -c $< -o $@ + .PHONY: log2lines_clean log2lines_clean: -@$(rm) $(LOG2LINES_TARGET) $(LOG2LINES_OBJECTS) 2>$(NUL) diff --git a/reactos/tools/log2lines/match.c b/reactos/tools/log2lines/match.c new file mode 100644 index 00000000000..256a8b71902 --- /dev/null +++ b/reactos/tools/log2lines/match.c @@ -0,0 +1,91 @@ +/* + * ReactOS log2lines + * Written by Jan Roeloffzen + * + * - Custom match routines + */ + +#include + +#include "config.h" +#include "log2lines.h" +#include "match.h" + +// break pattern: show source+line +static int match_break(FILE *outFile, char *Line, int processed) +{ + static int state = 0; + + if ( processed ) return processed; + switch (state) + { + case 1: + state = 0; + break; + default: + state = 0; + } + return 1; +} +// "mod" command: update relocated addresses +static int match_mod(FILE *outFile, char *Line, int processed) +{ + static int state = 0; + char Image[NAMESIZE]; + DWORD Base; + DWORD Size; + PLIST_MEMBER plm; + + int cnt; + + if ( processed ) return processed; + if ( (cnt = sscanf(Line," Base Size %5s", Image)) == 1 ) + { + l2l_dbg(1, "Module relocate list:\n"); + state = 1; + return 0; + } + switch (state) + { + case 1: + if ( (cnt = sscanf(Line,"%lx %lx %20s", &Base, &Size, Image)) == 3 ) + { + if (( plm = entry_lookup(&cache, Image) )) + { + plm->RelBase = Base; + plm->Size = Size; + l2l_dbg(1, "Relocated: %s %08x -> %08x\n", Image, plm->ImageBase, plm->RelBase); + } + return 0; + } + else + { + state = 0; + } + break; + default: + state = 0; + } + return 1; +} + +int match_line(FILE *outFile, char *Line) +{ + int processed = 1; + + if ( *Line == '\n' || *Line == '\0' ) + return 1; + if ( strncmp(Line, KDBG_CONT, sizeof(KDBG_CONT)-1 ) == 0 ) + return 1; + + processed = match_mod(outFile, Line, processed); + processed = match_break(outFile, Line, processed); + /* more to be appended here: + * processed = match_xxx(outFile, Line, processed ); + * ... + */ + + return (int)(Line[0]); +} + +/* EOF */ diff --git a/reactos/tools/log2lines/match.h b/reactos/tools/log2lines/match.h new file mode 100644 index 00000000000..436c0134fc5 --- /dev/null +++ b/reactos/tools/log2lines/match.h @@ -0,0 +1,5 @@ +#include "util.h" + +int match_line(FILE *outFile, char *Line); + +/* EOF */ diff --git a/reactos/tools/log2lines/options.c b/reactos/tools/log2lines/options.c index 88d7f4b9e37..efa77e44d18 100644 --- a/reactos/tools/log2lines/options.c +++ b/reactos/tools/log2lines/options.c @@ -4,6 +4,7 @@ * * - Option init and parsing */ + #include #include #include @@ -16,7 +17,7 @@ #include "log2lines.h" #include "options.h" -char *optchars = "bcd:fFhl:mMP:rR:sS:tTuUvz:"; +char *optchars = "bcd:fFhl:L:mMP:rR:sS:tTuUvz:"; int opt_buffered = 0; // -b int opt_help = 0; // -h int opt_force = 0; // -f @@ -37,8 +38,10 @@ int opt_Twice = 0; // -T int opt_undo = 0; // -u int opt_redo = 0; // -U char *opt_Revision = NULL; // -R +int opt_Revision_check = 0; // -R check char opt_dir[MAX_PATH]; // -d -char opt_logFile[MAX_PATH]; // -l +char opt_logFile[MAX_PATH]; // -l|L +char *opt_mod = NULL; // -mod for opt_logFile char opt_7z[MAX_PATH]; // -z char opt_scanned[LINESIZE]; // all scanned options char opt_SourcesPath[LINESIZE]; //sources path @@ -48,6 +51,7 @@ int optionInit(int argc, const char **argv) int i; char *s; + opt_mod = "a"; strcpy(opt_dir, ""); strcpy(opt_logFile, ""); strcpy(opt_7z, CMD_7Z); @@ -70,6 +74,9 @@ int optionInit(int argc, const char **argv) case 'd': strcpy(opt_dir, argv[i+1]); break; + case 'L': + opt_mod = "w"; + //fall through case 'l': strcpy(opt_logFile, argv[i+1]); break; @@ -146,6 +153,8 @@ int optionParse(int argc, const char **argv) free(opt_Revision); opt_Revision = malloc(LINESIZE); sscanf(optarg, "%s", opt_Revision); + if (strcmp(opt_Revision, "check") == 0) + opt_Revision_check ++; break; case 's': opt_stats++; @@ -161,6 +170,7 @@ int optionParse(int argc, const char **argv) /* need to retranslate for source info: */ opt_undo++; opt_redo++; + opt_Revision_check ++; } break; case 't': @@ -208,3 +218,5 @@ int optionParse(int argc, const char **argv) return optCount; } + +/* EOF */ diff --git a/reactos/tools/log2lines/options.h b/reactos/tools/log2lines/options.h index 87b6cd0f321..a3f2d75ba83 100644 --- a/reactos/tools/log2lines/options.h +++ b/reactos/tools/log2lines/options.h @@ -28,8 +28,10 @@ extern int opt_Twice ; // -T extern int opt_undo ; // -u extern int opt_redo ; // -U extern char *opt_Revision; // -R +extern int opt_Revision_check; // -R check extern char opt_dir[]; // -d extern char opt_logFile[]; // -l +extern char *opt_mod; // mod for opt_logFile extern char opt_7z[]; // -z extern char opt_scanned[]; // all scanned options diff --git a/reactos/tools/log2lines/revision.c b/reactos/tools/log2lines/revision.c index 5a05bc66ef3..ae5fa17da37 100644 --- a/reactos/tools/log2lines/revision.c +++ b/reactos/tools/log2lines/revision.c @@ -29,7 +29,7 @@ log_rev_check(FILE *outFile, char *fileName, int showfile) if (revinfo.opt_verbose) log(outFile, "| R--- %s Last Changed Rev: %d\n", s, rev); - if (rev && opt_Revision) + if (rev && opt_Revision_check) { if (revinfo.rev < revinfo.buildrev) { @@ -128,9 +128,7 @@ getTBRevision(char *fileName) void reportRevision(FILE *outFile) { - if (!opt_Revision) - return; - if (strcmp(opt_Revision, "check") == 0) + if (opt_Revision_check) { if (lastLine.valid) logRevCheck(outFile); @@ -297,3 +295,5 @@ updateSvnlog(void) return res; } + +/* EOF */ diff --git a/reactos/tools/log2lines/stat.c b/reactos/tools/log2lines/stat.c index 6f8e5fe83c2..801f693bde2 100644 --- a/reactos/tools/log2lines/stat.c +++ b/reactos/tools/log2lines/stat.c @@ -42,3 +42,5 @@ stat_clear(PSUMM psumm) { memset(psumm, 0, sizeof(SUMM)); } + +/* EOF */ diff --git a/reactos/tools/log2lines/util.c b/reactos/tools/log2lines/util.c index 50887e3c456..19e6342934a 100644 --- a/reactos/tools/log2lines/util.c +++ b/reactos/tools/log2lines/util.c @@ -16,25 +16,25 @@ #include "options.h" int -set_LogFile(FILE *logFile) +set_LogFile(FILE **plogFile) { if (*opt_logFile) { - if (logFile) - fclose(logFile); - logFile = NULL; + if (*plogFile) + fclose(*plogFile); + *plogFile = NULL; if (strcmp(opt_logFile,"none") == 0) return 0; //just close - logFile = fopen(opt_logFile, "a"); - if (logFile) + *plogFile = fopen(opt_logFile, opt_mod ? opt_mod : "a"); + if (*plogFile) { // disable buffering so fflush is not needed if (!opt_buffered) { l2l_dbg(1, "Disabling log buffering on %s\n", opt_logFile); - setbuf(logFile, NULL); + setbuf(*plogFile, NULL); } else l2l_dbg(1, "Enabling log buffering on %s\n", opt_logFile); @@ -186,3 +186,5 @@ copy_file(char *src, char *dst) } return 0; } + +/* EOF */ diff --git a/reactos/tools/log2lines/util.h b/reactos/tools/log2lines/util.h index afb5dcfb116..8df1181b4f7 100644 --- a/reactos/tools/log2lines/util.h +++ b/reactos/tools/log2lines/util.h @@ -10,6 +10,7 @@ #include #include "cmd.h" +#include "options.h" #define log(outFile, fmt, ...) \ { \ @@ -44,6 +45,6 @@ const char *getFmt(const char *a); long my_atoi(const char *a); int isOffset(const char *a); int copy_file(char *src, char *dst); -int set_LogFile(FILE *logFile); +int set_LogFile(FILE **plogFile); /* EOF */ diff --git a/reactos/tools/log2lines/version.h b/reactos/tools/log2lines/version.h index 1222b4f56da..ad1e9299af0 100644 --- a/reactos/tools/log2lines/version.h +++ b/reactos/tools/log2lines/version.h @@ -7,6 +7,6 @@ #pragma once -#define LOG2LINES_VERSION "2.1" +#define LOG2LINES_VERSION "2.2" /* EOF */ From 920b13160cda4d27d8c26e446e76857756397308 Mon Sep 17 00:00:00 2001 From: Christoph von Wittich Date: Mon, 15 Mar 2010 17:58:48 +0000 Subject: [PATCH 31/61] [DBGHELP] sync dbghelp with wine 1.1.40 svn path=/trunk/; revision=46212 --- reactos/dll/win32/dbghelp/coff.c | 25 +- reactos/dll/win32/dbghelp/cpu_i386.c | 412 ++++++ reactos/dll/win32/dbghelp/cpu_ppc.c | 62 + reactos/dll/win32/dbghelp/cpu_x86_64.c | 132 ++ reactos/dll/win32/dbghelp/crc32.c | 149 ++ reactos/dll/win32/dbghelp/dbghelp.c | 85 +- reactos/dll/win32/dbghelp/dbghelp.rbuild | 6 + reactos/dll/win32/dbghelp/dbghelp_private.h | 135 +- reactos/dll/win32/dbghelp/dwarf.c | 211 ++- reactos/dll/win32/dbghelp/dwarf.h | 12 + reactos/dll/win32/dbghelp/elf_module.c | 224 +-- reactos/dll/win32/dbghelp/macho_module.c | 1434 +++++++++++++++++++ reactos/dll/win32/dbghelp/minidump.c | 192 +-- reactos/dll/win32/dbghelp/module.c | 120 +- reactos/dll/win32/dbghelp/msc.c | 136 +- reactos/dll/win32/dbghelp/path.c | 25 +- reactos/dll/win32/dbghelp/pe_module.c | 258 +++- reactos/dll/win32/dbghelp/rosstubs.c | 80 -- reactos/dll/win32/dbghelp/source.c | 122 +- reactos/dll/win32/dbghelp/stabs.c | 281 +++- reactos/dll/win32/dbghelp/stack.c | 545 ++----- reactos/dll/win32/dbghelp/storage.c | 73 +- reactos/dll/win32/dbghelp/symbol.c | 651 ++++++--- reactos/dll/win32/dbghelp/type.c | 79 +- reactos/dll/win32/dbghelp/version.rc | 26 + reactos/include/psdk/winternl.h | 85 +- reactos/include/reactos/wine/mscvpdb.h | 47 +- 27 files changed, 4128 insertions(+), 1479 deletions(-) create mode 100644 reactos/dll/win32/dbghelp/cpu_i386.c create mode 100644 reactos/dll/win32/dbghelp/cpu_ppc.c create mode 100644 reactos/dll/win32/dbghelp/cpu_x86_64.c create mode 100644 reactos/dll/win32/dbghelp/crc32.c create mode 100644 reactos/dll/win32/dbghelp/macho_module.c create mode 100644 reactos/dll/win32/dbghelp/version.rc diff --git a/reactos/dll/win32/dbghelp/coff.c b/reactos/dll/win32/dbghelp/coff.c index ef8632b0f09..720f00b58af 100644 --- a/reactos/dll/win32/dbghelp/coff.c +++ b/reactos/dll/win32/dbghelp/coff.c @@ -108,12 +108,18 @@ static int coff_add_file(struct CoffFileSet* coff_files, struct module* module, if (coff_files->nfiles + 1 >= coff_files->nfiles_alloc) { - coff_files->nfiles_alloc += 10; - coff_files->files = (coff_files->files) ? - HeapReAlloc(GetProcessHeap(), 0, coff_files->files, - coff_files->nfiles_alloc * sizeof(struct CoffFile)) : - HeapAlloc(GetProcessHeap(), 0, - coff_files->nfiles_alloc * sizeof(struct CoffFile)); + if (coff_files->files) + { + coff_files->nfiles_alloc *= 2; + coff_files->files = HeapReAlloc(GetProcessHeap(), 0, coff_files->files, + coff_files->nfiles_alloc * sizeof(struct CoffFile)); + } + else + { + coff_files->nfiles_alloc = 16; + coff_files->files = HeapAlloc(GetProcessHeap(), 0, + coff_files->nfiles_alloc * sizeof(struct CoffFile)); + } } file = coff_files->files + coff_files->nfiles; file->startaddr = 0xffffffff; @@ -132,7 +138,7 @@ static void coff_add_symbol(struct CoffFile* coff_file, struct symt* sym) { if (coff_file->neps + 1 >= coff_file->neps_alloc) { - coff_file->neps_alloc += 10; + coff_file->neps_alloc *= 2; coff_file->entries = (coff_file->entries) ? HeapReAlloc(GetProcessHeap(), 0, coff_file->entries, coff_file->neps_alloc * sizeof(struct symt*)) : @@ -389,6 +395,7 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg) { if (coff_files.files[j].entries != NULL) { + symt_cmp_addr_module = msc_dbg->module; qsort(coff_files.files[j].entries, coff_files.files[j].neps, sizeof(struct symt*), symt_cmp_addr); } @@ -413,7 +420,7 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg) for (;;) { if (l+1 >= coff_files.files[j].neps) break; - symt_get_info(coff_files.files[j].entries[l+1], TI_GET_ADDRESS, &addr); + symt_get_info(msc_dbg->module, coff_files.files[j].entries[l+1], TI_GET_ADDRESS, &addr); if (((msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress) < addr)) break; l++; @@ -426,7 +433,7 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg) * start of the function, so we need to subtract that offset * first. */ - symt_get_info(coff_files.files[j].entries[l+1], TI_GET_ADDRESS, &addr); + symt_get_info(msc_dbg->module, coff_files.files[j].entries[l+1], TI_GET_ADDRESS, &addr); symt_add_func_line(msc_dbg->module, (struct symt_function*)coff_files.files[j].entries[l+1], coff_files.files[j].compiland->source, linepnt->Linenumber, msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress - addr); diff --git a/reactos/dll/win32/dbghelp/cpu_i386.c b/reactos/dll/win32/dbghelp/cpu_i386.c new file mode 100644 index 00000000000..f3de6523539 --- /dev/null +++ b/reactos/dll/win32/dbghelp/cpu_i386.c @@ -0,0 +1,412 @@ +/* + * File cpu_i386.c + * + * Copyright (C) 2009-2009, Eric Pouech. + * + * 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 + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "dbghelp_private.h" +#include "wine/winbase16.h" +#include "winternl.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); + +#define STEP_FLAG 0x00000100 /* single step flag */ +#define V86_FLAG 0x00020000 + +#define IS_VM86_MODE(ctx) (ctx->EFlags & V86_FLAG) + +#ifdef __i386__ +static ADDRESS_MODE get_selector_type(HANDLE hThread, const CONTEXT* ctx, WORD sel) +{ + LDT_ENTRY le; + + if (IS_VM86_MODE(ctx)) return AddrModeReal; + /* null or system selector */ + if (!(sel & 4) || ((sel >> 3) < 17)) return AddrModeFlat; + if (hThread && GetThreadSelectorEntry(hThread, sel, &le)) + return le.HighWord.Bits.Default_Big ? AddrMode1632 : AddrMode1616; + /* selector doesn't exist */ + return -1; +} + +static unsigned i386_build_addr(HANDLE hThread, const CONTEXT* ctx, ADDRESS64* addr, + unsigned seg, unsigned long offset) +{ + addr->Mode = AddrModeFlat; + addr->Segment = seg; + addr->Offset = offset; + if (seg) + { + switch (addr->Mode = get_selector_type(hThread, ctx, seg)) + { + case AddrModeReal: + case AddrMode1616: + addr->Offset &= 0xffff; + break; + case AddrModeFlat: + case AddrMode1632: + break; + default: + return FALSE; + } + } + return TRUE; +} +#endif + +static unsigned i386_get_addr(HANDLE hThread, const CONTEXT* ctx, + enum cpu_addr ca, ADDRESS64* addr) +{ +#ifdef __i386__ + switch (ca) + { + case cpu_addr_pc: return i386_build_addr(hThread, ctx, addr, ctx->SegCs, ctx->Eip); + case cpu_addr_stack: return i386_build_addr(hThread, ctx, addr, ctx->SegSs, ctx->Esp); + case cpu_addr_frame: return i386_build_addr(hThread, ctx, addr, ctx->SegSs, ctx->Ebp); + } +#endif + return FALSE; +} + +enum st_mode {stm_start, stm_32bit, stm_16bit, stm_done}; + +/* indexes in Reserved array */ +#define __CurrentMode 0 +#define __CurrentSwitch 1 +#define __NextSwitch 2 + +#define curr_mode (frame->Reserved[__CurrentMode]) +#define curr_switch (frame->Reserved[__CurrentSwitch]) +#define next_switch (frame->Reserved[__NextSwitch]) + +static BOOL i386_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame) +{ + STACK32FRAME frame32; + STACK16FRAME frame16; + char ch; + ADDRESS64 tmp; + DWORD p; + WORD val; + BOOL do_switch; + + /* sanity check */ + if (curr_mode >= stm_done) return FALSE; + + TRACE("Enter: PC=%s Frame=%s Return=%s Stack=%s Mode=%s cSwitch=%p nSwitch=%p\n", + wine_dbgstr_addr(&frame->AddrPC), + wine_dbgstr_addr(&frame->AddrFrame), + wine_dbgstr_addr(&frame->AddrReturn), + wine_dbgstr_addr(&frame->AddrStack), + curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"), + (void*)(DWORD_PTR)curr_switch, (void*)(DWORD_PTR)next_switch); + + if (curr_mode == stm_start) + { + THREAD_BASIC_INFORMATION info; + + if ((frame->AddrPC.Mode == AddrModeFlat) && + (frame->AddrFrame.Mode != AddrModeFlat)) + { + WARN("Bad AddrPC.Mode / AddrFrame.Mode combination\n"); + goto done_err; + } + + /* Init done */ + curr_mode = (frame->AddrPC.Mode == AddrModeFlat) ? stm_32bit : stm_16bit; + + /* cur_switch holds address of WOW32Reserved field in TEB in debuggee + * address space + */ + if (NtQueryInformationThread(csw->hThread, ThreadBasicInformation, &info, + sizeof(info), NULL) == STATUS_SUCCESS) + { + curr_switch = (unsigned long)info.TebBaseAddress + FIELD_OFFSET(TEB, WOW32Reserved); + if (!sw_read_mem(csw, curr_switch, &p, sizeof(p))) + { + WARN("Can't read TEB:WOW32Reserved\n"); + goto done_err; + } + next_switch = p; + if (!next_switch) /* no 16-bit stack */ + { + curr_switch = 0; + } + else if (curr_mode == stm_16bit) + { + if (!sw_read_mem(csw, next_switch, &frame32, sizeof(frame32))) + { + WARN("Bad stack frame %p\n", (void*)(DWORD_PTR)next_switch); + goto done_err; + } + curr_switch = (DWORD)frame32.frame16; + tmp.Mode = AddrMode1616; + tmp.Segment = SELECTOROF(curr_switch); + tmp.Offset = OFFSETOF(curr_switch); + if (!sw_read_mem(csw, sw_xlat_addr(csw, &tmp), &ch, sizeof(ch))) + curr_switch = 0xFFFFFFFF; + } + else + { + tmp.Mode = AddrMode1616; + tmp.Segment = SELECTOROF(next_switch); + tmp.Offset = OFFSETOF(next_switch); + p = sw_xlat_addr(csw, &tmp); + if (!sw_read_mem(csw, p, &frame16, sizeof(frame16))) + { + WARN("Bad stack frame 0x%08x\n", p); + goto done_err; + } + curr_switch = (DWORD_PTR)frame16.frame32; + + if (!sw_read_mem(csw, curr_switch, &ch, sizeof(ch))) + curr_switch = 0xFFFFFFFF; + } + } + else + /* FIXME: this will allow to work when we're not attached to a live target, + * but the 16 <=> 32 switch facility won't be available. + */ + curr_switch = 0; + frame->AddrReturn.Mode = frame->AddrStack.Mode = (curr_mode == stm_16bit) ? AddrMode1616 : AddrModeFlat; + /* don't set up AddrStack on first call. Either the caller has set it up, or + * we will get it in the next frame + */ + memset(&frame->AddrBStore, 0, sizeof(frame->AddrBStore)); + } + else + { + if (frame->AddrFrame.Offset == 0) goto done_err; + if (frame->AddrFrame.Mode == AddrModeFlat) + { + assert(curr_mode == stm_32bit); + do_switch = curr_switch && frame->AddrFrame.Offset >= curr_switch; + } + else + { + assert(curr_mode == stm_16bit); + do_switch = curr_switch && + frame->AddrFrame.Segment == SELECTOROF(curr_switch) && + frame->AddrFrame.Offset >= OFFSETOF(curr_switch); + } + + if (do_switch) + { + if (curr_mode == stm_16bit) + { + if (!sw_read_mem(csw, next_switch, &frame32, sizeof(frame32))) + { + WARN("Bad stack frame %p\n", (void*)(DWORD_PTR)next_switch); + goto done_err; + } + + frame->AddrPC.Mode = AddrModeFlat; + frame->AddrPC.Segment = 0; + frame->AddrPC.Offset = frame32.retaddr; + frame->AddrFrame.Mode = AddrModeFlat; + frame->AddrFrame.Segment = 0; + frame->AddrFrame.Offset = frame32.ebp; + + frame->AddrStack.Mode = AddrModeFlat; + frame->AddrStack.Segment = 0; + frame->AddrReturn.Mode = AddrModeFlat; + frame->AddrReturn.Segment = 0; + + next_switch = curr_switch; + tmp.Mode = AddrMode1616; + tmp.Segment = SELECTOROF(next_switch); + tmp.Offset = OFFSETOF(next_switch); + p = sw_xlat_addr(csw, &tmp); + + if (!sw_read_mem(csw, p, &frame16, sizeof(frame16))) + { + WARN("Bad stack frame 0x%08x\n", p); + goto done_err; + } + curr_switch = (DWORD_PTR)frame16.frame32; + curr_mode = stm_32bit; + if (!sw_read_mem(csw, curr_switch, &ch, sizeof(ch))) + curr_switch = 0; + } + else + { + tmp.Mode = AddrMode1616; + tmp.Segment = SELECTOROF(next_switch); + tmp.Offset = OFFSETOF(next_switch); + p = sw_xlat_addr(csw, &tmp); + + if (!sw_read_mem(csw, p, &frame16, sizeof(frame16))) + { + WARN("Bad stack frame 0x%08x\n", p); + goto done_err; + } + + TRACE("Got a 16 bit stack switch:" + "\n\tframe32: %08lx" + "\n\tedx:%08x ecx:%08x ebp:%08x" + "\n\tds:%04x es:%04x fs:%04x gs:%04x" + "\n\tcall_from_ip:%08x module_cs:%04x relay=%08x" + "\n\tentry_ip:%04x entry_point:%08x" + "\n\tbp:%04x ip:%04x cs:%04x\n", + (unsigned long)frame16.frame32, + frame16.edx, frame16.ecx, frame16.ebp, + frame16.ds, frame16.es, frame16.fs, frame16.gs, + frame16.callfrom_ip, frame16.module_cs, frame16.relay, + frame16.entry_ip, frame16.entry_point, + frame16.bp, frame16.ip, frame16.cs); + + frame->AddrPC.Mode = AddrMode1616; + frame->AddrPC.Segment = frame16.cs; + frame->AddrPC.Offset = frame16.ip; + + frame->AddrFrame.Mode = AddrMode1616; + frame->AddrFrame.Segment = SELECTOROF(next_switch); + frame->AddrFrame.Offset = frame16.bp; + + frame->AddrStack.Mode = AddrMode1616; + frame->AddrStack.Segment = SELECTOROF(next_switch); + + frame->AddrReturn.Mode = AddrMode1616; + frame->AddrReturn.Segment = frame16.cs; + + next_switch = curr_switch; + if (!sw_read_mem(csw, next_switch, &frame32, sizeof(frame32))) + { + WARN("Bad stack frame %p\n", (void*)(DWORD_PTR)next_switch); + goto done_err; + } + curr_switch = (DWORD)frame32.frame16; + tmp.Mode = AddrMode1616; + tmp.Segment = SELECTOROF(curr_switch); + tmp.Offset = OFFSETOF(curr_switch); + + if (!sw_read_mem(csw, sw_xlat_addr(csw, &tmp), &ch, sizeof(ch))) + curr_switch = 0; + curr_mode = stm_16bit; + } + } + else + { + frame->AddrPC = frame->AddrReturn; + if (curr_mode == stm_16bit) + { + frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(WORD); + /* "pop up" previous BP value */ + if (!sw_read_mem(csw, sw_xlat_addr(csw, &frame->AddrFrame), + &val, sizeof(WORD))) + goto done_err; + frame->AddrFrame.Offset = val; + } + else + { + frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(DWORD); + /* "pop up" previous EBP value */ + if (!sw_read_mem(csw, frame->AddrFrame.Offset, + &frame->AddrFrame.Offset, sizeof(DWORD))) + goto done_err; + } + } + } + + if (curr_mode == stm_16bit) + { + unsigned int i; + + p = sw_xlat_addr(csw, &frame->AddrFrame); + if (!sw_read_mem(csw, p + sizeof(WORD), &val, sizeof(WORD))) + goto done_err; + frame->AddrReturn.Offset = val; + /* get potential cs if a far call was used */ + if (!sw_read_mem(csw, p + 2 * sizeof(WORD), &val, sizeof(WORD))) + goto done_err; + if (frame->AddrFrame.Offset & 1) + frame->AddrReturn.Segment = val; /* far call assumed */ + else + { + /* not explicitly marked as far call, + * but check whether it could be anyway + */ + if ((val & 7) == 7 && val != frame->AddrReturn.Segment) + { + LDT_ENTRY le; + + if (GetThreadSelectorEntry(csw->hThread, val, &le) && + (le.HighWord.Bits.Type & 0x08)) /* code segment */ + { + /* it is very uncommon to push a code segment cs as + * a parameter, so this should work in most cases + */ + frame->AddrReturn.Segment = val; + } + } + } + frame->AddrFrame.Offset &= ~1; + /* we "pop" parameters as 16 bit entities... of course, this won't + * work if the parameter is in fact bigger than 16bit, but + * there's no way to know that here + */ + for (i = 0; i < sizeof(frame->Params) / sizeof(frame->Params[0]); i++) + { + sw_read_mem(csw, p + (2 + i) * sizeof(WORD), &val, sizeof(val)); + frame->Params[i] = val; + } + } + else + { + if (!sw_read_mem(csw, frame->AddrFrame.Offset + sizeof(DWORD), + &frame->AddrReturn.Offset, sizeof(DWORD))) + { + WARN("Cannot read new frame offset %p\n", + (void*)(DWORD_PTR)(frame->AddrFrame.Offset + (int)sizeof(DWORD))); + goto done_err; + } + sw_read_mem(csw, frame->AddrFrame.Offset + 2 * sizeof(DWORD), + frame->Params, sizeof(frame->Params)); + } + + frame->Far = TRUE; + frame->Virtual = TRUE; + p = sw_xlat_addr(csw, &frame->AddrPC); + if (p && sw_module_base(csw, p)) + frame->FuncTableEntry = sw_table_access(csw, p); + else + frame->FuncTableEntry = NULL; + + TRACE("Leave: PC=%s Frame=%s Return=%s Stack=%s Mode=%s cSwitch=%p nSwitch=%p FuncTable=%p\n", + wine_dbgstr_addr(&frame->AddrPC), + wine_dbgstr_addr(&frame->AddrFrame), + wine_dbgstr_addr(&frame->AddrReturn), + wine_dbgstr_addr(&frame->AddrStack), + curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"), + (void*)(DWORD_PTR)curr_switch, (void*)(DWORD_PTR)next_switch, frame->FuncTableEntry); + + return TRUE; +done_err: + curr_mode = stm_done; + return FALSE; +} + +struct cpu cpu_i386 = { + IMAGE_FILE_MACHINE_I386, + 4, + i386_get_addr, + i386_stack_walk, +}; diff --git a/reactos/dll/win32/dbghelp/cpu_ppc.c b/reactos/dll/win32/dbghelp/cpu_ppc.c new file mode 100644 index 00000000000..fca5ec76ccf --- /dev/null +++ b/reactos/dll/win32/dbghelp/cpu_ppc.c @@ -0,0 +1,62 @@ +/* + * File cpu_ppc.c + * + * Copyright (C) 2009-2009, Eric Pouech. + * + * 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 + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "dbghelp_private.h" +#include "winternl.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); + +static unsigned ppc_get_addr(HANDLE hThread, const CONTEXT* ctx, + enum cpu_addr ca, ADDRESS64* addr) +{ + switch (ca) + { +#if defined(__powerpc__) + case cpu_addr_pc: + addr->Mode = AddrModeFlat; + addr->Segment = 0; /* don't need segment */ + addr->Offset = ctx->Iar; + return TRUE; +#endif + default: + case cpu_addr_stack: + case cpu_addr_frame: + FIXME("not done\n"); + } + return FALSE; +} + +static BOOL ppc_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame) +{ + FIXME("not done\n"); + return FALSE; +} + +struct cpu cpu_ppc = { + IMAGE_FILE_MACHINE_POWERPC, + 4, + ppc_get_addr, + ppc_stack_walk, +}; diff --git a/reactos/dll/win32/dbghelp/cpu_x86_64.c b/reactos/dll/win32/dbghelp/cpu_x86_64.c new file mode 100644 index 00000000000..cd0e32c5081 --- /dev/null +++ b/reactos/dll/win32/dbghelp/cpu_x86_64.c @@ -0,0 +1,132 @@ +/* + * File cpu_x86_64.c + * + * Copyright (C) 2009-2009, Eric Pouech. + * + * 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 + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "dbghelp_private.h" +#include "winternl.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); + +static unsigned x86_64_get_addr(HANDLE hThread, const CONTEXT* ctx, + enum cpu_addr ca, ADDRESS64* addr) +{ + addr->Mode = AddrModeFlat; + switch (ca) + { +#ifdef __x86_64__ + case cpu_addr_pc: addr->Segment = ctx->SegCs; addr->Offset = ctx->Rip; return TRUE; + case cpu_addr_stack: addr->Segment = ctx->SegSs; addr->Offset = ctx->Rsp; return TRUE; + case cpu_addr_frame: addr->Segment = ctx->SegSs; addr->Offset = ctx->Rbp; return TRUE; +#endif + default: addr->Mode = -1; + return FALSE; + } +} + +enum st_mode {stm_start, stm_64bit, stm_done}; + +/* indexes in Reserved array */ +#define __CurrentMode 0 +#define __CurrentSwitch 1 +#define __NextSwitch 2 + +#define curr_mode (frame->Reserved[__CurrentMode]) +#define curr_switch (frame->Reserved[__CurrentSwitch]) +#define next_switch (frame->Reserved[__NextSwitch]) + +static BOOL x86_64_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame) +{ + /* sanity check */ + if (curr_mode >= stm_done) return FALSE; + assert(!csw->is32); + + TRACE("Enter: PC=%s Frame=%s Return=%s Stack=%s Mode=%s\n", + wine_dbgstr_addr(&frame->AddrPC), + wine_dbgstr_addr(&frame->AddrFrame), + wine_dbgstr_addr(&frame->AddrReturn), + wine_dbgstr_addr(&frame->AddrStack), + curr_mode == stm_start ? "start" : "64bit"); + + if (curr_mode == stm_start) + { + if ((frame->AddrPC.Mode == AddrModeFlat) && + (frame->AddrFrame.Mode != AddrModeFlat)) + { + WARN("Bad AddrPC.Mode / AddrFrame.Mode combination\n"); + goto done_err; + } + + /* Init done */ + curr_mode = stm_64bit; + curr_switch = 0; + frame->AddrReturn.Mode = frame->AddrStack.Mode = AddrModeFlat; + /* don't set up AddrStack on first call. Either the caller has set it up, or + * we will get it in the next frame + */ + memset(&frame->AddrBStore, 0, sizeof(frame->AddrBStore)); + } + else + { + if (frame->AddrReturn.Offset == 0) goto done_err; + frame->AddrPC = frame->AddrReturn; + } + + if (!sw_read_mem(csw, frame->AddrStack.Offset, + &frame->AddrReturn.Offset, sizeof(DWORD64))) + { + WARN("Cannot read new frame offset %s\n", + wine_dbgstr_longlong(frame->AddrFrame.Offset + sizeof(DWORD64))); + goto done_err; + } + /* FIXME: simplistic stuff... need to handle both dwarf & PE stack information */ + frame->AddrStack.Offset += sizeof(DWORD64); + memset(&frame->Params, 0, sizeof(frame->Params)); + + frame->Far = TRUE; + frame->Virtual = TRUE; + if (frame->AddrPC.Offset && sw_module_base(csw, frame->AddrPC.Offset)) + frame->FuncTableEntry = sw_table_access(csw, frame->AddrPC.Offset); + else + frame->FuncTableEntry = NULL; + + TRACE("Leave: PC=%s Frame=%s Return=%s Stack=%s Mode=%s FuncTable=%p\n", + wine_dbgstr_addr(&frame->AddrPC), + wine_dbgstr_addr(&frame->AddrFrame), + wine_dbgstr_addr(&frame->AddrReturn), + wine_dbgstr_addr(&frame->AddrStack), + curr_mode == stm_start ? "start" : "64bit", + frame->FuncTableEntry); + + return TRUE; +done_err: + curr_mode = stm_done; + return FALSE; +} + +struct cpu cpu_x86_64 = { + IMAGE_FILE_MACHINE_AMD64, + 8, + x86_64_get_addr, + x86_64_stack_walk, +}; diff --git a/reactos/dll/win32/dbghelp/crc32.c b/reactos/dll/win32/dbghelp/crc32.c new file mode 100644 index 00000000000..edd42eacfba --- /dev/null +++ b/reactos/dll/win32/dbghelp/crc32.c @@ -0,0 +1,149 @@ +/* + * File crc32.c - calculate CRC32 checksum of a file + * + * Copyright (C) 1996, Eric Youngdale. + * 1999-2007 Eric Pouech + * + * 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 "config.h" +#include "wine/port.h" + +#include + +#include "dbghelp_private.h" + +/* Copyright (C) 1986 Gary S. Brown. Modified by Robert Shearman. You may use + the following calc_crc32 code or tables extracted from it, as desired without + restriction. */ + +/**********************************************************************\ +|* Demonstration program to compute the 32-bit CRC used as the frame *| +|* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71 *| +|* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level *| +|* protocol). The 32-bit FCS was added via the Federal Register, *| +|* 1 June 1982, p.23798. I presume but don't know for certain that *| +|* this polynomial is or will be included in CCITT V.41, which *| +|* defines the 16-bit CRC (often called CRC-CCITT) polynomial. FIPS *| +|* PUB 78 says that the 32-bit FCS reduces otherwise undetected *| +|* errors by a factor of 10^-5 over 16-bit FCS. *| +\**********************************************************************/ + +/* First, the polynomial itself and its table of feedback terms. The */ +/* polynomial is */ +/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ +/* Note that we take it "backwards" and put the highest-order term in */ +/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ +/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ +/* the MSB being 1. */ + +/* Note that the usual hardware shift register implementation, which */ +/* is what we're using (we're merely optimizing it by doing eight-bit */ +/* chunks at a time) shifts bits into the lowest-order term. In our */ +/* implementation, that means shifting towards the right. Why do we */ +/* do it this way? Because the calculated CRC must be transmitted in */ +/* order from highest-order term to lowest-order term. UARTs transmit */ +/* characters in order from LSB to MSB. By storing the CRC this way, */ +/* we hand it to the UART in the order low-byte to high-byte; the UART */ +/* sends each low-bit to hight-bit; and the result is transmission bit */ +/* by bit from highest- to lowest-order term without requiring any bit */ +/* shuffling on our part. Reception works similarly. */ + +/* The feedback terms table consists of 256, 32-bit entries. Notes: */ +/* */ +/* 1. The table can be generated at runtime if desired; code to do so */ +/* is shown later. It might not be obvious, but the feedback */ +/* terms simply represent the results of eight shift/xor opera- */ +/* tions for all combinations of data and CRC register values. */ +/* */ +/* 2. The CRC accumulation logic is the same for all CRC polynomials, */ +/* be they sixteen or thirty-two bits wide. You simply choose the */ +/* appropriate table. Alternatively, because the table can be */ +/* generated at runtime, you can start by generating the table for */ +/* the polynomial in question and use exactly the same "updcrc", */ +/* if your application needn't simultaneously handle two CRC */ +/* polynomials. (Note, however, that XMODEM is strange.) */ +/* */ +/* 3. For 16-bit CRCs, the table entries need be only 16 bits wide; */ +/* of course, 32-bit entries work OK if the high 16 bits are zero. */ +/* */ +/* 4. The values must be right-shifted by eight bits by the "updcrc" */ +/* logic; the shift must be unsigned (bring in zeroes). On some */ +/* hardware you could probably optimize the shift in assembler by */ +/* using byte-swap instructions. */ + + +DWORD calc_crc32(int fd) +{ +#define UPDC32(octet,crc) (crc_32_tab[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8)) + static const DWORD crc_32_tab[] = + { /* CRC polynomial 0xedb88320 */ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d + }; + int i, r; + unsigned char buffer[8192]; + DWORD crc = ~0; + + _lseek(fd, 0, SEEK_SET); + while ((r = _read(fd, buffer, sizeof(buffer))) > 0) + { + for (i = 0; i < r; i++) crc = UPDC32(buffer[i], crc); + } + return ~crc; +#undef UPDC32 +} diff --git a/reactos/dll/win32/dbghelp/dbghelp.c b/reactos/dll/win32/dbghelp/dbghelp.c index 1bfc338e596..d9a828fcef9 100644 --- a/reactos/dll/win32/dbghelp/dbghelp.c +++ b/reactos/dll/win32/dbghelp/dbghelp.c @@ -106,7 +106,7 @@ struct process* process_find_by_handle(HANDLE hProcess) */ BOOL validate_addr64(DWORD64 addr) { - if (addr >> 32) + if (sizeof(void*) == sizeof(int) && (addr >> 32)) { FIXME("Unsupported address %s\n", wine_dbgstr_longlong(addr)); SetLastError(ERROR_INVALID_PARAMETER); @@ -133,6 +133,48 @@ void* fetch_buffer(struct process* pcs, unsigned size) return pcs->buffer; } +const char* wine_dbgstr_addr(const ADDRESS64* addr) +{ + if (!addr) return "(null)"; + switch (addr->Mode) + { + case AddrModeFlat: + return wine_dbg_sprintf("flat<%s>", wine_dbgstr_longlong(addr->Offset)); + case AddrMode1616: + return wine_dbg_sprintf("1616<%04x:%04x>", addr->Segment, (DWORD)addr->Offset); + case AddrMode1632: + return wine_dbg_sprintf("1632<%04x:%08x>", addr->Segment, (DWORD)addr->Offset); + case AddrModeReal: + return wine_dbg_sprintf("real<%04x:%04x>", addr->Segment, (DWORD)addr->Offset); + default: + return "unknown"; + } +} + +extern struct cpu cpu_i386, cpu_x86_64; + +static struct cpu* dbghelp_cpus[] = {&cpu_i386, &cpu_x86_64, NULL}; +struct cpu* dbghelp_current_cpu = +#if defined(__i386__) + &cpu_i386 +#elif defined(__x86_64__) + &cpu_x86_64 +#else +#error define support for your CPU +#endif + ; + +struct cpu* cpu_find(DWORD machine) +{ + struct cpu** cpu; + + for (cpu = dbghelp_cpus ; *cpu; cpu++) + { + if (cpu[0]->machine == machine) return cpu[0]; + } + return NULL; +} + /****************************************************************** * SymSetSearchPathW (DBGHELP.@) * @@ -211,16 +253,16 @@ BOOL WINAPI SymGetSearchPath(HANDLE hProcess, PSTR szSearchPath, * SymInitialize helper: loads in dbghelp all known (and loaded modules) * this assumes that hProcess is a handle on a valid process */ -static BOOL WINAPI process_invade_cb(PCSTR name, ULONG base, ULONG size, PVOID user) +static BOOL WINAPI process_invade_cb(PCWSTR name, ULONG64 base, ULONG size, PVOID user) { - char tmp[MAX_PATH]; + WCHAR tmp[MAX_PATH]; HANDLE hProcess = user; - if (!GetModuleFileNameExA(hProcess, (HMODULE)base, - tmp, sizeof(tmp))) - lstrcpynA(tmp, name, sizeof(tmp)); + if (!GetModuleFileNameExW(hProcess, (HMODULE)(DWORD_PTR)base, + tmp, sizeof(tmp) / sizeof(WCHAR))) + lstrcpynW(tmp, name, sizeof(tmp) / sizeof(WCHAR)); - SymLoadModule(hProcess, 0, tmp, name, base, size); + SymLoadModuleExW(hProcess, 0, tmp, name, base, size, NULL, 0); return TRUE; } @@ -232,7 +274,8 @@ static BOOL check_live_target(struct process* pcs) { if (!GetProcessId(pcs->handle)) return FALSE; if (GetEnvironmentVariableA("DBGHELP_NOLIVE", NULL, 0)) return FALSE; - elf_read_wine_loader_dbg_info(pcs); + if (!elf_read_wine_loader_dbg_info(pcs)) + macho_read_wine_loader_dbg_info(pcs); return TRUE; } @@ -325,8 +368,9 @@ BOOL WINAPI SymInitializeW(HANDLE hProcess, PCWSTR UserSearchPath, BOOL fInvadeP if (check_live_target(pcs)) { if (fInvadeProcess) - EnumerateLoadedModules(hProcess, process_invade_cb, hProcess); + EnumerateLoadedModulesW64(hProcess, process_invade_cb, hProcess); elf_synchronize_module_list(pcs); + macho_synchronize_module_list(pcs); } else if (fInvadeProcess) { @@ -459,25 +503,25 @@ BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame, */ static BOOL CALLBACK reg_cb64to32(HANDLE hProcess, ULONG action, ULONG64 data, ULONG64 user) { - PSYMBOL_REGISTERED_CALLBACK cb32 = (PSYMBOL_REGISTERED_CALLBACK)(DWORD)(user >> 32); - DWORD user32 = (DWORD)user; + struct process* pcs = process_find_by_handle(hProcess); void* data32; IMAGEHLP_DEFERRED_SYMBOL_LOAD64* idsl64; IMAGEHLP_DEFERRED_SYMBOL_LOAD idsl; + if (!pcs) return FALSE; switch (action) { case CBA_DEBUG_INFO: case CBA_DEFERRED_SYMBOL_LOAD_CANCEL: case CBA_SET_OPTIONS: case CBA_SYMBOLS_UNLOADED: - data32 = (void*)(DWORD)data; + data32 = (void*)(DWORD_PTR)data; break; case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE: case CBA_DEFERRED_SYMBOL_LOAD_FAILURE: case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL: case CBA_DEFERRED_SYMBOL_LOAD_START: - idsl64 = (IMAGEHLP_DEFERRED_SYMBOL_LOAD64*)(DWORD)data; + idsl64 = (IMAGEHLP_DEFERRED_SYMBOL_LOAD64*)(DWORD_PTR)data; if (!validate_addr64(idsl64->BaseOfImage)) return FALSE; idsl.SizeOfStruct = sizeof(idsl); @@ -495,7 +539,7 @@ static BOOL CALLBACK reg_cb64to32(HANDLE hProcess, ULONG action, ULONG64 data, U FIXME("No mapping for action %u\n", action); return FALSE; } - return cb32(hProcess, action, data32, (PVOID)user32); + return pcs->reg_cb32(hProcess, action, data32, (PVOID)(DWORD_PTR)user); } /****************************************************************** @@ -522,7 +566,7 @@ BOOL pcs_callback(const struct process* pcs, ULONG action, void* data) case CBA_DEFERRED_SYMBOL_LOAD_FAILURE: case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL: case CBA_DEFERRED_SYMBOL_LOAD_START: - idslW = (IMAGEHLP_DEFERRED_SYMBOL_LOADW64*)(DWORD)data; + idslW = data; idsl.SizeOfStruct = sizeof(idsl); idsl.BaseOfImage = idslW->BaseOfImage; idsl.CheckSum = idslW->CheckSum; @@ -548,14 +592,16 @@ BOOL pcs_callback(const struct process* pcs, ULONG action, void* data) * * Helper for registering a callback. */ -static BOOL sym_register_cb(HANDLE hProcess, +static BOOL sym_register_cb(HANDLE hProcess, PSYMBOL_REGISTERED_CALLBACK64 cb, + PSYMBOL_REGISTERED_CALLBACK cb32, DWORD64 user, BOOL unicode) { struct process* pcs = process_find_by_handle(hProcess); if (!pcs) return FALSE; pcs->reg_cb = cb; + pcs->reg_cb32 = cb32; pcs->reg_is_unicode = unicode; pcs->reg_user = user; @@ -569,10 +615,9 @@ BOOL WINAPI SymRegisterCallback(HANDLE hProcess, PSYMBOL_REGISTERED_CALLBACK CallbackFunction, PVOID UserContext) { - DWORD64 tmp = ((ULONGLONG)(DWORD)CallbackFunction << 32) | (DWORD)UserContext; TRACE("(%p, %p, %p)\n", hProcess, CallbackFunction, UserContext); - return sym_register_cb(hProcess, reg_cb64to32, tmp, FALSE); + return sym_register_cb(hProcess, reg_cb64to32, CallbackFunction, (DWORD_PTR)UserContext, FALSE); } /*********************************************************************** @@ -584,7 +629,7 @@ BOOL WINAPI SymRegisterCallback64(HANDLE hProcess, { TRACE("(%p, %p, %s)\n", hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext)); - return sym_register_cb(hProcess, CallbackFunction, UserContext, FALSE); + return sym_register_cb(hProcess, CallbackFunction, NULL, UserContext, FALSE); } /*********************************************************************** @@ -596,7 +641,7 @@ BOOL WINAPI SymRegisterCallbackW64(HANDLE hProcess, { TRACE("(%p, %p, %s)\n", hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext)); - return sym_register_cb(hProcess, CallbackFunction, UserContext, TRUE); + return sym_register_cb(hProcess, CallbackFunction, NULL, UserContext, TRUE); } /* This is imagehlp version not dbghelp !! */ diff --git a/reactos/dll/win32/dbghelp/dbghelp.rbuild b/reactos/dll/win32/dbghelp/dbghelp.rbuild index 59bf735bcf0..26b829a0fe4 100644 --- a/reactos/dll/win32/dbghelp/dbghelp.rbuild +++ b/reactos/dll/win32/dbghelp/dbghelp.rbuild @@ -9,10 +9,15 @@ coff.c + cpu_i386.c + cpu_ppc.c + cpu_x86_64.c + crc32.c dbghelp.c dwarf.c elf_module.c image.c + macho_module.c memory.c minidump.c module.c @@ -27,6 +32,7 @@ storage.c symbol.c type.c + version.rc wine psapi version diff --git a/reactos/dll/win32/dbghelp/dbghelp_private.h b/reactos/dll/win32/dbghelp/dbghelp_private.h index 31dc7027e3b..e7e3c7c3c37 100644 --- a/reactos/dll/win32/dbghelp/dbghelp_private.h +++ b/reactos/dll/win32/dbghelp/dbghelp_private.h @@ -29,6 +29,7 @@ #include "objbase.h" #include "oaidl.h" #include "winnls.h" +#include "wine/list.h" #include "wine/unicode.h" #include "cvconst.h" @@ -37,13 +38,14 @@ struct pool /* poor's man */ { - struct pool_arena* first; - unsigned arena_size; + struct list arena_list; + struct list arena_full; + size_t arena_size; }; -void pool_init(struct pool* a, unsigned arena_size); +void pool_init(struct pool* a, size_t arena_size); void pool_destroy(struct pool* a); -void* pool_alloc(struct pool* a, unsigned len); +void* pool_alloc(struct pool* a, size_t len); char* pool_strdup(struct pool* a, const char* str); struct vector @@ -96,7 +98,6 @@ void hash_table_init(struct pool* pool, struct hash_table* ht, unsigned num_buckets); void hash_table_destroy(struct hash_table* ht); void hash_table_add(struct hash_table* ht, struct hash_table_elt* elt); -unsigned hash_table_hash(const char* name, unsigned num_buckets); struct hash_table_iter { @@ -116,7 +117,7 @@ void* hash_table_iter_up(struct hash_table_iter* hti); extern unsigned dbghelp_options; /* some more Wine extensions */ -#define SYMOPT_WINE_WITH_ELF_MODULES 0x40000000 +#define SYMOPT_WINE_WITH_NATIVE_MODULES 0x40000000 enum location_kind {loc_error, /* reg is the error code */ loc_absolute, /* offset is the location */ @@ -226,8 +227,6 @@ struct symt_public struct symt* container; /* compiland */ unsigned long address; unsigned long size; - unsigned in_code : 1, - is_function : 1; }; struct symt_thunk @@ -245,7 +244,7 @@ struct symt_array { struct symt symt; int start; - int end; + int end; /* end index if > 0, or -array_len (in bytes) if < 0 */ struct symt* base_type; struct symt* index_type; }; @@ -308,6 +307,7 @@ enum module_type DMT_UNKNOWN, /* for lookup, not actually used for a module */ DMT_ELF, /* a real ELF shared module */ DMT_PE, /* a native or builtin PE module */ + DMT_MACHO, /* a real Mach-O shared module */ DMT_PDB, /* .PDB file */ DMT_DBG, /* .DBG file */ }; @@ -327,12 +327,17 @@ struct module struct elf_module_info* elf_info; struct dwarf2_module_info_s*dwarf2_info; + struct macho_module_info* macho_info; + /* memory allocation pool */ struct pool pool; /* symbols & symbol tables */ + struct vector vsymt; int sortlist_valid; unsigned num_sorttab; /* number of symbols with addresses */ + unsigned num_symbols; + unsigned sorttab_size; struct symt_ht** addr_sorttab; struct hash_table ht_symbols; void (*loc_compute)(struct process* pcs, @@ -355,8 +360,9 @@ struct process struct process* next; HANDLE handle; WCHAR* search_path; - + PSYMBOL_REGISTERED_CALLBACK64 reg_cb; + PSYMBOL_REGISTERED_CALLBACK reg_cb32; BOOL reg_is_unicode; DWORD64 reg_user; @@ -411,17 +417,62 @@ struct pdb_lookup } u; }; +struct cpu_stack_walk +{ + HANDLE hProcess; + HANDLE hThread; + BOOL is32; + union + { + struct + { + PREAD_PROCESS_MEMORY_ROUTINE f_read_mem; + PTRANSLATE_ADDRESS_ROUTINE f_xlat_adr; + PFUNCTION_TABLE_ACCESS_ROUTINE f_tabl_acs; + PGET_MODULE_BASE_ROUTINE f_modl_bas; + } s32; + struct + { + PREAD_PROCESS_MEMORY_ROUTINE64 f_read_mem; + PTRANSLATE_ADDRESS_ROUTINE64 f_xlat_adr; + PFUNCTION_TABLE_ACCESS_ROUTINE64 f_tabl_acs; + PGET_MODULE_BASE_ROUTINE64 f_modl_bas; + } s64; + } u; +}; + +enum cpu_addr {cpu_addr_pc, cpu_addr_stack, cpu_addr_frame}; +struct cpu +{ + DWORD machine; + DWORD word_size; + /* address manipulation */ + unsigned (*get_addr)(HANDLE hThread, const CONTEXT* ctx, + enum cpu_addr, ADDRESS64* addr); + + /* stack manipulation */ + BOOL (*stack_walk)(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame); +}; + +extern struct cpu* dbghelp_current_cpu; + /* dbghelp.c */ extern struct process* process_find_by_handle(HANDLE hProcess); extern HANDLE hMsvcrt; extern BOOL validate_addr64(DWORD64 addr); extern BOOL pcs_callback(const struct process* pcs, ULONG action, void* data); extern void* fetch_buffer(struct process* pcs, unsigned size); +extern const char* wine_dbgstr_addr(const ADDRESS64* addr); +extern struct cpu* cpu_find(DWORD); + +/* crc32.c */ +extern DWORD calc_crc32(int fd); + +typedef BOOL (*enum_modules_cb)(const WCHAR*, unsigned long addr, void* user); /* elf_module.c */ -#define ELF_NO_MAP ((const void*)0xffffffff) -typedef BOOL (*elf_enum_modules_cb)(const WCHAR*, unsigned long addr, void* user); -extern BOOL elf_enum_modules(HANDLE hProc, elf_enum_modules_cb, void*); +#define ELF_NO_MAP ((const void*)-1) +extern BOOL elf_enum_modules(HANDLE hProc, enum_modules_cb, void*); extern BOOL elf_fetch_file_info(const WCHAR* name, DWORD* base, DWORD* size, DWORD* checksum); struct elf_file_map; extern BOOL elf_load_debug_info(struct module* module, struct elf_file_map* fmap); @@ -431,21 +482,27 @@ extern BOOL elf_read_wine_loader_dbg_info(struct process* pcs); extern BOOL elf_synchronize_module_list(struct process* pcs); struct elf_thunk_area; extern int elf_is_in_thunk_area(unsigned long addr, const struct elf_thunk_area* thunks); -extern DWORD WINAPI addr_to_linear(HANDLE hProcess, HANDLE hThread, ADDRESS* addr); + +/* macho_module.c */ +#define MACHO_NO_MAP ((const void*)-1) +extern BOOL macho_enum_modules(HANDLE hProc, enum_modules_cb, void*); +extern BOOL macho_fetch_file_info(const WCHAR* name, DWORD* base, DWORD* size, DWORD* checksum); +struct macho_file_map; +extern BOOL macho_load_debug_info(struct module* module, struct macho_file_map* fmap); +extern struct module* + macho_load_module(struct process* pcs, const WCHAR* name, unsigned long); +extern BOOL macho_read_wine_loader_dbg_info(struct process* pcs); +extern BOOL macho_synchronize_module_list(struct process* pcs); /* module.c */ extern const WCHAR S_ElfW[]; extern const WCHAR S_WineLoaderW[]; -extern const WCHAR S_WinePThreadW[]; -extern const WCHAR S_WineKThreadW[]; +extern const WCHAR S_WineW[]; extern const WCHAR S_SlashW[]; extern struct module* module_find_by_addr(const struct process* pcs, unsigned long addr, enum module_type type); -extern struct module* - module_find_by_name(const struct process* pcs, - const WCHAR* name); extern struct module* module_find_by_nameA(const struct process* pcs, const char* name); @@ -456,11 +513,8 @@ extern BOOL module_get_debug(struct module_pair*); extern struct module* module_new(struct process* pcs, const WCHAR* name, enum module_type type, BOOL virtual, - unsigned long addr, unsigned long size, + DWORD64 addr, DWORD64 size, unsigned long stamp, unsigned long checksum); -extern struct module* - module_get_container(const struct process* pcs, - const struct module* inner); extern struct module* module_get_containee(const struct process* pcs, const struct module* inner); @@ -485,13 +539,13 @@ extern BOOL path_find_symbol_file(const struct process* pcs, PCSTR full_ BOOL* is_unmatched); /* pe_module.c */ -extern BOOL pe_load_nt_header(HANDLE hProc, DWORD base, IMAGE_NT_HEADERS* nth); +extern BOOL pe_load_nt_header(HANDLE hProc, DWORD64 base, IMAGE_NT_HEADERS* nth); extern struct module* pe_load_native_module(struct process* pcs, const WCHAR* name, HANDLE hFile, DWORD base, DWORD size); extern struct module* pe_load_builtin_module(struct process* pcs, const WCHAR* name, - DWORD base, DWORD size); + DWORD64 base, DWORD64 size); extern BOOL pe_load_debug_info(const struct process* pcs, struct module* module); /* source.c */ @@ -499,9 +553,14 @@ extern unsigned source_new(struct module* module, const char* basedir, const extern const char* source_get(const struct module* module, unsigned idx); /* stabs.c */ +typedef void (*stabs_def_cb)(struct module* module, unsigned long load_offset, + const char* name, unsigned long offset, + BOOL is_public, BOOL is_global, unsigned char other, + struct symt_compiland* compiland, void* user); extern BOOL stabs_parse(struct module* module, unsigned long load_offset, const void* stabs, int stablen, - const char* strs, int strtablen); + const char* strs, int strtablen, + stabs_def_cb callback, void* user); /* dwarf.c */ extern BOOL dwarf2_parse(struct module* module, unsigned long load_offset, @@ -512,12 +571,19 @@ extern BOOL dwarf2_parse(struct module* module, unsigned long load_offse const unsigned char* line, unsigned int line_size, const unsigned char* loclist, unsigned int loclist_size); +/* stack.c */ +extern BOOL sw_read_mem(struct cpu_stack_walk* csw, DWORD64 addr, void* ptr, DWORD sz); +extern DWORD64 sw_xlat_addr(struct cpu_stack_walk* csw, ADDRESS64* addr); +extern void* sw_table_access(struct cpu_stack_walk* csw, DWORD64 addr); +extern DWORD64 sw_module_base(struct cpu_stack_walk* csw, DWORD64 addr); + /* symbol.c */ extern const char* symt_get_name(const struct symt* sym); +extern struct module* symt_cmp_addr_module; extern int symt_cmp_addr(const void* p1, const void* p2); extern void copy_symbolW(SYMBOL_INFOW* siw, const SYMBOL_INFO* si); extern struct symt_ht* - symt_find_nearest(struct module* module, DWORD addr); + symt_find_nearest(struct module* module, DWORD_PTR addr); extern struct symt_compiland* symt_new_compiland(struct module* module, unsigned long address, unsigned src_idx); @@ -525,8 +591,7 @@ extern struct symt_public* symt_new_public(struct module* module, struct symt_compiland* parent, const char* typename, - unsigned long address, unsigned size, - BOOL in_code, BOOL is_func); + unsigned long address, unsigned size); extern struct symt_data* symt_new_global_variable(struct module* module, struct symt_compiland* parent, @@ -540,7 +605,7 @@ extern struct symt_function* unsigned long addr, unsigned long size, struct symt* type); extern BOOL symt_normalize_function(struct module* module, - struct symt_function* func); + const struct symt_function* func); extern void symt_add_func_line(struct module* module, struct symt_function* func, unsigned source_idx, int line_num, @@ -558,7 +623,7 @@ extern struct symt_block* unsigned pc, unsigned len); extern struct symt_block* symt_close_func_block(struct module* module, - struct symt_function* func, + const struct symt_function* func, struct symt_block* block, unsigned pc); extern struct symt_hierarchy_point* symt_add_function_point(struct module* module, @@ -568,8 +633,8 @@ extern struct symt_hierarchy_point* const char* name); extern BOOL symt_fill_func_line_info(const struct module* module, const struct symt_function* func, - DWORD addr, IMAGEHLP_LINE* line); -extern BOOL symt_get_func_line_next(const struct module* module, PIMAGEHLP_LINE line); + DWORD64 addr, IMAGEHLP_LINE64* line); +extern BOOL symt_get_func_line_next(const struct module* module, PIMAGEHLP_LINE64 line); extern struct symt_thunk* symt_new_thunk(struct module* module, struct symt_compiland* parent, @@ -584,10 +649,12 @@ extern struct symt_hierarchy_point* symt_new_label(struct module* module, struct symt_compiland* compiland, const char* name, unsigned long address); +extern struct symt* symt_index2ptr(struct module* module, DWORD id); +extern DWORD symt_ptr2index(struct module* module, const struct symt* sym); /* type.c */ extern void symt_init_basic(struct module* module); -extern BOOL symt_get_info(const struct symt* type, +extern BOOL symt_get_info(struct module* module, const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, void* pInfo); extern struct symt_basic* symt_new_basic(struct module* module, enum BasicType, diff --git a/reactos/dll/win32/dbghelp/dwarf.c b/reactos/dll/win32/dbghelp/dwarf.c index 3667c6769cc..433dca88ff4 100644 --- a/reactos/dll/win32/dbghelp/dwarf.c +++ b/reactos/dll/win32/dbghelp/dwarf.c @@ -72,7 +72,7 @@ static void dump(const void* ptr, unsigned len) int i, j; BYTE msg[128]; static const char hexof[] = "0123456789abcdef"; - const BYTE* x = (const BYTE*)ptr; + const BYTE* x = ptr; for (i = 0; i < len; i += 16) { @@ -217,7 +217,7 @@ static unsigned char dwarf2_parse_byte(dwarf2_traverse_context_t* ctx) static unsigned short dwarf2_get_u2(const unsigned char* ptr) { - return *(const unsigned short*)ptr; + return *(const UINT16*)ptr; } static unsigned short dwarf2_parse_u2(dwarf2_traverse_context_t* ctx) @@ -229,7 +229,7 @@ static unsigned short dwarf2_parse_u2(dwarf2_traverse_context_t* ctx) static unsigned long dwarf2_get_u4(const unsigned char* ptr) { - return *(const unsigned long*)ptr; + return *(const UINT32*)ptr; } static unsigned long dwarf2_parse_u4(dwarf2_traverse_context_t* ctx) @@ -239,6 +239,18 @@ static unsigned long dwarf2_parse_u4(dwarf2_traverse_context_t* ctx) return uvalue; } +static DWORD64 dwarf2_get_u8(const unsigned char* ptr) +{ + return *(const UINT64*)ptr; +} + +static DWORD64 dwarf2_parse_u8(dwarf2_traverse_context_t* ctx) +{ + DWORD64 uvalue = dwarf2_get_u8(ctx->data); + ctx->data += 8; + return uvalue; +} + static unsigned long dwarf2_get_leb128_as_unsigned(const unsigned char* ptr, const unsigned char** end) { unsigned long ret = 0; @@ -309,6 +321,13 @@ static unsigned dwarf2_leb128_length(const dwarf2_traverse_context_t* ctx) return ret + 1; } +/****************************************************************** + * dwarf2_get_addr + * + * Returns an address. + * We assume that in all cases word size from Dwarf matches the size of + * addresses in platform where the exec is compiled. + */ static unsigned long dwarf2_get_addr(const unsigned char* ptr, unsigned word_size) { unsigned long ret; @@ -318,6 +337,9 @@ static unsigned long dwarf2_get_addr(const unsigned char* ptr, unsigned word_siz case 4: ret = dwarf2_get_u4(ptr); break; + case 8: + ret = dwarf2_get_u8(ptr); + break; default: FIXME("Unsupported Word Size %u\n", word_size); ret = 0; @@ -490,7 +512,9 @@ static void dwarf2_fill_attr(const dwarf2_parse_context_t* ctx, break; case DW_FORM_data8: - FIXME("Unhandled 64bits support\n"); + attr->u.block.size = 8; + attr->u.block.ptr = data; + data += 8; break; case DW_FORM_ref1: @@ -652,7 +676,7 @@ static enum location_error compute_location(dwarf2_traverse_context_t* ctx, struct location* loc, HANDLE hproc, const struct location* frame) { - unsigned long stack[64]; + DWORD_PTR tmp, stack[64]; unsigned stk; unsigned char op; BOOL piece_found = FALSE; @@ -665,27 +689,11 @@ compute_location(dwarf2_traverse_context_t* ctx, struct location* loc, while (ctx->data < ctx->end_data) { op = dwarf2_parse_byte(ctx); - switch (op) + + if (op >= DW_OP_lit0 && op <= DW_OP_lit31) + stack[++stk] = op - DW_OP_lit0; + else if (op >= DW_OP_reg0 && op <= DW_OP_reg31) { - case DW_OP_addr: stack[++stk] = dwarf2_parse_addr(ctx); break; - case DW_OP_const1u: stack[++stk] = dwarf2_parse_byte(ctx); break; - case DW_OP_const1s: stack[++stk] = (long)(signed char)dwarf2_parse_byte(ctx); break; - case DW_OP_const2u: stack[++stk] = dwarf2_parse_u2(ctx); break; - case DW_OP_const2s: stack[++stk] = (long)(short)dwarf2_parse_u2(ctx); break; - case DW_OP_const4u: stack[++stk] = dwarf2_parse_u4(ctx); break; - case DW_OP_const4s: stack[++stk] = dwarf2_parse_u4(ctx); break; - case DW_OP_constu: stack[++stk] = dwarf2_leb128_as_unsigned(ctx); break; - case DW_OP_consts: stack[++stk] = dwarf2_leb128_as_signed(ctx); break; - case DW_OP_plus_uconst: - stack[stk] += dwarf2_leb128_as_unsigned(ctx); break; - case DW_OP_reg0: case DW_OP_reg1: case DW_OP_reg2: case DW_OP_reg3: - case DW_OP_reg4: case DW_OP_reg5: case DW_OP_reg6: case DW_OP_reg7: - case DW_OP_reg8: case DW_OP_reg9: case DW_OP_reg10: case DW_OP_reg11: - case DW_OP_reg12: case DW_OP_reg13: case DW_OP_reg14: case DW_OP_reg15: - case DW_OP_reg16: case DW_OP_reg17: case DW_OP_reg18: case DW_OP_reg19: - case DW_OP_reg20: case DW_OP_reg21: case DW_OP_reg22: case DW_OP_reg23: - case DW_OP_reg24: case DW_OP_reg25: case DW_OP_reg26: case DW_OP_reg27: - case DW_OP_reg28: case DW_OP_reg29: case DW_OP_reg30: case DW_OP_reg31: /* dbghelp APIs don't know how to cope with this anyway * (for example 'long long' stored in two registers) * FIXME: We should tell winedbg how to deal with it (sigh) @@ -698,15 +706,9 @@ compute_location(dwarf2_traverse_context_t* ctx, struct location* loc, loc->reg = dwarf2_map_register(op - DW_OP_reg0); } loc->kind = loc_register; - break; - case DW_OP_breg0: case DW_OP_breg1: case DW_OP_breg2: case DW_OP_breg3: - case DW_OP_breg4: case DW_OP_breg5: case DW_OP_breg6: case DW_OP_breg7: - case DW_OP_breg8: case DW_OP_breg9: case DW_OP_breg10: case DW_OP_breg11: - case DW_OP_breg12: case DW_OP_breg13: case DW_OP_breg14: case DW_OP_breg15: - case DW_OP_breg16: case DW_OP_breg17: case DW_OP_breg18: case DW_OP_breg19: - case DW_OP_breg20: case DW_OP_breg21: case DW_OP_breg22: case DW_OP_breg23: - case DW_OP_breg24: case DW_OP_breg25: case DW_OP_breg26: case DW_OP_breg27: - case DW_OP_breg28: case DW_OP_breg29: case DW_OP_breg30: case DW_OP_breg31: + } + else if (op >= DW_OP_breg0 && op <= DW_OP_breg31) + { /* dbghelp APIs don't know how to cope with this anyway * (for example 'long long' stored in two registers) * FIXME: We should tell winedbg how to deal with it (sigh) @@ -714,13 +716,71 @@ compute_location(dwarf2_traverse_context_t* ctx, struct location* loc, if (!piece_found) { if (loc->reg != Wine_DW_no_register) - FIXME("Only supporting one reg (%d -> %d)\n", + FIXME("Only supporting one breg (%d -> %d)\n", loc->reg, dwarf2_map_register(op - DW_OP_breg0)); loc->reg = dwarf2_map_register(op - DW_OP_breg0); } stack[++stk] = dwarf2_leb128_as_signed(ctx); loc->kind = loc_regrel; break; + } + else switch (op) + { + case DW_OP_nop: break; + case DW_OP_addr: stack[++stk] = dwarf2_parse_addr(ctx); break; + case DW_OP_const1u: stack[++stk] = dwarf2_parse_byte(ctx); break; + case DW_OP_const1s: stack[++stk] = dwarf2_parse_byte(ctx); break; + case DW_OP_const2u: stack[++stk] = dwarf2_parse_u2(ctx); break; + case DW_OP_const2s: stack[++stk] = dwarf2_parse_u2(ctx); break; + case DW_OP_const4u: stack[++stk] = dwarf2_parse_u4(ctx); break; + case DW_OP_const4s: stack[++stk] = dwarf2_parse_u4(ctx); break; + case DW_OP_const8u: stack[++stk] = dwarf2_parse_u8(ctx); break; + case DW_OP_const8s: stack[++stk] = dwarf2_parse_u8(ctx); break; + case DW_OP_constu: stack[++stk] = dwarf2_leb128_as_unsigned(ctx); break; + case DW_OP_consts: stack[++stk] = dwarf2_leb128_as_signed(ctx); break; + case DW_OP_dup: stack[stk + 1] = stack[stk]; stk++; break; + case DW_OP_drop: stk--; break; + case DW_OP_over: stack[stk + 1] = stack[stk - 1]; stk++; break; + case DW_OP_pick: stack[stk + 1] = stack[stk - dwarf2_parse_byte(ctx)]; stk++; break; + case DW_OP_swap: tmp = stack[stk]; stack[stk] = stack[stk-1]; stack[stk-1] = tmp; break; + case DW_OP_rot: tmp = stack[stk]; stack[stk] = stack[stk-1]; stack[stk-1] = stack[stk-2]; stack[stk-2] = tmp; break; + case DW_OP_abs: stack[stk] = labs(stack[stk]); break; + case DW_OP_neg: stack[stk] = -stack[stk]; break; + case DW_OP_not: stack[stk] = ~stack[stk]; break; + case DW_OP_and: stack[stk-1] &= stack[stk]; stk--; break; + case DW_OP_or: stack[stk-1] |= stack[stk]; stk--; break; + case DW_OP_minus: stack[stk-1] -= stack[stk]; stk--; break; + case DW_OP_mul: stack[stk-1] *= stack[stk]; stk--; break; + case DW_OP_plus: stack[stk-1] += stack[stk]; stk--; break; + case DW_OP_xor: stack[stk-1] ^= stack[stk]; stk--; break; + case DW_OP_shl: stack[stk-1] <<= stack[stk]; stk--; break; + case DW_OP_shr: stack[stk-1] >>= stack[stk]; stk--; break; + case DW_OP_plus_uconst: stack[stk] += dwarf2_leb128_as_unsigned(ctx); break; + case DW_OP_shra: stack[stk-1] = stack[stk-1] / (1 << stack[stk]); stk--; break; + case DW_OP_div: stack[stk-1] = stack[stk-1] / stack[stk]; stk--; break; + case DW_OP_mod: stack[stk-1] = stack[stk-1] % stack[stk]; stk--; break; + case DW_OP_ge: stack[stk-1] = (stack[stk-1] >= stack[stk]); stk--; break; + case DW_OP_gt: stack[stk-1] = (stack[stk-1] > stack[stk]); stk--; break; + case DW_OP_le: stack[stk-1] = (stack[stk-1] <= stack[stk]); stk--; break; + case DW_OP_lt: stack[stk-1] = (stack[stk-1] < stack[stk]); stk--; break; + case DW_OP_eq: stack[stk-1] = (stack[stk-1] == stack[stk]); stk--; break; + case DW_OP_ne: stack[stk-1] = (stack[stk-1] != stack[stk]); stk--; break; + case DW_OP_skip: tmp = dwarf2_parse_u2(ctx); ctx->data += tmp; break; + case DW_OP_bra: tmp = dwarf2_parse_u2(ctx); if (!stack[stk--]) ctx->data += tmp; break; + case DW_OP_regx: + if (loc->reg != Wine_DW_no_register) + FIXME("Only supporting one regx\n"); + loc->reg = dwarf2_map_register(dwarf2_leb128_as_unsigned(ctx)); + loc->kind = loc_register; + break; + case DW_OP_bregx: + tmp = dwarf2_leb128_as_unsigned(ctx); + ctx->data++; + if (loc->reg != Wine_DW_no_register) + FIXME("Only supporting one regx\n"); + loc->reg = dwarf2_map_register(tmp) + dwarf2_leb128_as_signed(ctx); + loc->kind = loc_register; + break; case DW_OP_fbreg: if (loc->reg != Wine_DW_no_register) FIXME("Only supporting one reg (%d -> -2)\n", loc->reg); @@ -765,12 +825,12 @@ compute_location(dwarf2_traverse_context_t* ctx, struct location* loc, } if (hproc) { - DWORD addr = stack[stk--]; - DWORD deref; + DWORD_PTR addr = stack[stk--]; + DWORD_PTR deref; if (!ReadProcessMemory(hproc, (void*)addr, &deref, sizeof(deref), NULL)) { - WARN("Couldn't read memory at %x\n", addr); + WARN("Couldn't read memory at %lx\n", addr); return loc_err_cant_read; } stack[++stk] = deref; @@ -780,8 +840,46 @@ compute_location(dwarf2_traverse_context_t* ctx, struct location* loc, loc->kind = loc_dwarf2_block; } break; + case DW_OP_deref_size: + if (!stk) + { + FIXME("Unexpected empty stack\n"); + return loc_err_internal; + } + if (loc->reg != Wine_DW_no_register) + { + WARN("Too complex expression for deref\n"); + return loc_err_too_complex; + } + if (hproc) + { + DWORD_PTR addr = stack[stk--]; + BYTE derefsize = dwarf2_parse_byte(ctx); + DWORD64 deref; + + if (!ReadProcessMemory(hproc, (void*)addr, &deref, derefsize, NULL)) + { + WARN("Couldn't read memory at %lx\n", addr); + return loc_err_cant_read; + } + + switch (derefsize) + { + case 1: stack[++stk] = *(unsigned char*)&deref; break; + case 2: stack[++stk] = *(unsigned short*)&deref; break; + case 4: stack[++stk] = *(DWORD*)&deref; break; + case 8: if (ctx->word_size >= derefsize) stack[++stk] = deref; break; + } + } + else + { + loc->kind = loc_dwarf2_block; + } + break; default: - FIXME("Unhandled attr op: %x\n", op); + if (op < DW_OP_lo_user) /* as DW_OP_hi_user is 0xFF, we don't need to test against it */ + FIXME("Unhandled attr op: %x\n", op); + /* FIXME else unhandled extension */ return loc_err_internal; } } @@ -1163,7 +1261,8 @@ static void dwarf2_parse_udt_member(dwarf2_parse_context_t* ctx, if (!dwarf2_find_attribute(ctx, di, DW_AT_byte_size, &nbytes)) { DWORD64 size; - nbytes.u.uvalue = symt_get_info(elt_type, TI_GET_LENGTH, &size) ? (unsigned long)size : 0; + nbytes.u.uvalue = symt_get_info(ctx->module, elt_type, TI_GET_LENGTH, &size) ? + (unsigned long)size : 0; } bit_offset.u.uvalue = nbytes.u.uvalue * 8 - bit_offset.u.uvalue - bit_size.u.uvalue; } @@ -1214,6 +1313,10 @@ static struct symt* dwarf2_parse_udt_type(dwarf2_parse_context_t* ctx, case DW_TAG_union_type: case DW_TAG_typedef: /* FIXME: we need to handle nested udt definitions */ + case DW_TAG_inheritance: + case DW_TAG_subprogram: + case DW_TAG_variable: + /* FIXME: some C++ related stuff */ break; default: FIXME("Unhandled Tag type 0x%lx at %s, for %s\n", @@ -1334,6 +1437,8 @@ static void dwarf2_parse_variable(dwarf2_subprogram_t* subpgm, switch (loc.kind) { + case loc_error: + break; case loc_absolute: /* it's a global variable */ /* FIXME: we don't handle its scope yet */ @@ -1389,11 +1494,28 @@ static void dwarf2_parse_variable(dwarf2_subprogram_t* subpgm, v.n1.n2.n3.byref = pool_strdup(&subpgm->ctx->module->pool, value.u.string); break; - case DW_FORM_data8: case DW_FORM_block: case DW_FORM_block1: case DW_FORM_block2: case DW_FORM_block4: + v.n1.n2.vt = VT_I4; + switch (value.u.block.size) + { + case 1: v.n1.n2.n3.lVal = *(BYTE*)value.u.block.ptr; break; + case 2: v.n1.n2.n3.lVal = *(USHORT*)value.u.block.ptr; break; + case 4: v.n1.n2.n3.lVal = *(DWORD*)value.u.block.ptr; break; + default: + v.n1.n2.vt = VT_I1 | VT_BYREF; + v.n1.n2.n3.byref = pool_alloc(&subpgm->ctx->module->pool, value.u.block.size); + memcpy(v.n1.n2.n3.byref, value.u.block.ptr, value.u.block.size); + } + break; + + case DW_FORM_data8: + v.n1.n2.vt = VT_I1 | VT_BYREF; + v.n1.n2.n3.byref = pool_alloc(&subpgm->ctx->module->pool, value.u.block.size); + memcpy(v.n1.n2.n3.byref, value.u.block.ptr, value.u.block.size); + break; default: FIXME("Unsupported form for const value %s (%lx)\n", @@ -1786,6 +1908,11 @@ static void dwarf2_load_one_entry(dwarf2_parse_context_t* ctx, dwarf2_parse_variable(&subpgm, NULL, di); } break; + /* silence a couple of C++ defines */ + case DW_TAG_namespace: + case DW_TAG_imported_module: + case DW_TAG_imported_declaration: + break; default: FIXME("Unhandled Tag type 0x%lx at %s, for %lu\n", di->abbrev->tag, dwarf2_debug_ctx(ctx), di->abbrev->entry_code); @@ -2010,7 +2137,7 @@ static BOOL dwarf2_parse_compilation_unit(const dwarf2_section_t* sections, cu_ctx.word_size = dwarf2_parse_byte(&cu_ctx); TRACE("Compilation Unit Header found at 0x%x:\n", - comp_unit_start - sections[section_debug].address); + (int)(comp_unit_start - sections[section_debug].address)); TRACE("- length: %lu\n", cu_length); TRACE("- version: %u\n", cu_version); TRACE("- abbrev_offset: %lu\n", cu_abbrev_offset); diff --git a/reactos/dll/win32/dbghelp/dwarf.h b/reactos/dll/win32/dbghelp/dwarf.h index e7a0a7e4824..a590df2c9f0 100644 --- a/reactos/dll/win32/dbghelp/dwarf.h +++ b/reactos/dll/win32/dbghelp/dwarf.h @@ -376,6 +376,18 @@ typedef enum dwarf_operation_e DW_OP_call2 = 0x98, DW_OP_call4 = 0x99, DW_OP_call_ref = 0x9a, + DW_OP_form_tls_address = 0x9b, + DW_OP_call_frame_cfa = 0x9c, + DW_OP_bit_piece = 0x9d, + + /* Implementation defined extensions */ + DW_OP_lo_user = 0xe0, + DW_OP_hi_user = 0xff, + + /* GNU extensions */ + DW_OP_GNU_push_tls_address = 0xe0, + DW_OP_GNU_uninit = 0xf0, + DW_OP_GNU_encoded_addr = 0xf1, } dwarf_operation_t; enum dwarf_calling_convention diff --git a/reactos/dll/win32/dbghelp/elf_module.c b/reactos/dll/win32/dbghelp/elf_module.c index 30b7a3c0102..6a8a1515f9d 100644 --- a/reactos/dll/win32/dbghelp/elf_module.c +++ b/reactos/dll/win32/dbghelp/elf_module.c @@ -77,7 +77,7 @@ struct elf_module_info { - unsigned long elf_addr; + DWORD_PTR elf_addr; unsigned short elf_mark : 1, elf_loader : 1; }; @@ -93,22 +93,36 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); struct elf_info { unsigned flags; /* IN one (or several) of the ELF_INFO constants */ - unsigned long dbg_hdr_addr; /* OUT address of debug header (if ELF_INFO_DEBUG_HEADER is set) */ + DWORD_PTR dbg_hdr_addr; /* OUT address of debug header (if ELF_INFO_DEBUG_HEADER is set) */ struct module* module; /* OUT loaded module (if ELF_INFO_MODULE is set) */ const WCHAR* module_name; /* OUT found module name (if ELF_INFO_NAME is set) */ }; +#ifdef _WIN64 +#define Elf_Ehdr Elf64_Ehdr +#define Elf_Shdr Elf64_Shdr +#define Elf_Phdr Elf64_Phdr +#define Elf_Dyn Elf64_Dyn +#define Elf_Sym Elf64_Sym +#else +#define Elf_Ehdr Elf32_Ehdr +#define Elf_Shdr Elf32_Shdr +#define Elf_Phdr Elf32_Phdr +#define Elf_Dyn Elf32_Dyn +#define Elf_Sym Elf32_Sym +#endif + /* structure holding information while handling an ELF image * allows one by one section mapping for memory savings */ struct elf_file_map { - Elf32_Ehdr elfhdr; + Elf_Ehdr elfhdr; size_t elf_size; size_t elf_start; struct { - Elf32_Shdr shdr; + Elf_Shdr shdr; const char* mapped; }* sect; int fd; @@ -125,7 +139,7 @@ struct elf_section_map struct symtab_elt { struct hash_table_elt ht_elt; - const Elf32_Sym* symp; + const Elf_Sym* symp; struct symt_compiland* compiland; unsigned used; }; @@ -237,7 +251,7 @@ static void elf_end_find(struct elf_file_map* fmap) * * Get the size of an ELF section */ -static inline unsigned elf_get_map_size(struct elf_section_map* esm) +static inline unsigned elf_get_map_size(const struct elf_section_map* esm) { if (esm->sidx < 0 || esm->sidx >= esm->fmap->elfhdr.e_shnum) return 0; @@ -254,7 +268,7 @@ static BOOL elf_map_file(const WCHAR* filenameW, struct elf_file_map* fmap) static const BYTE elf_signature[4] = { ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3 }; struct stat statbuf; int i; - Elf32_Phdr phdr; + Elf_Phdr phdr; unsigned tmp, page_mask = getpagesize() - 1; char* filename; unsigned len; @@ -279,7 +293,12 @@ static BOOL elf_map_file(const WCHAR* filenameW, struct elf_file_map* fmap) /* and check for an ELF header */ if (memcmp(fmap->elfhdr.e_ident, elf_signature, sizeof(elf_signature))) goto done; - + /* and check 32 vs 64 size according to current machine */ +#ifdef _WIN64 + if (fmap->elfhdr.e_ident[EI_CLASS] != ELFCLASS64) goto done; +#else + if (fmap->elfhdr.e_ident[EI_CLASS] != ELFCLASS32) goto done; +#endif fmap->sect = HeapAlloc(GetProcessHeap(), 0, fmap->elfhdr.e_shnum * sizeof(fmap->sect[0])); if (!fmap->sect) goto done; @@ -350,7 +369,7 @@ int elf_is_in_thunk_area(unsigned long addr, { unsigned i; - for (i = 0; thunks[i].symname; i++) + if (thunks) for (i = 0; thunks[i].symname; i++) { if (addr >= thunks[i].rva_start && addr < thunks[i].rva_end) return i; @@ -372,13 +391,13 @@ static void elf_hash_symtab(struct module* module, struct pool* pool, const char* symname; struct symt_compiland* compiland = NULL; const char* ptr; - const Elf32_Sym* symp; + const Elf_Sym* symp; struct symtab_elt* ste; struct elf_section_map esm, esm_str; if (!elf_find_section(fmap, ".symtab", SHT_SYMTAB, &esm) && !elf_find_section(fmap, ".dynsym", SHT_DYNSYM, &esm)) return; - if ((symp = (const Elf32_Sym*)elf_map_section(&esm)) == ELF_NO_MAP) return; + if ((symp = (const Elf_Sym*)elf_map_section(&esm)) == ELF_NO_MAP) return; esm_str.fmap = fmap; esm_str.sidx = fmap->sect[esm.sidx].shdr.sh_link; if ((strp = elf_map_section(&esm_str)) == ELF_NO_MAP) return; @@ -471,9 +490,9 @@ static void elf_hash_symtab(struct module* module, struct pool* pool, * * lookup a symbol by name in our internal hash table for the symtab */ -static const Elf32_Sym* elf_lookup_symtab(const struct module* module, +static const Elf_Sym* elf_lookup_symtab(const struct module* module, const struct hash_table* ht_symtab, - const char* name, struct symt* compiland) + const char* name, const struct symt* compiland) { struct symtab_elt* weak_result = NULL; /* without compiland name */ struct symtab_elt* result = NULL; @@ -490,7 +509,7 @@ static const Elf32_Sym* elf_lookup_symtab(const struct module* module, if (compiland) { compiland_name = source_get(module, - ((struct symt_compiland*)compiland)->source); + ((const struct symt_compiland*)compiland)->source); compiland_basename = strrchr(compiland_name, '/'); if (!compiland_basename++) compiland_basename = compiland_name; } @@ -542,12 +561,12 @@ static const Elf32_Sym* elf_lookup_symtab(const struct module* module, * - get any relevant information (address & size) from the bits we got from the * stabs debugging information */ -static void elf_finish_stabs_info(struct module* module, struct hash_table* symtab) +static void elf_finish_stabs_info(struct module* module, const struct hash_table* symtab) { struct hash_table_iter hti; void* ptr; struct symt_ht* sym; - const Elf32_Sym* symp; + const Elf_Sym* symp; hash_table_iter_init(&module->ht_symbols, &hti, NULL); while ((ptr = hash_table_iter_up(&hti))) @@ -623,13 +642,13 @@ static void elf_finish_stabs_info(struct module* module, struct hash_table* symt * * creating the thunk objects for a wine native DLL */ -static int elf_new_wine_thunks(struct module* module, struct hash_table* ht_symtab, +static int elf_new_wine_thunks(struct module* module, const struct hash_table* ht_symtab, const struct elf_thunk_area* thunks) { int j; struct hash_table_iter hti; struct symtab_elt* ste; - DWORD addr; + DWORD_PTR addr; struct symt_ht* symt; hash_table_iter_init(ht_symtab, &hti, NULL); @@ -650,8 +669,8 @@ static int elf_new_wine_thunks(struct module* module, struct hash_table* ht_symt ULONG64 ref_addr; symt = symt_find_nearest(module, addr); - if (symt) - symt_get_info(&symt->symt, TI_GET_ADDRESS, &ref_addr); + if (symt && !symt_get_info(module, &symt->symt, TI_GET_ADDRESS, &ref_addr)) + ref_addr = addr; if (!symt || addr != ref_addr) { /* creating public symbols for all the ELF symbols which haven't been @@ -687,9 +706,9 @@ static int elf_new_wine_thunks(struct module* module, struct hash_table* ht_symt ULONG64 xaddr = 0, xsize = 0; DWORD kind = -1; - symt_get_info(&symt->symt, TI_GET_ADDRESS, &xaddr); - symt_get_info(&symt->symt, TI_GET_LENGTH, &xsize); - symt_get_info(&symt->symt, TI_GET_DATAKIND, &kind); + symt_get_info(module, &symt->symt, TI_GET_ADDRESS, &xaddr); + symt_get_info(module, &symt->symt, TI_GET_LENGTH, &xsize); + symt_get_info(module, &symt->symt, TI_GET_DATAKIND, &kind); /* If none of symbols has a correct size, we consider they are both markers * Hence, we can silence this warning @@ -698,7 +717,7 @@ static int elf_new_wine_thunks(struct module* module, struct hash_table* ht_symt */ if ((xsize || ste->symp->st_size) && (kind == (ELF32_ST_BIND(ste->symp->st_info) == STB_LOCAL) ? DataIsFileStatic : DataIsGlobal)) - FIXME("Duplicate in %s: %s<%08x-%08x> %s<%s-%s>\n", + FIXME("Duplicate in %s: %s<%08lx-%08x> %s<%s-%s>\n", debugstr_w(module->module.ModuleName), ste->ht_elt.name, addr, (unsigned int)ste->symp->st_size, symt->hash_elt.name, @@ -716,7 +735,7 @@ static int elf_new_wine_thunks(struct module* module, struct hash_table* ht_symt * * Creates a set of public symbols from an ELF symtab */ -static int elf_new_public_symbols(struct module* module, struct hash_table* symtab) +static int elf_new_public_symbols(struct module* module, const struct hash_table* symtab) { struct hash_table_iter hti; struct symtab_elt* ste; @@ -730,142 +749,19 @@ static int elf_new_public_symbols(struct module* module, struct hash_table* symt { symt_new_public(module, ste->compiland, ste->ht_elt.name, module->elf_info->elf_addr + ste->symp->st_value, - ste->symp->st_size, TRUE /* FIXME */, - ELF32_ST_TYPE(ste->symp->st_info) == STT_FUNC); + ste->symp->st_size); } return TRUE; } -/* Copyright (C) 1986 Gary S. Brown. Modified by Robert Shearman. You may use - the following calc_crc32 code or tables extracted from it, as desired without - restriction. */ - -/**********************************************************************\ -|* Demonstration program to compute the 32-bit CRC used as the frame *| -|* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71 *| -|* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level *| -|* protocol). The 32-bit FCS was added via the Federal Register, *| -|* 1 June 1982, p.23798. I presume but don't know for certain that *| -|* this polynomial is or will be included in CCITT V.41, which *| -|* defines the 16-bit CRC (often called CRC-CCITT) polynomial. FIPS *| -|* PUB 78 says that the 32-bit FCS reduces otherwise undetected *| -|* errors by a factor of 10^-5 over 16-bit FCS. *| -\**********************************************************************/ - -/* First, the polynomial itself and its table of feedback terms. The */ -/* polynomial is */ -/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ -/* Note that we take it "backwards" and put the highest-order term in */ -/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ -/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ -/* the MSB being 1. */ - -/* Note that the usual hardware shift register implementation, which */ -/* is what we're using (we're merely optimizing it by doing eight-bit */ -/* chunks at a time) shifts bits into the lowest-order term. In our */ -/* implementation, that means shifting towards the right. Why do we */ -/* do it this way? Because the calculated CRC must be transmitted in */ -/* order from highest-order term to lowest-order term. UARTs transmit */ -/* characters in order from LSB to MSB. By storing the CRC this way, */ -/* we hand it to the UART in the order low-byte to high-byte; the UART */ -/* sends each low-bit to hight-bit; and the result is transmission bit */ -/* by bit from highest- to lowest-order term without requiring any bit */ -/* shuffling on our part. Reception works similarly. */ - -/* The feedback terms table consists of 256, 32-bit entries. Notes: */ -/* */ -/* 1. The table can be generated at runtime if desired; code to do so */ -/* is shown later. It might not be obvious, but the feedback */ -/* terms simply represent the results of eight shift/xor opera- */ -/* tions for all combinations of data and CRC register values. */ -/* */ -/* 2. The CRC accumulation logic is the same for all CRC polynomials, */ -/* be they sixteen or thirty-two bits wide. You simply choose the */ -/* appropriate table. Alternatively, because the table can be */ -/* generated at runtime, you can start by generating the table for */ -/* the polynomial in question and use exactly the same "updcrc", */ -/* if your application needn't simultaneously handle two CRC */ -/* polynomials. (Note, however, that XMODEM is strange.) */ -/* */ -/* 3. For 16-bit CRCs, the table entries need be only 16 bits wide; */ -/* of course, 32-bit entries work OK if the high 16 bits are zero. */ -/* */ -/* 4. The values must be right-shifted by eight bits by the "updcrc" */ -/* logic; the shift must be unsigned (bring in zeroes). On some */ -/* hardware you could probably optimize the shift in assembler by */ -/* using byte-swap instructions. */ - - -static DWORD calc_crc32(struct elf_file_map* fmap) -{ -#define UPDC32(octet,crc) (crc_32_tab[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8)) - static const DWORD crc_32_tab[] = - { /* CRC polynomial 0xedb88320 */ - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, - 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, - 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, - 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, - 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, - 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, - 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, - 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, - 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, - 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, - 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, - 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, - 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, - 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, - 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, - 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, - 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, - 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, - 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, - 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, - 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d - }; - int i, r; - unsigned char buffer[256]; - DWORD crc = ~0; - - lseek(fmap->fd, 0, SEEK_SET); - while ((r = read(fmap->fd, buffer, sizeof(buffer))) > 0) - { - for (i = 0; i < r; i++) crc = UPDC32(buffer[i], crc); - } - return ~crc; -#undef UPDC32 -} - static BOOL elf_check_debug_link(const WCHAR* file, struct elf_file_map* fmap, DWORD crc) { BOOL ret; if (!elf_map_file(file, fmap)) return FALSE; - if (!(ret = crc == calc_crc32(fmap))) + if (!(ret = crc == calc_crc32(fmap->fd))) { WARN("Bad CRC for file %s (got %08x while expecting %08x)\n", - debugstr_w(file), calc_crc32(fmap), crc); + debugstr_w(file), calc_crc32(fmap->fd), crc); elf_unmap_file(fmap); } return ret; @@ -952,7 +848,7 @@ found: * Parses a .gnu_debuglink section and loads the debug info from * the external file specified there. */ -static BOOL elf_debuglink_parse(struct elf_file_map* fmap, struct module* module, +static BOOL elf_debuglink_parse(struct elf_file_map* fmap, const struct module* module, const BYTE* debuglink) { /* The content of a debug link section is: @@ -1039,7 +935,8 @@ static BOOL elf_load_debug_info_from_map(struct module* module, /* OK, now just parse all of the stabs. */ lret = stabs_parse(module, module->elf_info->elf_addr, stab, elf_get_map_size(&stab_sect), - stabstr, elf_get_map_size(&stabstr_sect)); + stabstr, elf_get_map_size(&stabstr_sect), + NULL, NULL); if (lret) /* and fill in the missing information for stabs */ elf_finish_stabs_info(module, ht_symtab); @@ -1160,7 +1057,7 @@ BOOL elf_fetch_file_info(const WCHAR* name, DWORD* base, if (!elf_map_file(name, &fmap)) return FALSE; if (base) *base = fmap.elf_start; *size = fmap.elf_size; - *checksum = calc_crc32(&fmap); + *checksum = calc_crc32(fmap.fd); elf_unmap_file(&fmap); return TRUE; } @@ -1184,7 +1081,7 @@ static BOOL elf_load_file(struct process* pcs, const WCHAR* filename, TRACE("Processing elf file '%s' at %08lx\n", debugstr_w(filename), load_offset); - if (!elf_map_file(filename, &fmap)) goto leave; + if (!elf_map_file(filename, &fmap)) return ret; /* Next, we need to find a few of the internal ELF headers within * this thing. We need the main executable header, and the section @@ -1206,7 +1103,7 @@ static BOOL elf_load_file(struct process* pcs, const WCHAR* filename, if (elf_find_section(&fmap, ".dynamic", SHT_DYNAMIC, &esm)) { - Elf32_Dyn dyn; + Elf_Dyn dyn; char* ptr = (char*)fmap.sect[esm.sidx].shdr.sh_addr; unsigned long len; @@ -1234,7 +1131,7 @@ static BOOL elf_load_file(struct process* pcs, const WCHAR* filename, if (!elf_module_info) goto leave; elf_info->module = module_new(pcs, filename, DMT_ELF, FALSE, (load_offset) ? load_offset : fmap.elf_start, - fmap.elf_size, 0, calc_crc32(&fmap)); + fmap.elf_size, 0, calc_crc32(fmap.fd)); if (!elf_info->module) { HeapFree(GetProcessHeap(), 0, elf_module_info); @@ -1389,7 +1286,7 @@ static BOOL elf_search_and_load_file(struct process* pcs, const WCHAR* filename, */ static BOOL elf_enum_modules_internal(const struct process* pcs, const WCHAR* main_name, - elf_enum_modules_cb cb, void* user) + enum_modules_cb cb, void* user) { struct r_debug dbg_hdr; void* lm_addr; @@ -1492,9 +1389,7 @@ static BOOL elf_search_loader(struct process* pcs, struct elf_info* elf_info) const char* ptr; /* All binaries are loaded with WINELOADER (if run from tree) or by the - * main executable (either wine-kthread or wine-pthread) - * FIXME: the heuristic used to know whether we need to load wine-pthread - * or wine-kthread is not 100% safe + * main executable */ if ((ptr = getenv("WINELOADER"))) { @@ -1504,8 +1399,7 @@ static BOOL elf_search_loader(struct process* pcs, struct elf_info* elf_info) } else { - ret = elf_search_and_load_file(pcs, S_WineKThreadW, 0, elf_info) || - elf_search_and_load_file(pcs, S_WinePThreadW, 0, elf_info); + ret = elf_search_and_load_file(pcs, S_WineW, 0, elf_info); } return ret; } @@ -1533,7 +1427,7 @@ BOOL elf_read_wine_loader_dbg_info(struct process* pcs) * This function doesn't require that someone has called SymInitialize * on this very process. */ -BOOL elf_enum_modules(HANDLE hProc, elf_enum_modules_cb cb, void* user) +BOOL elf_enum_modules(HANDLE hProc, enum_modules_cb cb, void* user) { struct process pcs; struct elf_info elf_info; @@ -1638,7 +1532,7 @@ BOOL elf_read_wine_loader_dbg_info(struct process* pcs) return FALSE; } -BOOL elf_enum_modules(HANDLE hProc, elf_enum_modules_cb cb, void* user) +BOOL elf_enum_modules(HANDLE hProc, enum_modules_cb cb, void* user) { return FALSE; } diff --git a/reactos/dll/win32/dbghelp/macho_module.c b/reactos/dll/win32/dbghelp/macho_module.c new file mode 100644 index 00000000000..379596b2f58 --- /dev/null +++ b/reactos/dll/win32/dbghelp/macho_module.c @@ -0,0 +1,1434 @@ +/* + * File macho_module.c - processing of Mach-O files + * Originally based on elf_module.c + * + * Copyright (C) 1996, Eric Youngdale. + * 1999-2007 Eric Pouech + * 2009 Ken Thomases, CodeWeavers Inc. + * + * 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 "config.h" +#include "wine/port.h" + +#include "dbghelp_private.h" + +#ifdef __MACH__ + +#include +#include +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef HAVE_SYS_MMAN_H +# include +#endif + +#include +#include +#include + +#ifdef HAVE_MACH_O_DYLD_IMAGES_H +#include +#else +struct dyld_image_info { + const struct mach_header *imageLoadAddress; + const char *imageFilePath; + uintptr_t imageFileModDate; +}; + +struct dyld_all_image_infos { + uint32_t version; + uint32_t infoArrayCount; + const struct dyld_image_info *infoArray; + void* notification; + int processDetachedFromSharedRegion; +}; +#endif + +#include "winternl.h" +#include "wine/library.h" +#include "wine/debug.h" + +#ifdef WORDS_BIGENDIAN +#define swap_ulong_be_to_host(n) (n) +#else +#define swap_ulong_be_to_host(n) (RtlUlongByteSwap(n)) +#endif + +WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_macho); + + +struct macho_module_info +{ + unsigned long load_addr; + unsigned short in_use : 1, + is_loader : 1; +}; + +#define MACHO_INFO_DEBUG_HEADER 0x0001 +#define MACHO_INFO_MODULE 0x0002 +#define MACHO_INFO_NAME 0x0004 + +struct macho_info +{ + unsigned flags; /* IN one (or several) of the MACHO_INFO constants */ + unsigned long dbg_hdr_addr; /* OUT address of debug header (if MACHO_INFO_DEBUG_HEADER is set) */ + struct module* module; /* OUT loaded module (if MACHO_INFO_MODULE is set) */ + const WCHAR* module_name; /* OUT found module name (if MACHO_INFO_NAME is set) */ +}; + +/* structure holding information while handling a Mach-O image */ +#define BITS_PER_ULONG (sizeof(ULONG) * 8) +#define ULONGS_FOR_BITS(nbits) (((nbits) + BITS_PER_ULONG - 1) / BITS_PER_ULONG) +struct macho_file_map +{ + /* A copy of the Mach-O header for an individual architecture. */ + struct mach_header mach_header; + + /* The mapped load commands. */ + const struct load_command* load_commands; + + /* The portion of the file which is this architecture. mach_header was + * read from arch_offset. */ + unsigned arch_offset; + unsigned arch_size; + + /* The range of address space covered by all segments. */ + size_t segs_start; + size_t segs_size; + + /* Map of which sections contain code. Sections are accessed using 1-based + * index. Bit 0 of this bitset indicates if the bitset has been initialized. */ + RTL_BITMAP sect_is_code; + ULONG sect_is_code_buff[ULONGS_FOR_BITS(MAX_SECT + 1)]; + + /* The file. */ + int fd; +}; + +static void macho_unmap_file(struct macho_file_map* fmap); + +/****************************************************************** + * macho_calc_range + * + * For a range (offset & length) of a single architecture within + * a Mach-O file, calculate the page-aligned range of the whole file + * that encompasses it. For a fat binary, the architecture will + * itself be offset within the file, so take that into account. + */ +static void macho_calc_range(const struct macho_file_map* fmap, unsigned offset, + unsigned len, unsigned* out_aligned_offset, + unsigned* out_aligned_end, unsigned* out_aligned_len, + unsigned* out_misalign) +{ + unsigned pagemask = getpagesize() - 1; + unsigned file_offset, misalign; + + file_offset = fmap->arch_offset + offset; + misalign = file_offset & pagemask; + *out_aligned_offset = file_offset - misalign; + *out_aligned_end = (file_offset + len + pagemask) & ~pagemask; + if (out_aligned_len) + *out_aligned_len = *out_aligned_end - *out_aligned_offset; + if (out_misalign) + *out_misalign = misalign; +} + +/****************************************************************** + * macho_map_range + * + * Maps a range (offset, length in bytes) from a Mach-O file into memory + */ +static const char* macho_map_range(const struct macho_file_map* fmap, unsigned offset, unsigned len) +{ + unsigned misalign, aligned_offset, aligned_map_end, map_size; + const void* aligned_ptr; + + TRACE("(%p/%d, 0x%08x, 0x%08x)\n", fmap, fmap->fd, offset, len); + + macho_calc_range(fmap, offset, len, &aligned_offset, &aligned_map_end, + &map_size, &misalign); + + aligned_ptr = mmap(NULL, map_size, PROT_READ, MAP_PRIVATE, fmap->fd, aligned_offset); + + TRACE("Mapped (0x%08x - 0x%08x) to %p\n", aligned_offset, aligned_map_end, aligned_ptr); + + if (aligned_ptr == MAP_FAILED) return MACHO_NO_MAP; + return (const char*)aligned_ptr + misalign; +} + +/****************************************************************** + * macho_unmap_range + * + * Unmaps a range (offset, length in bytes) of a Mach-O file from memory + */ +static void macho_unmap_range(const void** mapped, const struct macho_file_map* fmap, + unsigned offset, unsigned len) +{ + TRACE("(%p, %p/%d, 0x%08x, 0x%08x)\n", mapped, fmap, fmap->fd, offset, len); + + if (mapped && *mapped != MACHO_NO_MAP) + { + unsigned misalign, aligned_offset, aligned_map_end, map_size; + void* aligned_ptr; + + macho_calc_range(fmap, offset, len, &aligned_offset, &aligned_map_end, + &map_size, &misalign); + + aligned_ptr = (char*)*mapped - misalign; + if (munmap(aligned_ptr, map_size) < 0) + WARN("Couldn't unmap the range\n"); + TRACE("Unmapped (0x%08x - 0x%08x) from %p - %p\n", aligned_offset, aligned_map_end, aligned_ptr, (char*)aligned_ptr + map_size); + *mapped = MACHO_NO_MAP; + } +} + +/****************************************************************** + * macho_map_ranges + * + * Maps two ranges (offset, length in bytes) from a Mach-O file + * into memory. If the two ranges overlap, use one mmap so that + * the munmap doesn't fragment the mapping. + */ +static BOOL macho_map_ranges(const struct macho_file_map* fmap, + unsigned offset1, unsigned len1, + unsigned offset2, unsigned len2, + const void** mapped1, const void** mapped2) +{ + unsigned aligned_offset1, aligned_map_end1; + unsigned aligned_offset2, aligned_map_end2; + + TRACE("(%p/%d, 0x%08x, 0x%08x, 0x%08x, 0x%08x, %p, %p)\n", fmap, fmap->fd, + offset1, len1, offset2, len2, mapped1, mapped2); + + macho_calc_range(fmap, offset1, len1, &aligned_offset1, &aligned_map_end1, NULL, NULL); + macho_calc_range(fmap, offset2, len2, &aligned_offset2, &aligned_map_end2, NULL, NULL); + + if (aligned_map_end1 < aligned_offset2 || aligned_map_end2 < aligned_offset1) + { + *mapped1 = macho_map_range(fmap, offset1, len1); + if (*mapped1 != MACHO_NO_MAP) + { + *mapped2 = macho_map_range(fmap, offset2, len2); + if (*mapped2 == MACHO_NO_MAP) + macho_unmap_range(mapped1, fmap, offset1, len1); + } + } + else + { + if (offset1 < offset2) + { + *mapped1 = macho_map_range(fmap, offset1, offset2 + len2 - offset1); + if (*mapped1 != MACHO_NO_MAP) + *mapped2 = (const char*)*mapped1 + offset2 - offset1; + } + else + { + *mapped2 = macho_map_range(fmap, offset2, offset1 + len1 - offset2); + if (*mapped2 != MACHO_NO_MAP) + *mapped1 = (const char*)*mapped2 + offset1 - offset2; + } + } + + TRACE(" => %p, %p\n", *mapped1, *mapped2); + + return (*mapped1 != MACHO_NO_MAP) && (*mapped2 != MACHO_NO_MAP); +} + +/****************************************************************** + * macho_unmap_ranges + * + * Unmaps two ranges (offset, length in bytes) of a Mach-O file + * from memory. Use for ranges which were mapped by + * macho_map_ranges. + */ +static void macho_unmap_ranges(const struct macho_file_map* fmap, + unsigned offset1, unsigned len1, + unsigned offset2, unsigned len2, + const void** mapped1, const void** mapped2) +{ + unsigned aligned_offset1, aligned_map_end1; + unsigned aligned_offset2, aligned_map_end2; + + TRACE("(%p/%d, 0x%08x, 0x%08x, 0x%08x, 0x%08x, %p/%p, %p/%p)\n", fmap, fmap->fd, + offset1, len1, offset2, len2, mapped1, *mapped1, mapped2, *mapped2); + + macho_calc_range(fmap, offset1, len1, &aligned_offset1, &aligned_map_end1, NULL, NULL); + macho_calc_range(fmap, offset2, len2, &aligned_offset2, &aligned_map_end2, NULL, NULL); + + if (aligned_map_end1 < aligned_offset2 || aligned_map_end2 < aligned_offset1) + { + macho_unmap_range(mapped1, fmap, offset1, len1); + macho_unmap_range(mapped2, fmap, offset2, len2); + } + else + { + if (offset1 < offset2) + { + macho_unmap_range(mapped1, fmap, offset1, offset2 + len2 - offset1); + *mapped2 = MACHO_NO_MAP; + } + else + { + macho_unmap_range(mapped2, fmap, offset2, offset1 + len1 - offset2); + *mapped1 = MACHO_NO_MAP; + } + } +} + +/****************************************************************** + * macho_map_load_commands + * + * Maps the load commands from a Mach-O file into memory + */ +static const struct load_command* macho_map_load_commands(struct macho_file_map* fmap) +{ + if (fmap->load_commands == MACHO_NO_MAP) + { + fmap->load_commands = (const struct load_command*) macho_map_range( + fmap, sizeof(fmap->mach_header), fmap->mach_header.sizeofcmds); + TRACE("Mapped load commands: %p\n", fmap->load_commands); + } + + return fmap->load_commands; +} + +/****************************************************************** + * macho_unmap_load_commands + * + * Unmaps the load commands of a Mach-O file from memory + */ +static void macho_unmap_load_commands(struct macho_file_map* fmap) +{ + if (fmap->load_commands != MACHO_NO_MAP) + { + TRACE("Unmapping load commands: %p\n", fmap->load_commands); + macho_unmap_range((const void**)&fmap->load_commands, fmap, + sizeof(fmap->mach_header), fmap->mach_header.sizeofcmds); + } +} + +/****************************************************************** + * macho_next_load_command + * + * Advance to the next load command + */ +static const struct load_command* macho_next_load_command(const struct load_command* lc) +{ + return (const struct load_command*)((const char*)lc + lc->cmdsize); +} + +/****************************************************************** + * macho_enum_load_commands + * + * Enumerates the load commands for a Mach-O file, selecting by + * the command type, calling a callback for each. If the callback + * returns <0, that indicates an error. If it returns >0, that means + * it's not interested in getting any more load commands. + * If this function returns <0, that's an error produced by the + * callback. If >=0, that's the count of load commands successfully + * processed. + */ +static int macho_enum_load_commands(struct macho_file_map* fmap, unsigned cmd, + int (*cb)(struct macho_file_map*, const struct load_command*, void*), + void* user) +{ + const struct load_command* lc; + int i; + int count = 0; + + TRACE("(%p/%d, %u, %p, %p)\n", fmap, fmap->fd, cmd, cb, user); + + if ((lc = macho_map_load_commands(fmap)) == MACHO_NO_MAP) return -1; + + TRACE("%d total commands\n", fmap->mach_header.ncmds); + + for (i = 0; i < fmap->mach_header.ncmds; i++, lc = macho_next_load_command(lc)) + { + int result; + + if (cmd && cmd != lc->cmd) continue; + count++; + + result = cb(fmap, lc, user); + TRACE("load_command[%d] (%p), cmd %u; callback => %d\n", i, lc, lc->cmd, result); + if (result) return (result < 0) ? result : count; + } + + return count; +} + +/****************************************************************** + * macho_accum_segs_range + * + * Callback for macho_enum_load_commands. Accumulates the address + * range covered by the segments of a Mach-O file. All commands + * are expected to be of LC_SEGMENT type. + */ +static int macho_accum_segs_range(struct macho_file_map* fmap, + const struct load_command* lc, void* user) +{ + const struct segment_command* sc = (const struct segment_command*)lc; + unsigned tmp, page_mask = getpagesize() - 1; + + TRACE("(%p/%d, %p, %p) before: 0x%08x - 0x%08x\n", fmap, fmap->fd, lc, user, + (unsigned)fmap->segs_start, (unsigned)fmap->segs_size); + TRACE("Segment command vm: 0x%08x - 0x%08x\n", (unsigned)sc->vmaddr, + (unsigned)sc->vmaddr + sc->vmsize); + + if (!strncmp(sc->segname, "WINE_", 5)) + { + TRACE("Ignoring special Wine segment %s\n", debugstr_an(sc->segname, sizeof(sc->segname))); + return 0; + } + + /* If this segment starts before previously-known earliest, record + * new earliest. */ + if (sc->vmaddr < fmap->segs_start) + fmap->segs_start = sc->vmaddr; + + /* If this segment extends beyond previously-known furthest, record + * new furthest. */ + tmp = (sc->vmaddr + sc->vmsize + page_mask) & ~page_mask; + if (fmap->segs_size < tmp) fmap->segs_size = tmp; + + TRACE("after: 0x%08x - 0x%08x\n", (unsigned)fmap->segs_start, (unsigned)fmap->segs_size); + + return 0; +} + +/****************************************************************** + * macho_map_file + * + * Maps a Mach-O file into memory (and checks it's a real Mach-O file) + */ +static BOOL macho_map_file(const WCHAR* filenameW, struct macho_file_map* fmap) +{ + struct fat_header fat_header; + struct stat statbuf; + int i; + char* filename; + unsigned len; + BOOL ret = FALSE; + + TRACE("(%s, %p)\n", debugstr_w(filenameW), fmap); + + fmap->fd = -1; + fmap->load_commands = MACHO_NO_MAP; + RtlInitializeBitMap(&fmap->sect_is_code, fmap->sect_is_code_buff, MAX_SECT + 1); + + len = WideCharToMultiByte(CP_UNIXCP, 0, filenameW, -1, NULL, 0, NULL, NULL); + if (!(filename = HeapAlloc(GetProcessHeap(), 0, len))) return FALSE; + WideCharToMultiByte(CP_UNIXCP, 0, filenameW, -1, filename, len, NULL, NULL); + + /* check that the file exists */ + if (stat(filename, &statbuf) == -1 || S_ISDIR(statbuf.st_mode)) goto done; + + /* Now open the file, so that we can mmap() it. */ + if ((fmap->fd = open(filename, O_RDONLY)) == -1) goto done; + + if (read(fmap->fd, &fat_header, sizeof(fat_header)) != sizeof(fat_header)) + goto done; + TRACE("... got possible fat header\n"); + + /* Fat header is always in big-endian order. */ + if (swap_ulong_be_to_host(fat_header.magic) == FAT_MAGIC) + { + int narch = swap_ulong_be_to_host(fat_header.nfat_arch); + for (i = 0; i < narch; i++) + { + struct fat_arch fat_arch; + if (read(fmap->fd, &fat_arch, sizeof(fat_arch)) != sizeof(fat_arch)) + goto done; + if (swap_ulong_be_to_host(fat_arch.cputype) == CPU_TYPE_X86) + { + fmap->arch_offset = swap_ulong_be_to_host(fat_arch.offset); + fmap->arch_size = swap_ulong_be_to_host(fat_arch.size); + break; + } + } + if (i >= narch) goto done; + TRACE("... found x86 arch\n"); + } + else + { + fmap->arch_offset = 0; + fmap->arch_size = statbuf.st_size; + TRACE("... not a fat header\n"); + } + + /* Individual architecture (standalone or within a fat file) is in its native byte order. */ + lseek(fmap->fd, fmap->arch_offset, SEEK_SET); + if (read(fmap->fd, &fmap->mach_header, sizeof(fmap->mach_header)) != sizeof(fmap->mach_header)) + goto done; + TRACE("... got possible Mach header\n"); + /* and check for a Mach-O header */ + if (fmap->mach_header.magic != MH_MAGIC || + fmap->mach_header.cputype != CPU_TYPE_X86) goto done; + /* Make sure the file type is one of the ones we expect. */ + switch (fmap->mach_header.filetype) + { + case MH_EXECUTE: + case MH_DYLIB: + case MH_DYLINKER: + case MH_BUNDLE: + break; + default: + goto done; + } + TRACE("... verified Mach x86 header\n"); + + fmap->segs_size = 0; + fmap->segs_start = ~0L; + + if (macho_enum_load_commands(fmap, LC_SEGMENT, macho_accum_segs_range, NULL) < 0) + goto done; + + fmap->segs_size -= fmap->segs_start; + TRACE("segs_start: 0x%08x, segs_size: 0x%08x\n", (unsigned)fmap->segs_start, + (unsigned)fmap->segs_size); + + ret = TRUE; +done: + if (!ret) + macho_unmap_file(fmap); + HeapFree(GetProcessHeap(), 0, filename); + return ret; +} + +/****************************************************************** + * macho_unmap_file + * + * Unmaps a Mach-O file from memory (previously mapped with macho_map_file) + */ +static void macho_unmap_file(struct macho_file_map* fmap) +{ + TRACE("(%p/%d)\n", fmap, fmap->fd); + if (fmap->fd != -1) + { + macho_unmap_load_commands(fmap); + close(fmap->fd); + fmap->fd = -1; + } +} + +/****************************************************************** + * macho_fill_sect_is_code + * + * Callback for macho_enum_load_commands. Determines which segments + * of a Mach-O file contain code. All commands are expected to be + * of LC_SEGMENT type. + */ +static int macho_fill_sect_is_code(struct macho_file_map* fmap, + const struct load_command* lc, void* user) +{ + const struct segment_command* sc = (const struct segment_command*)lc; + const struct section* sections; + int* cursect = user; + int i; + + TRACE("(%p/%d, %p, %p/%d) scanning %u sections\n", fmap, fmap->fd, lc, + cursect, *cursect, sc->nsects); + + sections = (const struct section*)(sc + 1); + for (i = 0; i < sc->nsects; i++) + { + if (*cursect > MAX_SECT) return -1; + (*cursect)++; + + if (!(sections[i].flags & SECTION_TYPE) && + (sections[i].flags & (S_ATTR_PURE_INSTRUCTIONS|S_ATTR_SOME_INSTRUCTIONS))) + RtlSetBits(&fmap->sect_is_code, *cursect, 1); + else + RtlClearBits(&fmap->sect_is_code, *cursect, 1); + TRACE("Section %d (%d of this segment) is%s code\n", *cursect, i, + (RtlAreBitsSet(&fmap->sect_is_code, *cursect, 1) ? "" : " not")); + } + + return 0; +} + +/****************************************************************** + * macho_sect_is_code + * + * Checks if a section, identified by sectidx which is a 1-based + * index into the sections of all segments, in order of load + * commands, contains code. + */ +static BOOL macho_sect_is_code(struct macho_file_map* fmap, unsigned char sectidx) +{ + TRACE("(%p/%d, %u)\n", fmap, fmap->fd, sectidx); + + if (!RtlAreBitsSet(&fmap->sect_is_code, 0, 1)) + { + int cursect = 0; + if (macho_enum_load_commands(fmap, LC_SEGMENT, macho_fill_sect_is_code, &cursect) < 0) + WARN("Couldn't load sect_is_code map\n"); + RtlSetBits(&fmap->sect_is_code, 0, 1); + } + + return RtlAreBitsSet(&fmap->sect_is_code, sectidx, 1); +} + +struct symtab_elt +{ + struct hash_table_elt ht_elt; + struct symt_compiland* compiland; + unsigned long addr; + unsigned char is_code:1, + is_public:1, + is_global:1, + used:1; +}; + +struct macho_debug_info +{ + struct macho_file_map* fmap; + struct module* module; + struct pool pool; + struct hash_table ht_symtab; +}; + +/****************************************************************** + * macho_stabs_def_cb + * + * Callback for stabs_parse. Collect symbol definitions. + */ +static void macho_stabs_def_cb(struct module* module, unsigned long load_offset, + const char* name, unsigned long offset, + BOOL is_public, BOOL is_global, unsigned char sectidx, + struct symt_compiland* compiland, void* user) +{ + struct macho_debug_info* mdi = user; + struct symtab_elt* ste; + + TRACE("(%p, 0x%08lx, %s, 0x%08lx, %d, %d, %u, %p, %p/%p/%d)\n", module, load_offset, + debugstr_a(name), offset, is_public, is_global, sectidx, + compiland, mdi, mdi->fmap, mdi->fmap->fd); + + /* Defer the creation of new non-debugging symbols until after we've + * finished parsing the stabs. */ + ste = pool_alloc(&mdi->pool, sizeof(*ste)); + ste->ht_elt.name = pool_strdup(&mdi->pool, name); + ste->compiland = compiland; + ste->addr = load_offset + offset; + ste->is_code = !!macho_sect_is_code(mdi->fmap, sectidx); + ste->is_public = !!is_public; + ste->is_global = !!is_global; + ste->used = 0; + hash_table_add(&mdi->ht_symtab, &ste->ht_elt); +} + +/****************************************************************** + * macho_parse_symtab + * + * Callback for macho_enum_load_commands. Processes the LC_SYMTAB + * load commands from the Mach-O file. + */ +static int macho_parse_symtab(struct macho_file_map* fmap, + const struct load_command* lc, void* user) +{ + const struct symtab_command* sc = (const struct symtab_command*)lc; + struct macho_debug_info* mdi = user; + const struct nlist* stab; + const char* stabstr; + int ret = 0; + + TRACE("(%p/%d, %p, %p) %u syms at 0x%08x, strings 0x%08x - 0x%08x\n", fmap, fmap->fd, lc, + user, sc->nsyms, sc->symoff, sc->stroff, sc->stroff + sc->strsize); + + if (!macho_map_ranges(fmap, sc->symoff, sc->nsyms * sizeof(struct nlist), + sc->stroff, sc->strsize, (const void**)&stab, (const void**)&stabstr)) + return 0; + + if (!stabs_parse(mdi->module, mdi->module->macho_info->load_addr - fmap->segs_start, + stab, sc->nsyms * sizeof(struct nlist), + stabstr, sc->strsize, macho_stabs_def_cb, mdi)) + ret = -1; + + macho_unmap_ranges(fmap, sc->symoff, sc->nsyms * sizeof(struct nlist), + sc->stroff, sc->strsize, (const void**)&stab, (const void**)&stabstr); + + return ret; +} + +/****************************************************************** + * macho_finish_stabs + * + * Integrate the non-debugging symbols we've gathered into the + * symbols that were generated during stabs parsing. + */ +static void macho_finish_stabs(struct module* module, struct hash_table* ht_symtab) +{ + struct hash_table_iter hti_ours; + struct symtab_elt* ste; + BOOL adjusted = FALSE; + + TRACE("(%p, %p)\n", module, ht_symtab); + + /* For each of our non-debugging symbols, see if it can provide some + * missing details to one of the module's known symbols. */ + hash_table_iter_init(ht_symtab, &hti_ours, NULL); + while ((ste = hash_table_iter_up(&hti_ours))) + { + struct hash_table_iter hti_modules; + void* ptr; + struct symt_ht* sym; + struct symt_function* func; + struct symt_data* data; + + hash_table_iter_init(&module->ht_symbols, &hti_modules, ste->ht_elt.name); + while ((ptr = hash_table_iter_up(&hti_modules))) + { + sym = GET_ENTRY(ptr, struct symt_ht, hash_elt); + + if (strcmp(sym->hash_elt.name, ste->ht_elt.name)) + continue; + + switch (sym->symt.tag) + { + case SymTagFunction: + func = (struct symt_function*)sym; + if (func->address == module->macho_info->load_addr) + { + TRACE("Adjusting function %p/%s!%s from 0x%08lx to 0x%08lx\n", func, + debugstr_w(module->module.ModuleName), sym->hash_elt.name, + func->address, ste->addr); + func->address = ste->addr; + adjusted = TRUE; + } + if (func->address == ste->addr) + ste->used = 1; + break; + case SymTagData: + data = (struct symt_data*)sym; + switch (data->kind) + { + case DataIsGlobal: + case DataIsFileStatic: + if (data->u.var.offset == module->macho_info->load_addr) + { + TRACE("Adjusting data symbol %p/%s!%s from 0x%08lx to 0x%08lx\n", + data, debugstr_w(module->module.ModuleName), sym->hash_elt.name, + data->u.var.offset, ste->addr); + data->u.var.offset = ste->addr; + adjusted = TRUE; + } + if (data->u.var.offset == ste->addr) + { + enum DataKind new_kind; + + new_kind = ste->is_global ? DataIsGlobal : DataIsFileStatic; + if (data->kind != new_kind) + { + WARN("Changing kind for %p/%s!%s from %d to %d\n", sym, + debugstr_w(module->module.ModuleName), sym->hash_elt.name, + (int)data->kind, (int)new_kind); + data->kind = new_kind; + adjusted = TRUE; + } + ste->used = 1; + } + break; + default:; + } + break; + default: + TRACE("Ignoring tag %u\n", sym->symt.tag); + break; + } + } + } + + if (adjusted) + { + /* since we may have changed some addresses, mark the module to be resorted */ + module->sortlist_valid = FALSE; + } + + /* Mark any of our non-debugging symbols which fall on an already-used + * address as "used". This allows us to skip them in the next loop, + * below. We do this in separate loops because symt_new_* marks the + * list as needing sorting and symt_find_nearest sorts if needed, + * causing thrashing. */ + if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY)) + { + hash_table_iter_init(ht_symtab, &hti_ours, NULL); + while ((ste = hash_table_iter_up(&hti_ours))) + { + struct symt_ht* sym; + ULONG64 addr; + + if (ste->used) continue; + + sym = symt_find_nearest(module, ste->addr); + if (sym) + symt_get_info(module, &sym->symt, TI_GET_ADDRESS, &addr); + if (sym && ste->addr == addr) + { + ULONG64 size = 0; + DWORD kind = -1; + + ste->used = 1; + + /* If neither symbol has a correct size (ours never does), we + * consider them both to be markers. No warning is needed in + * that case. + * Also, we check that we don't have two symbols, one local, the other + * global, which is legal. + */ + symt_get_info(module, &sym->symt, TI_GET_LENGTH, &size); + symt_get_info(module, &sym->symt, TI_GET_DATAKIND, &kind); + if (size && kind == (ste->is_global ? DataIsGlobal : DataIsFileStatic)) + FIXME("Duplicate in %s: %s<%08lx> %s<%s-%s>\n", + debugstr_w(module->module.ModuleName), + ste->ht_elt.name, ste->addr, + sym->hash_elt.name, + wine_dbgstr_longlong(addr), wine_dbgstr_longlong(size)); + } + } + } + + /* For any of our remaining non-debugging symbols which have no match + * among the module's known symbols, add them as new symbols. */ + hash_table_iter_init(ht_symtab, &hti_ours, NULL); + while ((ste = hash_table_iter_up(&hti_ours))) + { + if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY) && !ste->used) + { + if (ste->is_code) + { + symt_new_function(module, ste->compiland, ste->ht_elt.name, + ste->addr, 0, NULL); + } + else + { + symt_new_global_variable(module, ste->compiland, ste->ht_elt.name, + !ste->is_global, ste->addr, 0, NULL); + } + + ste->used = 1; + } + + if (ste->is_public && !(dbghelp_options & SYMOPT_NO_PUBLICS)) + { + symt_new_public(module, ste->compiland, ste->ht_elt.name, ste->addr, 0); + } + } +} + +/****************************************************************** + * macho_load_debug_info_from_map + * + * Loads the symbolic information from a Mach-O module. + * Returns + * FALSE if the file doesn't contain symbolic info (or this info + * cannot be read or parsed) + * TRUE on success + */ +static BOOL macho_load_debug_info_from_map(struct module* module, + struct macho_file_map* fmap) +{ + BOOL ret = FALSE; + struct macho_debug_info mdi; + int result; + + TRACE("(%p, %p/%d)\n", module, fmap, fmap->fd); + + module->module.SymType = SymExport; + + mdi.fmap = fmap; + mdi.module = module; + pool_init(&mdi.pool, 65536); + hash_table_init(&mdi.pool, &mdi.ht_symtab, 256); + result = macho_enum_load_commands(fmap, LC_SYMTAB, macho_parse_symtab, &mdi); + if (result > 0) + ret = TRUE; + else if (result < 0) + WARN("Couldn't correctly read stabs\n"); + + macho_finish_stabs(module, &mdi.ht_symtab); + + pool_destroy(&mdi.pool); + return ret; +} + +/****************************************************************** + * macho_load_debug_info + * + * Loads Mach-O debugging information from the module image file. + */ +BOOL macho_load_debug_info(struct module* module, struct macho_file_map* fmap) +{ + BOOL ret = TRUE; + struct macho_file_map my_fmap; + + TRACE("(%p, %p/%d)\n", module, fmap, fmap ? fmap->fd : -1); + + if (module->type != DMT_MACHO || !module->macho_info) + { + ERR("Bad Mach-O module '%s'\n", debugstr_w(module->module.LoadedImageName)); + return FALSE; + } + + if (!fmap) + { + fmap = &my_fmap; + ret = macho_map_file(module->module.LoadedImageName, fmap); + } + if (ret) + ret = macho_load_debug_info_from_map(module, fmap); + + if (fmap == &my_fmap) macho_unmap_file(fmap); + return ret; +} + +/****************************************************************** + * macho_fetch_file_info + * + * Gathers some more information for a Mach-O module from a given file + */ +BOOL macho_fetch_file_info(const WCHAR* name, DWORD* base, + DWORD* size, DWORD* checksum) +{ + struct macho_file_map fmap; + + TRACE("(%s, %p, %p, %p)\n", debugstr_w(name), base, size, checksum); + + if (!macho_map_file(name, &fmap)) return FALSE; + if (base) *base = fmap.segs_start; + *size = fmap.segs_size; + *checksum = calc_crc32(fmap.fd); + macho_unmap_file(&fmap); + return TRUE; +} + +/****************************************************************** + * macho_load_file + * + * Loads the information for Mach-O module stored in 'filename'. + * The module has been loaded at 'load_addr' address. + * returns + * FALSE if the file cannot be found/opened or if the file doesn't + * contain symbolic info (or this info cannot be read or parsed) + * TRUE on success + */ +static BOOL macho_load_file(struct process* pcs, const WCHAR* filename, + unsigned long load_addr, struct macho_info* macho_info) +{ + BOOL ret = TRUE; + struct macho_file_map fmap; + + TRACE("(%p/%p, %s, 0x%08lx, %p/0x%08x)\n", pcs, pcs->handle, debugstr_w(filename), + load_addr, macho_info, macho_info->flags); + + if (!macho_map_file(filename, &fmap)) return FALSE; + + /* Find the dynamic loader's table of images loaded into the process. + */ + if (macho_info->flags & MACHO_INFO_DEBUG_HEADER) + { + static void* dyld_all_image_infos_addr; + + /* This symbol should be in the same place in all processes. */ + if (!dyld_all_image_infos_addr) + { + struct nlist nl[2]; + memset(nl, 0, sizeof(nl)); + nl[0].n_un.n_name = (char*)"_dyld_all_image_infos"; + if (!nlist("/usr/lib/dyld", nl)) + dyld_all_image_infos_addr = (void*)nl[0].n_value; + } + + if (dyld_all_image_infos_addr) + macho_info->dbg_hdr_addr = (unsigned long)dyld_all_image_infos_addr; + else + ret = FALSE; + TRACE("dbg_hdr_addr = 0x%08lx\n", macho_info->dbg_hdr_addr); + } + + if (macho_info->flags & MACHO_INFO_MODULE) + { + struct macho_module_info *macho_module_info = + HeapAlloc(GetProcessHeap(), 0, sizeof(struct macho_module_info)); + if (!macho_module_info) goto leave; + macho_info->module = module_new(pcs, filename, DMT_MACHO, FALSE, load_addr, + fmap.segs_size, 0, calc_crc32(fmap.fd)); + if (!macho_info->module) + { + HeapFree(GetProcessHeap(), 0, macho_module_info); + goto leave; + } + macho_info->module->macho_info = macho_module_info; + macho_info->module->macho_info->load_addr = load_addr; + + if (dbghelp_options & SYMOPT_DEFERRED_LOADS) + macho_info->module->module.SymType = SymDeferred; + else if (!macho_load_debug_info(macho_info->module, &fmap)) + ret = FALSE; + + macho_info->module->macho_info->in_use = 1; + macho_info->module->macho_info->is_loader = 0; + TRACE("module = %p\n", macho_info->module); + } + + if (macho_info->flags & MACHO_INFO_NAME) + { + WCHAR* ptr; + ptr = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename) + 1) * sizeof(WCHAR)); + if (ptr) + { + strcpyW(ptr, filename); + macho_info->module_name = ptr; + } + else ret = FALSE; + TRACE("module_name = %p %s\n", macho_info->module_name, debugstr_w(macho_info->module_name)); + } +leave: + macho_unmap_file(&fmap); + + TRACE(" => %d\n", ret); + return ret; +} + +/****************************************************************** + * macho_load_file_from_path + * Tries to load a Mach-O file from a set of paths (separated by ':') + */ +static BOOL macho_load_file_from_path(HANDLE hProcess, + const WCHAR* filename, + unsigned long load_addr, + const char* path, + struct macho_info* macho_info) +{ + BOOL ret = FALSE; + WCHAR *s, *t, *fn; + WCHAR* pathW = NULL; + unsigned len; + + TRACE("(%p, %s, 0x%08lx, %s, %p)\n", hProcess, debugstr_w(filename), load_addr, + debugstr_a(path), macho_info); + + if (!path) return FALSE; + + len = MultiByteToWideChar(CP_UNIXCP, 0, path, -1, NULL, 0); + pathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (!pathW) return FALSE; + MultiByteToWideChar(CP_UNIXCP, 0, path, -1, pathW, len); + + for (s = pathW; s && *s; s = (t) ? (t+1) : NULL) + { + t = strchrW(s, ':'); + if (t) *t = '\0'; + fn = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename) + 1 + lstrlenW(s) + 1) * sizeof(WCHAR)); + if (!fn) break; + strcpyW(fn, s); + strcatW(fn, S_SlashW); + strcatW(fn, filename); + ret = macho_load_file(hProcess, fn, load_addr, macho_info); + HeapFree(GetProcessHeap(), 0, fn); + if (ret) break; + s = (t) ? (t+1) : NULL; + } + + TRACE(" => %d\n", ret); + HeapFree(GetProcessHeap(), 0, pathW); + return ret; +} + +/****************************************************************** + * macho_load_file_from_dll_path + * + * Tries to load a Mach-O file from the dll path + */ +static BOOL macho_load_file_from_dll_path(HANDLE hProcess, + const WCHAR* filename, + unsigned long load_addr, + struct macho_info* macho_info) +{ + BOOL ret = FALSE; + unsigned int index = 0; + const char *path; + + TRACE("(%p, %s, 0x%08lx, %p)\n", hProcess, debugstr_w(filename), load_addr, + macho_info); + + while (!ret && (path = wine_dll_enum_load_path( index++ ))) + { + WCHAR *name; + unsigned len; + + len = MultiByteToWideChar(CP_UNIXCP, 0, path, -1, NULL, 0); + + name = HeapAlloc( GetProcessHeap(), 0, + (len + lstrlenW(filename) + 2) * sizeof(WCHAR) ); + + if (!name) break; + MultiByteToWideChar(CP_UNIXCP, 0, path, -1, name, len); + strcatW( name, S_SlashW ); + strcatW( name, filename ); + ret = macho_load_file(hProcess, name, load_addr, macho_info); + HeapFree( GetProcessHeap(), 0, name ); + } + TRACE(" => %d\n", ret); + return ret; +} + +/****************************************************************** + * macho_search_and_load_file + * + * Lookup a file in standard Mach-O locations, and if found, load it + */ +static BOOL macho_search_and_load_file(struct process* pcs, const WCHAR* filename, + unsigned long load_addr, + struct macho_info* macho_info) +{ + BOOL ret = FALSE; + struct module* module; + static WCHAR S_libstdcPPW[] = {'l','i','b','s','t','d','c','+','+','\0'}; + const WCHAR* p; + + TRACE("(%p/%p, %s, 0x%08lx, %p)\n", pcs, pcs->handle, debugstr_w(filename), load_addr, + macho_info); + + if (filename == NULL || *filename == '\0') return FALSE; + if ((module = module_is_already_loaded(pcs, filename))) + { + macho_info->module = module; + module->macho_info->in_use = 1; + return module->module.SymType; + } + + if (strstrW(filename, S_libstdcPPW)) return FALSE; /* We know we can't do it */ + + /* If has no directories, try LD_LIBRARY_PATH first. */ + if (!strchrW(filename, '/')) + { + ret = macho_load_file_from_path(pcs, filename, load_addr, + getenv("PATH"), macho_info); + } + /* Try DYLD_LIBRARY_PATH, with just the filename (no directories). */ + if (!ret) + { + if ((p = strrchrW(filename, '/'))) p++; + else p = filename; + ret = macho_load_file_from_path(pcs, p, load_addr, + getenv("DYLD_LIBRARY_PATH"), macho_info); + } + /* Try the path as given. */ + if (!ret) + ret = macho_load_file(pcs, filename, load_addr, macho_info); + /* Try DYLD_FALLBACK_LIBRARY_PATH, with just the filename (no directories). */ + if (!ret) + { + ret = macho_load_file_from_path(pcs, p, load_addr, + getenv("DYLD_FALLBACK_LIBRARY_PATH"), macho_info); + } + if (!ret && !strchrW(filename, '/')) + ret = macho_load_file_from_dll_path(pcs, filename, load_addr, macho_info); + + return ret; +} + +/****************************************************************** + * macho_enum_modules_internal + * + * Enumerate Mach-O modules from a running process + */ +static BOOL macho_enum_modules_internal(const struct process* pcs, + const WCHAR* main_name, + enum_modules_cb cb, void* user) +{ + struct dyld_all_image_infos image_infos; + struct dyld_image_info* info_array = NULL; + unsigned long len; + int i; + char bufstr[256]; + WCHAR bufstrW[MAX_PATH]; + BOOL ret = FALSE; + + TRACE("(%p/%p, %s, %p, %p)\n", pcs, pcs->handle, debugstr_w(main_name), cb, + user); + + if (!pcs->dbg_hdr_addr || + !ReadProcessMemory(pcs->handle, (void*)pcs->dbg_hdr_addr, + &image_infos, sizeof(image_infos), NULL) || + !image_infos.infoArray) + goto done; + TRACE("Process has %u image infos at %p\n", image_infos.infoArrayCount, image_infos.infoArray); + + len = image_infos.infoArrayCount * sizeof(info_array[0]); + info_array = HeapAlloc(GetProcessHeap(), 0, len); + if (!info_array || + !ReadProcessMemory(pcs->handle, image_infos.infoArray, + info_array, len, NULL)) + goto done; + TRACE("... read image infos\n"); + + for (i = 0; i < image_infos.infoArrayCount; i++) + { + if (info_array[i].imageFilePath != NULL && + ReadProcessMemory(pcs->handle, info_array[i].imageFilePath, bufstr, sizeof(bufstr), NULL)) + { + bufstr[sizeof(bufstr) - 1] = '\0'; + TRACE("[%d] image file %s\n", i, debugstr_a(bufstr)); + MultiByteToWideChar(CP_UNIXCP, 0, bufstr, -1, bufstrW, sizeof(bufstrW) / sizeof(WCHAR)); + if (main_name && !bufstrW[0]) strcpyW(bufstrW, main_name); + if (!cb(bufstrW, (unsigned long)info_array[i].imageLoadAddress, user)) break; + } + } + + ret = TRUE; +done: + HeapFree(GetProcessHeap(), 0, info_array); + return ret; +} + +struct macho_sync +{ + struct process* pcs; + struct macho_info macho_info; +}; + +static BOOL macho_enum_sync_cb(const WCHAR* name, unsigned long addr, void* user) +{ + struct macho_sync* ms = user; + + TRACE("(%s, 0x%08lx, %p)\n", debugstr_w(name), addr, user); + macho_search_and_load_file(ms->pcs, name, addr, &ms->macho_info); + return TRUE; +} + +/****************************************************************** + * macho_synchronize_module_list + * + * Rescans the debuggee's modules list and synchronizes it with + * the one from 'pcs', ie: + * - if a module is in debuggee and not in pcs, it's loaded into pcs + * - if a module is in pcs and not in debuggee, it's unloaded from pcs + */ +BOOL macho_synchronize_module_list(struct process* pcs) +{ + struct module* module; + struct macho_sync ms; + + TRACE("(%p/%p)\n", pcs, pcs->handle); + + for (module = pcs->lmodules; module; module = module->next) + { + if (module->type == DMT_MACHO && !module->is_virtual) + module->macho_info->in_use = 0; + } + + ms.pcs = pcs; + ms.macho_info.flags = MACHO_INFO_MODULE; + if (!macho_enum_modules_internal(pcs, NULL, macho_enum_sync_cb, &ms)) + return FALSE; + + module = pcs->lmodules; + while (module) + { + if (module->type == DMT_MACHO && !module->is_virtual && + !module->macho_info->in_use && !module->macho_info->is_loader) + { + module_remove(pcs, module); + /* restart all over */ + module = pcs->lmodules; + } + else module = module->next; + } + return TRUE; +} + +/****************************************************************** + * macho_search_loader + * + * Lookup in a running Mach-O process the loader, and sets its Mach-O link + * address (for accessing the list of loaded images) in pcs. + * If flags is MACHO_INFO_MODULE, the module for the loader is also + * added as a module into pcs. + */ +static BOOL macho_search_loader(struct process* pcs, struct macho_info* macho_info) +{ + BOOL ret; + const char* ptr; + + TRACE("(%p/%p, %p)\n", pcs, pcs->handle, macho_info); + + /* All binaries are loaded with WINELOADER (if run from tree) or by the + * main executable + */ + if ((ptr = getenv("WINELOADER"))) + { + WCHAR tmp[MAX_PATH]; + MultiByteToWideChar(CP_UNIXCP, 0, ptr, -1, tmp, sizeof(tmp) / sizeof(WCHAR)); + ret = macho_search_and_load_file(pcs, tmp, 0, macho_info); + } + else + { + ret = macho_search_and_load_file(pcs, S_WineW, 0, macho_info); + } + return ret; +} + +/****************************************************************** + * macho_read_wine_loader_dbg_info + * + * Try to find a decent wine executable which could have loaded the debuggee + */ +BOOL macho_read_wine_loader_dbg_info(struct process* pcs) +{ + struct macho_info macho_info; + + TRACE("(%p/%p)\n", pcs, pcs->handle); + macho_info.flags = MACHO_INFO_DEBUG_HEADER | MACHO_INFO_MODULE; + if (!macho_search_loader(pcs, &macho_info)) return FALSE; + macho_info.module->macho_info->is_loader = 1; + module_set_module(macho_info.module, S_WineLoaderW); + return (pcs->dbg_hdr_addr = macho_info.dbg_hdr_addr) != 0; +} + +/****************************************************************** + * macho_enum_modules + * + * Enumerates the Mach-O loaded modules from a running target (hProc) + * This function doesn't require that someone has called SymInitialize + * on this very process. + */ +BOOL macho_enum_modules(HANDLE hProc, enum_modules_cb cb, void* user) +{ + struct process pcs; + struct macho_info macho_info; + BOOL ret; + + TRACE("(%p, %p, %p)\n", hProc, cb, user); + memset(&pcs, 0, sizeof(pcs)); + pcs.handle = hProc; + macho_info.flags = MACHO_INFO_DEBUG_HEADER | MACHO_INFO_NAME; + if (!macho_search_loader(&pcs, &macho_info)) return FALSE; + pcs.dbg_hdr_addr = macho_info.dbg_hdr_addr; + ret = macho_enum_modules_internal(&pcs, macho_info.module_name, cb, user); + HeapFree(GetProcessHeap(), 0, (char*)macho_info.module_name); + return ret; +} + +struct macho_load +{ + struct process* pcs; + struct macho_info macho_info; + const WCHAR* name; + BOOL ret; +}; + +/****************************************************************** + * macho_load_cb + * + * Callback for macho_load_module, used to walk the list of loaded + * modules. + */ +static BOOL macho_load_cb(const WCHAR* name, unsigned long addr, void* user) +{ + struct macho_load* ml = user; + const WCHAR* p; + + TRACE("(%s, 0x%08lx, %p)\n", debugstr_w(name), addr, user); + + /* memcmp is needed for matches when bufstr contains also version information + * ml->name: libc.so, name: libc.so.6.0 + */ + p = strrchrW(name, '/'); + if (!p++) p = name; + if (!memcmp(p, ml->name, lstrlenW(ml->name) * sizeof(WCHAR))) + { + ml->ret = macho_search_and_load_file(ml->pcs, name, addr, &ml->macho_info); + return FALSE; + } + return TRUE; +} + +/****************************************************************** + * macho_load_module + * + * Loads a Mach-O module and stores it in process' module list. + * Also, find module real name and load address from + * the real loaded modules list in pcs address space. + */ +struct module* macho_load_module(struct process* pcs, const WCHAR* name, unsigned long addr) +{ + struct macho_load ml; + + TRACE("(%p/%p, %s, 0x%08lx)\n", pcs, pcs->handle, debugstr_w(name), addr); + + ml.macho_info.flags = MACHO_INFO_MODULE; + ml.ret = FALSE; + + if (pcs->dbg_hdr_addr) /* we're debugging a live target */ + { + ml.pcs = pcs; + /* do only the lookup from the filename, not the path (as we lookup module + * name in the process' loaded module list) + */ + ml.name = strrchrW(name, '/'); + if (!ml.name++) ml.name = name; + ml.ret = FALSE; + + if (!macho_enum_modules_internal(pcs, NULL, macho_load_cb, &ml)) + return NULL; + } + else if (addr) + { + ml.name = name; + ml.ret = macho_search_and_load_file(pcs, ml.name, addr, &ml.macho_info); + } + if (!ml.ret) return NULL; + assert(ml.macho_info.module); + return ml.macho_info.module; +} + +#else /* !__MACH__ */ + +BOOL macho_synchronize_module_list(struct process* pcs) +{ + return FALSE; +} + +BOOL macho_fetch_file_info(const WCHAR* name, DWORD* base, + DWORD* size, DWORD* checksum) +{ + return FALSE; +} + +BOOL macho_read_wine_loader_dbg_info(struct process* pcs) +{ + return FALSE; +} + +BOOL macho_enum_modules(HANDLE hProc, enum_modules_cb cb, void* user) +{ + return FALSE; +} + +struct module* macho_load_module(struct process* pcs, const WCHAR* name, unsigned long addr) +{ + return NULL; +} + +BOOL macho_load_debug_info(struct module* module, struct macho_file_map* fmap) +{ + return FALSE; +} +#endif /* __MACH__ */ diff --git a/reactos/dll/win32/dbghelp/minidump.c b/reactos/dll/win32/dbghelp/minidump.c index cc124157544..3cddb72ee03 100644 --- a/reactos/dll/win32/dbghelp/minidump.c +++ b/reactos/dll/win32/dbghelp/minidump.c @@ -34,7 +34,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); struct dump_memory { - ULONG base; + ULONG64 base; ULONG size; ULONG rva; }; @@ -42,7 +42,7 @@ struct dump_memory struct dump_module { unsigned is_elf; - ULONG base; + ULONG64 base; ULONG size; DWORD timestamp; DWORD checksum; @@ -59,6 +59,7 @@ struct dump_context /* module information */ struct dump_module* modules; unsigned num_modules; + unsigned alloc_modules; /* exception information */ /* output information */ MINIDUMP_TYPE type; @@ -66,6 +67,7 @@ struct dump_context RVA rva; struct dump_memory* mem; unsigned num_mem; + unsigned alloc_mem; /* callback information */ MINIDUMP_CALLBACK_INFORMATION* cb; }; @@ -98,10 +100,9 @@ static BOOL fetch_processes_info(struct dump_context* dc) dc->spi = dc->pcs_buffer; for (;;) { - if (dc->spi->dwProcessID == dc->pid) return TRUE; - if (!dc->spi->dwOffset) break; - dc->spi = (SYSTEM_PROCESS_INFORMATION*) - ((char*)dc->spi + dc->spi->dwOffset); + if (HandleToUlong(dc->spi->UniqueProcessId) == dc->pid) return TRUE; + if (!dc->spi->NextEntryOffset) break; + dc->spi = (SYSTEM_PROCESS_INFORMATION*)((char*)dc->spi + dc->spi->NextEntryOffset); } } HeapFree(GetProcessHeap(), 0, dc->pcs_buffer); @@ -114,58 +115,25 @@ static void fetch_thread_stack(struct dump_context* dc, const void* teb_addr, const CONTEXT* ctx, MINIDUMP_MEMORY_DESCRIPTOR* mmd) { NT_TIB tib; + ADDRESS64 addr; - if (ReadProcessMemory(dc->hProcess, teb_addr, &tib, sizeof(tib), NULL)) + if (ReadProcessMemory(dc->hProcess, teb_addr, &tib, sizeof(tib), NULL) && + dbghelp_current_cpu && + dbghelp_current_cpu->get_addr(NULL /* FIXME */, ctx, cpu_addr_stack, &addr) && addr.Mode == AddrModeFlat) { -#ifdef __i386__ - /* limiting the stack dumping to the size actually used */ - if (ctx->Esp){ - - /* make sure ESP is within the established range of the stack. It could have + if (addr.Offset) + { + addr.Offset -= dbghelp_current_cpu->word_size; + /* make sure stack pointer is within the established range of the stack. It could have been clobbered by whatever caused the original exception. */ - if (ctx->Esp - 4 < (ULONG_PTR)tib.StackLimit || ctx->Esp - 4 > (ULONG_PTR)tib.StackBase) + if (addr.Offset < (ULONG_PTR)tib.StackLimit || addr.Offset > (ULONG_PTR)tib.StackBase) mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit; else - mmd->StartOfMemoryRange = (ctx->Esp - 4); + mmd->StartOfMemoryRange = addr.Offset; } - else mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit; - -#elif defined(__powerpc__) - if (ctx->Iar){ - - /* make sure IAR is within the established range of the stack. It could have - been clobbered by whatever caused the original exception. */ - if (ctx->Iar - 4 < (ULONG_PTR)tib.StackLimit || ctx->Iar - 4 > (ULONG_PTR)tib.StackBase) - mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit; - - else - mmd->StartOfMemoryRange = (ctx->Iar - 4); - } - - else - mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit; - -#elif defined(__x86_64__) - if (ctx->Rsp){ - - /* make sure RSP is within the established range of the stack. It could have - been clobbered by whatever caused the original exception. */ - if (ctx->Rsp - 8 < (ULONG_PTR)tib.StackLimit || ctx->Rsp - 8 > (ULONG_PTR)tib.StackBase) - mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit; - - else - mmd->StartOfMemoryRange = (ctx->Rsp - 8); - } - - else - mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit; - -#else -#error unsupported CPU -#endif mmd->Memory.DataSize = (ULONG_PTR)tib.StackBase - mmd->StartOfMemoryRange; } } @@ -179,13 +147,13 @@ static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx, const MINIDUMP_EXCEPTION_INFORMATION* except, MINIDUMP_THREAD* mdThd, CONTEXT* ctx) { - DWORD tid = dc->spi->ti[thd_idx].dwThreadID; + DWORD tid = HandleToUlong(dc->spi->ti[thd_idx].ClientId.UniqueThread); HANDLE hThread; THREAD_BASIC_INFORMATION tbi; memset(ctx, 0, sizeof(*ctx)); - mdThd->ThreadId = dc->spi->ti[thd_idx].dwThreadID; + mdThd->ThreadId = tid; mdThd->SuspendCount = 0; mdThd->Teb = 0; mdThd->Stack.StartOfMemoryRange = 0; @@ -198,8 +166,7 @@ static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx, if ((hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, tid)) == NULL) { - FIXME("Couldn't open thread %u (%u)\n", - dc->spi->ti[thd_idx].dwThreadID, GetLastError()); + FIXME("Couldn't open thread %u (%u)\n", tid, GetLastError()); return FALSE; } @@ -230,7 +197,7 @@ static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx, ReadProcessMemory(dc->hProcess, except->ExceptionPointers, &ep, sizeof(ep), NULL); ReadProcessMemory(dc->hProcess, ep.ContextRecord, - &ctx, sizeof(ctx), NULL); + &lctx, sizeof(lctx), NULL); pctx = &lctx; } else pctx = except->ExceptionPointers->ContextRecord; @@ -251,27 +218,38 @@ static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx, * Add a module to a dump context */ static BOOL add_module(struct dump_context* dc, const WCHAR* name, - DWORD base, DWORD size, DWORD timestamp, DWORD checksum, + DWORD64 base, DWORD size, DWORD timestamp, DWORD checksum, BOOL is_elf) { if (!dc->modules) + { + dc->alloc_modules = 32; dc->modules = HeapAlloc(GetProcessHeap(), 0, - ++dc->num_modules * sizeof(*dc->modules)); - else + dc->alloc_modules * sizeof(*dc->modules)); + } + else if(dc->num_modules >= dc->alloc_modules) + { + dc->alloc_modules *= 2; dc->modules = HeapReAlloc(GetProcessHeap(), 0, dc->modules, - ++dc->num_modules * sizeof(*dc->modules)); - if (!dc->modules) return FALSE; + dc->alloc_modules * sizeof(*dc->modules)); + } + if (!dc->modules) + { + dc->alloc_modules = dc->num_modules = 0; + return FALSE; + } if (is_elf || - !GetModuleFileNameExW(dc->hProcess, (HMODULE)base, - dc->modules[dc->num_modules - 1].name, - sizeof(dc->modules[dc->num_modules - 1].name) / sizeof(WCHAR))) - lstrcpynW(dc->modules[dc->num_modules - 1].name, name, - sizeof(dc->modules[dc->num_modules - 1].name) / sizeof(WCHAR)); - dc->modules[dc->num_modules - 1].base = base; - dc->modules[dc->num_modules - 1].size = size; - dc->modules[dc->num_modules - 1].timestamp = timestamp; - dc->modules[dc->num_modules - 1].checksum = checksum; - dc->modules[dc->num_modules - 1].is_elf = is_elf; + !GetModuleFileNameExW(dc->hProcess, (HMODULE)(DWORD_PTR)base, + dc->modules[dc->num_modules].name, + sizeof(dc->modules[dc->num_modules].name) / sizeof(WCHAR))) + lstrcpynW(dc->modules[dc->num_modules].name, name, + sizeof(dc->modules[dc->num_modules].name) / sizeof(WCHAR)); + dc->modules[dc->num_modules].base = base; + dc->modules[dc->num_modules].size = size; + dc->modules[dc->num_modules].timestamp = timestamp; + dc->modules[dc->num_modules].checksum = checksum; + dc->modules[dc->num_modules].is_elf = is_elf; + dc->num_modules++; return TRUE; } @@ -284,13 +262,13 @@ static BOOL add_module(struct dump_context* dc, const WCHAR* name, static BOOL WINAPI fetch_pe_module_info_cb(PCWSTR name, DWORD64 base, ULONG size, PVOID user) { - struct dump_context* dc = (struct dump_context*)user; + struct dump_context* dc = user; IMAGE_NT_HEADERS nth; if (!validate_addr64(base)) return FALSE; if (pe_load_nt_header(dc->hProcess, base, &nth)) - add_module((struct dump_context*)user, name, base, size, + add_module(user, name, base, size, nth.FileHeader.TimeDateStamp, nth.OptionalHeader.CheckSum, FALSE); return TRUE; @@ -304,7 +282,7 @@ static BOOL WINAPI fetch_pe_module_info_cb(PCWSTR name, DWORD64 base, ULONG size static BOOL fetch_elf_module_info_cb(const WCHAR* name, unsigned long base, void* user) { - struct dump_context* dc = (struct dump_context*)user; + struct dump_context* dc = user; DWORD rbase, size, checksum; /* FIXME: there's no relevant timestamp on ELF modules */ @@ -318,6 +296,27 @@ static BOOL fetch_elf_module_info_cb(const WCHAR* name, unsigned long base, return TRUE; } +/****************************************************************** + * fetch_macho_module_info_cb + * + * Callback for accumulating in dump_context a Mach-O modules set + */ +static BOOL fetch_macho_module_info_cb(const WCHAR* name, unsigned long base, + void* user) +{ + struct dump_context* dc = (struct dump_context*)user; + DWORD rbase, size, checksum; + + /* FIXME: there's no relevant timestamp on Mach-O modules */ + /* NB: if we have a non-null base from the live-target use it. If we have + * a null base, then grab its base address from Mach-O file. + */ + if (!macho_fetch_file_info(name, &rbase, &size, &checksum)) + size = checksum = 0; + add_module(dc, name, base ? base : rbase, size, 0 /* FIXME */, checksum, TRUE); + return TRUE; +} + static void fetch_modules_info(struct dump_context* dc) { EnumerateLoadedModulesW64(dc->hProcess, fetch_pe_module_info_cb, dc); @@ -327,6 +326,7 @@ static void fetch_modules_info(struct dump_context* dc) * a given application in a post mortem debugging condition. */ elf_enum_modules(dc->hProcess, fetch_elf_module_info_cb, dc); + macho_enum_modules(dc->hProcess, fetch_macho_module_info_cb, dc); } static void fetch_module_versioninfo(LPCWSTR filename, VS_FIXEDFILEINFO* ffi) @@ -361,18 +361,25 @@ static void fetch_module_versioninfo(LPCWSTR filename, VS_FIXEDFILEINFO* ffi) */ static void add_memory_block(struct dump_context* dc, ULONG64 base, ULONG size, ULONG rva) { - if (dc->mem) - dc->mem = HeapReAlloc(GetProcessHeap(), 0, dc->mem, - ++dc->num_mem * sizeof(*dc->mem)); - else - dc->mem = HeapAlloc(GetProcessHeap(), 0, ++dc->num_mem * sizeof(*dc->mem)); + if (!dc->mem) + { + dc->alloc_mem = 32; + dc->mem = HeapAlloc(GetProcessHeap(), 0, dc->alloc_mem * sizeof(*dc->mem)); + } + else if (dc->num_mem >= dc->alloc_mem) + { + dc->alloc_mem *= 2; + dc->mem = HeapReAlloc(GetProcessHeap(), 0, dc->mem, + dc->alloc_mem * sizeof(*dc->mem)); + } if (dc->mem) { - dc->mem[dc->num_mem - 1].base = base; - dc->mem[dc->num_mem - 1].size = size; - dc->mem[dc->num_mem - 1].rva = rva; + dc->mem[dc->num_mem].base = base; + dc->mem[dc->num_mem].size = size; + dc->mem[dc->num_mem].rva = rva; + dc->num_mem++; } - else dc->num_mem = 0; + else dc->num_mem = dc->alloc_mem = 0; } /****************************************************************** @@ -394,7 +401,7 @@ static void writeat(struct dump_context* dc, RVA rva, const void* data, unsigned * writes a new chunk of data to the minidump, increasing the current * rva in dc */ -static void append(struct dump_context* dc, void* data, unsigned size) +static void append(struct dump_context* dc, const void* data, unsigned size) { writeat(dc, dc->rva, data, size); dc->rva += size; @@ -683,7 +690,7 @@ static unsigned dump_threads(struct dump_context* dc, { MINIDUMP_THREAD mdThd; MINIDUMP_THREAD_LIST mdThdList; - unsigned i; + unsigned i, sz; RVA rva_base; DWORD flags_out; CONTEXT ctx; @@ -691,8 +698,7 @@ static unsigned dump_threads(struct dump_context* dc, mdThdList.NumberOfThreads = 0; rva_base = dc->rva; - dc->rva += sizeof(mdThdList.NumberOfThreads) + - dc->spi->dwThreadCount * sizeof(mdThd); + dc->rva += sz = sizeof(mdThdList.NumberOfThreads) + dc->spi->dwThreadCount * sizeof(mdThd); for (i = 0; i < dc->spi->dwThreadCount; i++) { @@ -713,7 +719,7 @@ static unsigned dump_threads(struct dump_context* dc, cbin.ProcessId = dc->pid; cbin.ProcessHandle = dc->hProcess; cbin.CallbackType = ThreadCallback; - cbin.u.Thread.ThreadId = dc->spi->ti[i].dwThreadID; + cbin.u.Thread.ThreadId = HandleToUlong(dc->spi->ti[i].ClientId.UniqueThread); cbin.u.Thread.ThreadHandle = 0; /* FIXME */ cbin.u.Thread.Context = ctx; cbin.u.Thread.SizeOfContext = sizeof(CONTEXT); @@ -760,7 +766,7 @@ static unsigned dump_threads(struct dump_context* dc, writeat(dc, rva_base, &mdThdList.NumberOfThreads, sizeof(mdThdList.NumberOfThreads)); - return dc->rva - rva_base; + return sz; } /****************************************************************** @@ -795,7 +801,7 @@ static unsigned dump_memory_info(struct dump_context* dc) { len = min(dc->mem[i].size - pos, sizeof(tmp)); if (ReadProcessMemory(dc->hProcess, - (void*)(dc->mem[i].base + pos), + (void*)(DWORD_PTR)(dc->mem[i].base + pos), tmp, len, NULL)) WriteFile(dc->hFile, tmp, len, &written, NULL); } @@ -847,10 +853,12 @@ BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile, dc.pid = pid; dc.modules = NULL; dc.num_modules = 0; + dc.alloc_modules = 0; dc.cb = CallbackParam; dc.type = DumpType; dc.mem = NULL; dc.num_mem = 0; + dc.alloc_mem = 0; dc.rva = 0; if (!fetch_processes_info(&dc)) return FALSE; @@ -973,7 +981,7 @@ BOOL WINAPI MiniDumpReadDumpStream(PVOID base, ULONG str_idx, PMINIDUMP_DIRECTORY* pdir, PVOID* stream, ULONG* size) { - MINIDUMP_HEADER* mdHead = (MINIDUMP_HEADER*)base; + MINIDUMP_HEADER* mdHead = base; if (mdHead->Signature == MINIDUMP_SIGNATURE) { @@ -985,9 +993,9 @@ BOOL WINAPI MiniDumpReadDumpStream(PVOID base, ULONG str_idx, { if (dir->StreamType == str_idx) { - *pdir = dir; - *stream = (char*)base + dir->Location.Rva; - *size = dir->Location.DataSize; + if (pdir) *pdir = dir; + if (stream) *stream = (char*)base + dir->Location.Rva; + if (size) *size = dir->Location.DataSize; return TRUE; } } diff --git a/reactos/dll/win32/dbghelp/module.c b/reactos/dll/win32/dbghelp/module.c index ddc6d3d89bd..53f56c25129 100644 --- a/reactos/dll/win32/dbghelp/module.c +++ b/reactos/dll/win32/dbghelp/module.c @@ -35,10 +35,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); const WCHAR S_ElfW[] = {'<','e','l','f','>','\0'}; const WCHAR S_WineLoaderW[] = {'<','w','i','n','e','-','l','o','a','d','e','r','>','\0'}; static const WCHAR S_DotSoW[] = {'.','s','o','\0'}; +static const WCHAR S_DotDylibW[] = {'.','d','y','l','i','b','\0'}; static const WCHAR S_DotPdbW[] = {'.','p','d','b','\0'}; static const WCHAR S_DotDbgW[] = {'.','d','b','g','\0'}; -const WCHAR S_WinePThreadW[] = {'w','i','n','e','-','p','t','h','r','e','a','d','\0'}; -const WCHAR S_WineKThreadW[] = {'w','i','n','e','-','k','t','h','r','e','a','d','\0'}; +const WCHAR S_WineW[] = {'w','i','n','e',0}; const WCHAR S_SlashW[] = {'/','\0'}; static const WCHAR S_AcmW[] = {'.','a','c','m','\0'}; @@ -87,9 +87,7 @@ static void module_fill_module(const WCHAR* in, WCHAR* out, size_t size) out[len] = '\0'; if (len > 4 && (l = match_ext(out, len))) out[len - l] = '\0'; - else if (len > 12 && - (!strcmpiW(out + len - 12, S_WinePThreadW) || - !strcmpiW(out + len - 12, S_WineKThreadW))) + else if (len > 4 && !strcmpiW(out + len - 4, S_WineW)) lstrcpynW(out, S_WineLoaderW, size); else { @@ -114,6 +112,7 @@ static const char* get_module_type(enum module_type type, BOOL virtual) { case DMT_ELF: return virtual ? "Virtual ELF" : "ELF"; case DMT_PE: return virtual ? "Virtual PE" : "PE"; + case DMT_MACHO: return virtual ? "Virtual Mach-O" : "Mach-O"; default: return "---"; } } @@ -123,20 +122,21 @@ static const char* get_module_type(enum module_type type, BOOL virtual) */ struct module* module_new(struct process* pcs, const WCHAR* name, enum module_type type, BOOL virtual, - unsigned long mod_addr, unsigned long size, + DWORD64 mod_addr, DWORD64 size, unsigned long stamp, unsigned long checksum) { struct module* module; - assert(type == DMT_ELF || type == DMT_PE); + assert(type == DMT_ELF || type == DMT_PE || type == DMT_MACHO); if (!(module = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*module)))) return NULL; module->next = pcs->lmodules; pcs->lmodules = module; - TRACE("=> %s %08lx-%08lx %s\n", - get_module_type(type, virtual), mod_addr, mod_addr + size, + TRACE("=> %s %s-%s %s\n", + get_module_type(type, virtual), + wine_dbgstr_longlong(mod_addr), wine_dbgstr_longlong(mod_addr + size), debugstr_w(name)); pool_init(&module->pool, 65536); @@ -169,7 +169,12 @@ struct module* module_new(struct process* pcs, const WCHAR* name, module->type = type; module->is_virtual = virtual ? TRUE : FALSE; module->sortlist_valid = FALSE; + module->sorttab_size = 0; module->addr_sorttab = NULL; + module->num_sorttab = 0; + module->num_symbols = 0; + + vector_init(&module->vsymt, sizeof(struct symt*), 128); /* FIXME: this seems a bit too high (on a per module basis) * need some statistics about this */ @@ -188,7 +193,7 @@ struct module* module_new(struct process* pcs, const WCHAR* name, * module_find_by_name * */ -struct module* module_find_by_name(const struct process* pcs, const WCHAR* name) +static struct module* module_find_by_name(const struct process* pcs, const WCHAR* name) { struct module* module; @@ -238,7 +243,7 @@ struct module* module_is_already_loaded(const struct process* pcs, const WCHAR* * module_get_container * */ -struct module* module_get_container(const struct process* pcs, +static struct module* module_get_container(const struct process* pcs, const struct module* inner) { struct module* module; @@ -319,6 +324,9 @@ BOOL module_get_debug(struct module_pair* pair) ret ? CBA_DEFERRED_SYMBOL_LOAD_COMPLETE : CBA_DEFERRED_SYMBOL_LOAD_FAILURE, &idslW64); break; + case DMT_MACHO: + ret = macho_load_debug_info(pair->effective, NULL); + break; default: ret = FALSE; break; @@ -344,7 +352,8 @@ struct module* module_find_by_addr(const struct process* pcs, unsigned long addr if (type == DMT_UNKNOWN) { if ((module = module_find_by_addr(pcs, addr, DMT_PE)) || - (module = module_find_by_addr(pcs, addr, DMT_ELF))) + (module = module_find_by_addr(pcs, addr, DMT_ELF)) || + (module = module_find_by_addr(pcs, addr, DMT_MACHO))) return module; } else @@ -361,13 +370,13 @@ struct module* module_find_by_addr(const struct process* pcs, unsigned long addr } /****************************************************************** - * module_is_elf_container_loaded + * module_is_container_loaded * - * checks whether the ELF container, for a (supposed) PE builtin is + * checks whether the native container, for a (supposed) PE builtin is * already loaded */ -static BOOL module_is_elf_container_loaded(const struct process* pcs, - const WCHAR* ImageName, DWORD base) +static BOOL module_is_container_loaded(const struct process* pcs, + const WCHAR* ImageName, DWORD64 base) { size_t len; struct module* module; @@ -379,7 +388,7 @@ static BOOL module_is_elf_container_loaded(const struct process* pcs, for (module = pcs->lmodules; module; module = module->next) { - if (module->type == DMT_ELF && + if ((module->type == DMT_ELF || module->type == DMT_MACHO) && base >= module->module.BaseOfImage && base < module->module.BaseOfImage + module->module.ImageSize) { @@ -419,8 +428,17 @@ enum module_type module_get_type_by_name(const WCHAR* name) } while (len); /* check for terminating .so or .so.[digit] */ + /* FIXME: Can't rely solely on extension; have to check magic or + * stop using .so on Mac OS X. For now, base on platform. */ if (len > 3 && !memcmp(name + len - 3, S_DotSoW, 3)) +#ifdef __APPLE__ + return DMT_MACHO; +#else return DMT_ELF; +#endif + + if (len > 6 && !strncmpiW(name + len - 6, S_DotDylibW, 6)) + return DMT_MACHO; if (len > 4 && !strncmpiW(name + len - 4, S_DotPdbW, 4)) return DMT_PDB; @@ -428,16 +446,27 @@ enum module_type module_get_type_by_name(const WCHAR* name) if (len > 4 && !strncmpiW(name + len - 4, S_DotDbgW, 4)) return DMT_DBG; - /* wine-[kp]thread is also an ELF module */ - if (((len > 12 && name[len - 13] == '/') || len == 12) && - (!strncmpiW(name + len - 12, S_WinePThreadW, 12) || - !strncmpiW(name + len - 12, S_WineKThreadW, 12))) + /* wine is also a native module (Mach-O on Mac OS X, ELF elsewhere) */ + if (((len > 4 && name[len - 5] == '/') || len == 4) && !strcmpiW(name + len - 4, S_WineW)) { +#ifdef __APPLE__ + return DMT_MACHO; +#else return DMT_ELF; +#endif } return DMT_PE; } +/****************************************************************** + * refresh_module_list + */ +static BOOL refresh_module_list(struct process* pcs) +{ + /* force transparent ELF and Mach-O loading / unloading */ + return elf_synchronize_module_list(pcs) || macho_synchronize_module_list(pcs); +} + /*********************************************************************** * SymLoadModule (DBGHELP.@) */ @@ -508,8 +537,9 @@ DWORD64 WINAPI SymLoadModuleExW(HANDLE hProcess, HANDLE hFile, PCWSTR wImageNam if (Flags & SLMFLAG_VIRTUAL) { + if (!wImageName) return FALSE; module = module_new(pcs, wImageName, module_get_type_by_name(wImageName), - TRUE, (DWORD)BaseOfDll, SizeOfDll, 0, 0); + TRUE, BaseOfDll, SizeOfDll, 0, 0); if (!module) return FALSE; if (wModuleName) module_set_module(module, wModuleName); module->module.SymType = SymVirtual; @@ -519,8 +549,7 @@ DWORD64 WINAPI SymLoadModuleExW(HANDLE hProcess, HANDLE hFile, PCWSTR wImageNam if (Flags & ~(SLMFLAG_VIRTUAL)) FIXME("Unsupported Flags %08x for %s\n", Flags, debugstr_w(wImageName)); - /* force transparent ELF loading / unloading */ - elf_synchronize_module_list(pcs); + refresh_module_list(pcs); /* this is a Wine extension to the API just to redo the synchronisation */ if (!wImageName && !hFile) return 0; @@ -531,7 +560,7 @@ DWORD64 WINAPI SymLoadModuleExW(HANDLE hProcess, HANDLE hFile, PCWSTR wImageNam if (wImageName) { module = module_is_already_loaded(pcs, wImageName); - if (!module && module_is_elf_container_loaded(pcs, wImageName, BaseOfDll)) + if (!module && module_is_container_loaded(pcs, wImageName, BaseOfDll)) { /* force the loading of DLL as builtin */ module = pe_load_builtin_module(pcs, wImageName, BaseOfDll, SizeOfDll); @@ -540,11 +569,22 @@ DWORD64 WINAPI SymLoadModuleExW(HANDLE hProcess, HANDLE hFile, PCWSTR wImageNam if (!module) { /* otherwise, try a regular PE module */ - if (!(module = pe_load_native_module(pcs, wImageName, hFile, BaseOfDll, SizeOfDll))) + if (!(module = pe_load_native_module(pcs, wImageName, hFile, BaseOfDll, SizeOfDll)) && + wImageName) { - /* and finally and ELF module */ - if (module_get_type_by_name(wImageName) == DMT_ELF) - module = elf_load_module(pcs, wImageName, BaseOfDll); + /* and finally an ELF or Mach-O module */ + switch (module_get_type_by_name(wImageName)) + { + case DMT_ELF: + module = elf_load_module(pcs, wImageName, BaseOfDll); + break; + case DMT_MACHO: + module = macho_load_module(pcs, wImageName, BaseOfDll); + break; + default: + /* Ignored */ + break; + } } } if (!module) @@ -558,7 +598,8 @@ DWORD64 WINAPI SymLoadModuleExW(HANDLE hProcess, HANDLE hFile, PCWSTR wImageNam */ if (wModuleName) module_set_module(module, wModuleName); - lstrcpynW(module->module.ImageName, wImageName, + if (wImageName) + lstrcpynW(module->module.ImageName, wImageName, sizeof(module->module.ImageName) / sizeof(WCHAR)); return module->module.BaseOfImage; @@ -715,7 +756,8 @@ BOOL WINAPI SymEnumerateModulesW64(HANDLE hProcess, for (module = pcs->lmodules; module; module = module->next) { - if (!(dbghelp_options & SYMOPT_WINE_WITH_ELF_MODULES) && module->type == DMT_ELF) + if (!(dbghelp_options & SYMOPT_WINE_WITH_NATIVE_MODULES) && + (module->type == DMT_ELF || module->type == DMT_MACHO)) continue; if (!EnumModulesCallback(module->module.ModuleName, module->module.BaseOfImage, UserContext)) @@ -1008,7 +1050,9 @@ DWORD64 WINAPI SymGetModuleBase64(HANDLE hProcess, DWORD64 dwAddr) void module_reset_debug_info(struct module* module) { module->sortlist_valid = TRUE; + module->sorttab_size = 0; module->addr_sorttab = NULL; + module->num_sorttab = module->num_symbols = 0; hash_table_destroy(&module->ht_symbols); module->ht_symbols.num_buckets = 0; module->ht_symbols.buckets = NULL; @@ -1020,3 +1064,17 @@ void module_reset_debug_info(struct module* module) module->sources_used = module->sources_alloc = 0; module->sources = NULL; } + +/****************************************************************** + * SymRefreshModuleList (DBGHELP.@) + */ +BOOL WINAPI SymRefreshModuleList(HANDLE hProcess) +{ + struct process* pcs; + + TRACE("(%p)\n", hProcess); + + if (!(pcs = process_find_by_handle(hProcess))) return FALSE; + + return refresh_module_list(pcs); +} diff --git a/reactos/dll/win32/dbghelp/msc.c b/reactos/dll/win32/dbghelp/msc.c index 47998549bde..ee394cd946c 100644 --- a/reactos/dll/win32/dbghelp/msc.c +++ b/reactos/dll/win32/dbghelp/msc.c @@ -71,7 +71,7 @@ static void dump(const void* ptr, unsigned len) unsigned int i, j; char msg[128]; const char* hexof = "0123456789abcdef"; - const BYTE* x = (const BYTE*)ptr; + const BYTE* x = ptr; for (i = 0; i < len; i += 16) { @@ -95,7 +95,7 @@ static void dump(const void* ptr, unsigned len) * Process CodeView type information. */ -#define MAX_BUILTIN_TYPES 0x0480 +#define MAX_BUILTIN_TYPES 0x0604 #define FIRST_DEFINABLE_TYPE 0x1000 static struct symt* cv_basic_types[MAX_BUILTIN_TYPES]; @@ -113,6 +113,7 @@ static struct cv_defined_module*cv_current_module; static void codeview_init_basic_types(struct module* module) { + struct symt_udt* udt; /* * These are the common builtin types that are used by VC++. */ @@ -169,6 +170,12 @@ static void codeview_init_basic_types(struct module* module) cv_basic_types[T_32PINT8] = &symt_new_pointer(module, cv_basic_types[T_INT8])->symt; cv_basic_types[T_32PUINT8] = &symt_new_pointer(module, cv_basic_types[T_UINT8])->symt; cv_basic_types[T_32PHRESULT]= &symt_new_pointer(module, cv_basic_types[T_HRESULT])->symt; + + /* The .pdb file can refer to 64 bit pointers values even on 32 bits applications. */ + udt = symt_new_udt(module, "PVOID64", 8, UdtStruct); + symt_add_udt_element(module, udt, "ptr64_low", cv_basic_types[T_LONG], 0, 32); + symt_add_udt_element(module, udt, "ptr64_high", cv_basic_types[T_LONG], 32, 32); + cv_basic_types[0x603]= &udt->symt; } static int leaf_as_variant(VARIANT* v, const unsigned short int* leaf) @@ -486,18 +493,23 @@ static int codeview_add_type(unsigned int typeno, struct symt* dt) if ((typeno >> 24) != 0) FIXME("No module index while inserting type-id assumption is wrong %x\n", typeno); - while (typeno - FIRST_DEFINABLE_TYPE >= cv_current_module->num_defined_types) + if (typeno - FIRST_DEFINABLE_TYPE >= cv_current_module->num_defined_types) { - cv_current_module->num_defined_types += 0x100; if (cv_current_module->defined_types) + { + cv_current_module->num_defined_types = max( cv_current_module->num_defined_types * 2, + typeno - FIRST_DEFINABLE_TYPE + 1 ); cv_current_module->defined_types = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cv_current_module->defined_types, cv_current_module->num_defined_types * sizeof(struct symt*)); + } else + { + cv_current_module->num_defined_types = max( 256, typeno - FIRST_DEFINABLE_TYPE + 1 ); cv_current_module->defined_types = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cv_current_module->num_defined_types * sizeof(struct symt*)); - + } if (cv_current_module->defined_types == NULL) return FALSE; } if (cv_current_module->defined_types[typeno - FIRST_DEFINABLE_TYPE]) @@ -581,15 +593,8 @@ static struct symt* codeview_add_type_array(struct codeview_type_parse* ctp, { struct symt* elem = codeview_fetch_type(ctp, elemtype, FALSE); struct symt* index = codeview_fetch_type(ctp, indextype, FALSE); - DWORD arr_max = 0; - if (elem) - { - DWORD64 elem_size; - symt_get_info(elem, TI_GET_LENGTH, &elem_size); - if (elem_size) arr_max = arr_len / (DWORD)elem_size; - } - return &symt_new_array(ctp->module, 0, arr_max, elem, index)->symt; + return &symt_new_array(ctp->module, 0, -arr_len, elem, index)->symt; } static int codeview_add_type_enum_field_list(struct module* module, @@ -669,7 +674,7 @@ static void codeview_add_udt_element(struct codeview_type_parse* ctp, if (subtype) { DWORD64 elem_size = 0; - symt_get_info(subtype, TI_GET_LENGTH, &elem_size); + symt_get_info(ctp->module, subtype, TI_GET_LENGTH, &elem_size); symt_add_udt_element(ctp->module, symt, name, subtype, value << 3, (DWORD)elem_size << 3); } @@ -1357,48 +1362,72 @@ static void codeview_snarf_linetab(const struct msc_debug_info* msc_dbg, const B } static void codeview_snarf_linetab2(const struct msc_debug_info* msc_dbg, const BYTE* linetab, DWORD size, - const char* strimage, DWORD strsize) + const char* strimage, DWORD strsize) { - DWORD offset; unsigned i; DWORD addr; - const struct codeview_linetab2_block* lbh; - const struct codeview_linetab2_file* fd; + const struct codeview_linetab2* lt2; + const struct codeview_linetab2* lt2_files = NULL; + const struct codeview_lt2blk_lines* lines_blk; + const struct codeview_linetab2_file*fd; unsigned source; struct symt_function* func; - if (*(const DWORD*)linetab != 0x000000f4) return; - offset = *((const DWORD*)linetab + 1); - - for (lbh = (const struct codeview_linetab2_block*)(linetab + 8 + offset); - (const BYTE*)lbh < linetab + size; - lbh = (const struct codeview_linetab2_block*)((const char*)lbh + 8 + lbh->size_of_block)) + /* locate LT2_FILES_BLOCK (if any) */ + lt2 = (const struct codeview_linetab2*)linetab; + while ((const BYTE*)(lt2 + 1) < linetab + size) { - if (lbh->header != 0x000000f2) - /* FIXME: should also check that whole lbh fits in linetab + size */ + if (lt2->header == LT2_FILES_BLOCK) { - TRACE("block end %x\n", lbh->header); + lt2_files = lt2; break; } - addr = codeview_get_address(msc_dbg, lbh->seg, lbh->start); - TRACE("block from %04x:%08x #%x (%x lines)\n", - lbh->seg, lbh->start, lbh->size, lbh->nlines); - fd = (const struct codeview_linetab2_file*)(linetab + 8 + lbh->file_offset); - /* FIXME: should check that string is within strimage + strsize */ - source = source_new(msc_dbg->module, NULL, strimage + fd->offset); - func = (struct symt_function*)symt_find_nearest(msc_dbg->module, addr); - /* FIXME: at least labels support line numbers */ - if (!func || func->symt.tag != SymTagFunction) + lt2 = codeview_linetab2_next_block(lt2); + } + if (!lt2_files) + { + TRACE("No LT2_FILES_BLOCK found\n"); + return; + } + + lt2 = (const struct codeview_linetab2*)linetab; + while ((const BYTE*)(lt2 + 1) < linetab + size) + { + /* FIXME: should also check that whole lines_blk fits in linetab + size */ + switch (lt2->header) { - WARN("--not a func at %04x:%08x %x tag=%d\n", - lbh->seg, lbh->start, addr, func ? func->symt.tag : -1); + case LT2_LINES_BLOCK: + lines_blk = (const struct codeview_lt2blk_lines*)lt2; + /* FIXME: should check that file_offset is within the LT2_FILES_BLOCK we've seen */ + addr = codeview_get_address(msc_dbg, lines_blk->seg, lines_blk->start); + TRACE("block from %04x:%08x #%x (%x lines)\n", + lines_blk->seg, lines_blk->start, lines_blk->size, lines_blk->nlines); + fd = (const struct codeview_linetab2_file*)((const char*)lt2_files + 8 + lines_blk->file_offset); + /* FIXME: should check that string is within strimage + strsize */ + source = source_new(msc_dbg->module, NULL, strimage + fd->offset); + func = (struct symt_function*)symt_find_nearest(msc_dbg->module, addr); + /* FIXME: at least labels support line numbers */ + if (!func || func->symt.tag != SymTagFunction) + { + WARN("--not a func at %04x:%08x %x tag=%d\n", + lines_blk->seg, lines_blk->start, addr, func ? func->symt.tag : -1); + break; + } + for (i = 0; i < lines_blk->nlines; i++) + { + symt_add_func_line(msc_dbg->module, func, source, + lines_blk->l[i].lineno ^ 0x80000000, + lines_blk->l[i].offset); + } + break; + case LT2_FILES_BLOCK: /* skip */ + break; + default: + TRACE("Block end %x\n", lt2->header); + lt2 = (const struct codeview_linetab2*)((const char*)linetab + size); continue; } - for (i = 0; i < lbh->nlines; i++) - { - symt_add_func_line(msc_dbg->module, func, source, - lbh->l[i].lineno ^ 0x80000000, lbh->l[i].offset - lbh->start); - } + lt2 = codeview_linetab2_next_block(lt2); } } @@ -1897,8 +1926,7 @@ static int codeview_snarf_public(const struct msc_debug_info* msc_dbg, const BYT { symt_new_public(msc_dbg->module, compiland, terminate_string(&sym->data_v1.p_name), - codeview_get_address(msc_dbg, sym->data_v1.segment, sym->data_v1.offset), - 1, TRUE /* FIXME */, TRUE /* FIXME */); + codeview_get_address(msc_dbg, sym->data_v1.segment, sym->data_v1.offset), 1); } break; case S_PUB_V2: /* FIXME is this really a 'data_v2' structure ?? */ @@ -1906,8 +1934,7 @@ static int codeview_snarf_public(const struct msc_debug_info* msc_dbg, const BYT { symt_new_public(msc_dbg->module, compiland, terminate_string(&sym->data_v2.p_name), - codeview_get_address(msc_dbg, sym->data_v2.segment, sym->data_v2.offset), - 1, TRUE /* FIXME */, TRUE /* FIXME */); + codeview_get_address(msc_dbg, sym->data_v2.segment, sym->data_v2.offset), 1); } break; @@ -1916,8 +1943,7 @@ static int codeview_snarf_public(const struct msc_debug_info* msc_dbg, const BYT { symt_new_public(msc_dbg->module, compiland, sym->data_v3.name, - codeview_get_address(msc_dbg, sym->data_v3.segment, sym->data_v3.offset), - 1, FALSE /* FIXME */, FALSE); + codeview_get_address(msc_dbg, sym->data_v3.segment, sym->data_v3.offset), 1); } break; case S_PUB_FUNC1_V3: @@ -1928,8 +1954,7 @@ static int codeview_snarf_public(const struct msc_debug_info* msc_dbg, const BYT { symt_new_public(msc_dbg->module, compiland, sym->data_v3.name, - codeview_get_address(msc_dbg, sym->data_v3.segment, sym->data_v3.offset), - 1, TRUE /* FIXME */, TRUE); + codeview_get_address(msc_dbg, sym->data_v3.segment, sym->data_v3.offset), 1); } #endif break; @@ -2150,7 +2175,7 @@ static void pdb_convert_symbol_file(const PDB_SYMBOLS* symbols, { if (symbols->version < 19970000) { - const PDB_SYMBOL_FILE *sym_file = (const PDB_SYMBOL_FILE*)image; + const PDB_SYMBOL_FILE *sym_file = image; memset(sfile, 0, sizeof(*sfile)); sfile->file = sym_file->file; sfile->range.index = sym_file->range.index; @@ -2217,7 +2242,8 @@ static void pdb_process_types(const struct msc_debug_info* msc_dbg, case 19950410: /* VC 4.0 */ case 19951122: case 19961031: /* VC 5.0 / 6.0 */ - case 19990903: + case 19990903: /* VC 7.0 */ + case 20040203: /* VC 8.0 */ break; default: ERR("-Unknown type info version %d\n", types.version); @@ -2385,7 +2411,7 @@ static void pdb_process_symbol_imports(const struct process* pcs, imp = (const PDB_SYMBOL_IMPORT*)((const char*)symbols_image + sizeof(PDB_SYMBOLS) + symbols->module_size + symbols->offset_size + symbols->hash_size + symbols->srcmodule_size); - first = (const char*)imp; + first = imp; last = (const char*)imp + symbols->pdbimport_size; while (imp < (const PDB_SYMBOL_IMPORT*)last) { @@ -2524,7 +2550,7 @@ static BOOL pdb_process_internal(const struct process* pcs, } file_name = (const char*)file + size; file_name += strlen(file_name) + 1; - file = (BYTE*)((DWORD)(file_name + strlen(file_name) + 1 + 3) & ~3); + file = (BYTE*)((DWORD_PTR)(file_name + strlen(file_name) + 1 + 3) & ~3); } /* finish the remaining public and global information */ if (globalimage) diff --git a/reactos/dll/win32/dbghelp/path.c b/reactos/dll/win32/dbghelp/path.c index e0cfc97a082..12c595b4d1e 100644 --- a/reactos/dll/win32/dbghelp/path.c +++ b/reactos/dll/win32/dbghelp/path.c @@ -234,7 +234,7 @@ static BOOL do_searchW(PCWSTR file, PWSTR buffer, BOOL recurse, strcpyW(buffer + pos, fd.cFileName); if (recurse && (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) found = do_searchW(file, buffer, TRUE, cb, user); - else if (SymMatchFileNameW(buffer, (WCHAR*)file, NULL, NULL)) + else if (SymMatchFileNameW(buffer, file, NULL, NULL)) { if (!cb || cb(buffer, user)) found = TRUE; } @@ -340,13 +340,13 @@ struct sffip */ static BOOL CALLBACK sffip_cb(PCWSTR buffer, PVOID user) { - struct sffip* s = (struct sffip*)user; + struct sffip* s = user; if (!s->cb) return TRUE; /* yes, EnumDirTree/do_search and SymFindFileInPath callbacks use the opposite * convention to stop/continue enumeration. sigh. */ - return !(s->cb)((WCHAR*)buffer, s->user); + return !(s->cb)(buffer, s->user); } /****************************************************************** @@ -461,7 +461,7 @@ struct module_find */ static BOOL CALLBACK module_find_cb(PCWSTR buffer, PVOID user) { - struct module_find* mf = (struct module_find*)user; + struct module_find* mf = user; DWORD size, checksum, timestamp; unsigned matched = 0; @@ -522,6 +522,21 @@ static BOOL CALLBACK module_find_cb(PCWSTR buffer, PVOID user) return FALSE; } break; + case DMT_MACHO: + if (macho_fetch_file_info(buffer, 0, &size, &checksum)) + { + matched++; + if (checksum == mf->dw1) matched++; + else + WARN("Found %s, but wrong checksums: %08x %08x\n", + debugstr_w(buffer), checksum, mf->dw1); + } + else + { + WARN("Couldn't read %s\n", debugstr_w(buffer)); + return FALSE; + } + break; case DMT_PDB: { struct pdb_lookup pdb_lookup; @@ -580,7 +595,7 @@ static BOOL CALLBACK module_find_cb(PCWSTR buffer, PVOID user) if ((mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL) { const IMAGE_SEPARATE_DEBUG_HEADER* hdr; - hdr = (const IMAGE_SEPARATE_DEBUG_HEADER*)mapping; + hdr = mapping; if (hdr->Signature == IMAGE_SEPARATE_DEBUG_SIGNATURE) { diff --git a/reactos/dll/win32/dbghelp/pe_module.c b/reactos/dll/win32/dbghelp/pe_module.c index a79396f5191..76d81ee5512 100644 --- a/reactos/dll/win32/dbghelp/pe_module.c +++ b/reactos/dll/win32/dbghelp/pe_module.c @@ -35,6 +35,141 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); +/****************************************************************** + * pe_locate_with_coff_symbol_table + * + * Use the COFF symbol table (if any) from the IMAGE_FILE_HEADER to set the absolute address + * of global symbols. + * Mingw32 requires this for stabs debug information as address for global variables isn't filled in + * (this is similar to what is done in elf_module.c when using the .symtab ELF section) + */ +static BOOL pe_locate_with_coff_symbol_table(struct module* module, IMAGE_NT_HEADERS* nth, void* mapping) +{ + const IMAGE_SYMBOL* isym; + int i, numsym, naux; + const char* strtable; + char tmp[9]; + const char* name; + struct hash_table_iter hti; + void* ptr; + struct symt_data* sym; + const IMAGE_SECTION_HEADER* sect; + + numsym = nth->FileHeader.NumberOfSymbols; + if (!nth->FileHeader.PointerToSymbolTable || !numsym) + return TRUE; + isym = (const IMAGE_SYMBOL*)((char*)mapping + nth->FileHeader.PointerToSymbolTable); + /* FIXME: no way to get strtable size */ + strtable = (const char*)&isym[numsym]; + sect = IMAGE_FIRST_SECTION(nth); + + for (i = 0; i < numsym; i+= naux, isym += naux) + { + if (isym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL && + isym->SectionNumber > 0 && isym->SectionNumber <= nth->FileHeader.NumberOfSections) + { + if (isym->N.Name.Short) + { + name = memcpy(tmp, isym->N.ShortName, 8); + tmp[8] = '\0'; + } + else name = strtable + isym->N.Name.Long; + if (name[0] == '_') name++; + hash_table_iter_init(&module->ht_symbols, &hti, name); + while ((ptr = hash_table_iter_up(&hti))) + { + sym = GET_ENTRY(ptr, struct symt_data, hash_elt); + if (sym->symt.tag == SymTagData && + (sym->kind == DataIsGlobal || sym->kind == DataIsFileStatic) && + !strcmp(sym->hash_elt.name, name)) + { + TRACE("Changing absolute address for %d.%s: %lx -> %s\n", + isym->SectionNumber, name, sym->u.var.offset, + wine_dbgstr_longlong(module->module.BaseOfImage + + sect[isym->SectionNumber - 1].VirtualAddress + isym->Value)); + sym->u.var.offset = module->module.BaseOfImage + + sect[isym->SectionNumber - 1].VirtualAddress + isym->Value; + break; + } + } + } + naux = isym->NumberOfAuxSymbols + 1; + } + return TRUE; +} + +/****************************************************************** + * pe_load_coff_symbol_table + * + * Load public symbols out of the COFF symbol table (if any). + */ +static BOOL pe_load_coff_symbol_table(struct module* module, IMAGE_NT_HEADERS* nth, void* mapping) +{ + const IMAGE_SYMBOL* isym; + int i, numsym, naux; + const char* strtable; + char tmp[9]; + const char* name; + const char* lastfilename = NULL; + struct symt_compiland* compiland = NULL; + const IMAGE_SECTION_HEADER* sect; + + numsym = nth->FileHeader.NumberOfSymbols; + if (!nth->FileHeader.PointerToSymbolTable || !numsym) + return TRUE; + isym = (const IMAGE_SYMBOL*)((char*)mapping + nth->FileHeader.PointerToSymbolTable); + /* FIXME: no way to get strtable size */ + strtable = (const char*)&isym[numsym]; + sect = IMAGE_FIRST_SECTION(nth); + + for (i = 0; i < numsym; i+= naux, isym += naux) + { + if (isym->StorageClass == IMAGE_SYM_CLASS_FILE) + { + lastfilename = (const char*)(isym + 1); + compiland = NULL; + } + if (isym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL && + isym->SectionNumber > 0 && isym->SectionNumber <= nth->FileHeader.NumberOfSections) + { + if (isym->N.Name.Short) + { + name = memcpy(tmp, isym->N.ShortName, 8); + tmp[8] = '\0'; + } + else name = strtable + isym->N.Name.Long; + if (name[0] == '_') name++; + + if (!compiland && lastfilename) + compiland = symt_new_compiland(module, 0, + source_new(module, NULL, lastfilename)); + symt_new_public(module, compiland, name, + module->module.BaseOfImage + sect[isym->SectionNumber - 1].VirtualAddress + isym->Value, + 1); + } + naux = isym->NumberOfAuxSymbols + 1; + } + module->module.SymType = SymCoff; + module->module.LineNumbers = FALSE; + module->module.GlobalSymbols = FALSE; + module->module.TypeInfo = FALSE; + module->module.SourceIndexed = FALSE; + module->module.Publics = TRUE; + + return TRUE; +} + +static inline void* pe_get_sect(IMAGE_NT_HEADERS* nth, void* mapping, + IMAGE_SECTION_HEADER* sect) +{ + return (sect) ? RtlImageRvaToVa(nth, mapping, sect->VirtualAddress, NULL) : NULL; +} + +static inline DWORD pe_get_sect_size(IMAGE_SECTION_HEADER* sect) +{ + return (sect) ? sect->SizeOfRawData : 0; +} + /****************************************************************** * pe_load_stabs * @@ -45,37 +180,85 @@ static BOOL pe_load_stabs(const struct process* pcs, struct module* module, void* mapping, IMAGE_NT_HEADERS* nth) { IMAGE_SECTION_HEADER* section; - int i, stabsize = 0, stabstrsize = 0; - unsigned int stabs = 0, stabstr = 0; + IMAGE_SECTION_HEADER* sect_stabs = NULL; + IMAGE_SECTION_HEADER* sect_stabstr = NULL; + int i; BOOL ret = FALSE; section = (IMAGE_SECTION_HEADER*) ((char*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader); for (i = 0; i < nth->FileHeader.NumberOfSections; i++, section++) { - if (!strcasecmp((const char*)section->Name, ".stab")) - { - stabs = section->VirtualAddress; - stabsize = section->SizeOfRawData; - } - else if (!strncasecmp((const char*)section->Name, ".stabstr", 8)) - { - stabstr = section->VirtualAddress; - stabstrsize = section->SizeOfRawData; - } + if (!strcasecmp((const char*)section->Name, ".stab")) sect_stabs = section; + else if (!strncasecmp((const char*)section->Name, ".stabstr", 8)) sect_stabstr = section; } - - if (stabstrsize && stabsize) + if (sect_stabs && sect_stabstr) { - ret = stabs_parse(module, - module->module.BaseOfImage - nth->OptionalHeader.ImageBase, - RtlImageRvaToVa(nth, mapping, stabs, NULL), - stabsize, - RtlImageRvaToVa(nth, mapping, stabstr, NULL), - stabstrsize); + ret = stabs_parse(module, + module->module.BaseOfImage - nth->OptionalHeader.ImageBase, + pe_get_sect(nth, mapping, sect_stabs), pe_get_sect_size(sect_stabs), + pe_get_sect(nth, mapping, sect_stabstr), pe_get_sect_size(sect_stabstr), + NULL, NULL); + if (ret) pe_locate_with_coff_symbol_table(module, nth, mapping); } - TRACE("%s the STABS debug info\n", ret ? "successfully loaded" : "failed to load"); + + return ret; +} + +/****************************************************************** + * pe_load_dwarf + * + * look for dwarf information in PE header (it's also a way for the mingw compiler + * to provide its debugging information) + */ +static BOOL pe_load_dwarf(const struct process* pcs, struct module* module, + void* mapping, IMAGE_NT_HEADERS* nth) +{ + IMAGE_SECTION_HEADER* section; + IMAGE_SECTION_HEADER* sect_debuginfo = NULL; + IMAGE_SECTION_HEADER* sect_debugstr = NULL; + IMAGE_SECTION_HEADER* sect_debugabbrev = NULL; + IMAGE_SECTION_HEADER* sect_debugline = NULL; + IMAGE_SECTION_HEADER* sect_debugloc = NULL; + int i; + const char* strtable; + const char* sectname; + BOOL ret = FALSE; + + if (nth->FileHeader.PointerToSymbolTable && nth->FileHeader.NumberOfSymbols) + /* FIXME: no way to get strtable size */ + strtable = (const char*)mapping + nth->FileHeader.PointerToSymbolTable + + nth->FileHeader.NumberOfSymbols * sizeof(IMAGE_SYMBOL); + else strtable = NULL; + + section = (IMAGE_SECTION_HEADER*) + ((char*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader); + for (i = 0; i < nth->FileHeader.NumberOfSections; i++, section++) + { + sectname = (const char*)section->Name; + /* long section names start with a '/' (at least on MinGW32) */ + if (*sectname == '/' && strtable) + sectname = strtable + atoi(sectname + 1); + if (!strcasecmp(sectname, ".debug_info")) sect_debuginfo = section; + else if (!strcasecmp(sectname, ".debug_str")) sect_debugstr = section; + else if (!strcasecmp(sectname, ".debug_abbrev")) sect_debugabbrev = section; + else if (!strcasecmp(sectname, ".debug_line")) sect_debugline = section; + else if (!strcasecmp(sectname, ".debug_loc")) sect_debugloc = section; + } + if (sect_debuginfo) + { + ret = dwarf2_parse(module, + module->module.BaseOfImage - nth->OptionalHeader.ImageBase, + NULL, /* FIXME: some thunks to deal with ? */ + pe_get_sect(nth, mapping, sect_debuginfo), pe_get_sect_size(sect_debuginfo), + pe_get_sect(nth, mapping, sect_debugabbrev), pe_get_sect_size(sect_debugabbrev), + pe_get_sect(nth, mapping, sect_debugstr), pe_get_sect_size(sect_debugstr), + pe_get_sect(nth, mapping, sect_debugline), pe_get_sect_size(sect_debugline), + pe_get_sect(nth, mapping, sect_debugloc), pe_get_sect_size(sect_debugloc)); + } + TRACE("%s the DWARF debug info\n", ret ? "successfully loaded" : "failed to load"); + return ret; } @@ -133,7 +316,7 @@ static BOOL pe_load_dbg_file(const struct process* pcs, struct module* module, */ static BOOL pe_load_msc_debug_info(const struct process* pcs, struct module* module, - void* mapping, IMAGE_NT_HEADERS* nth) + void* mapping, const IMAGE_NT_HEADERS* nth) { BOOL ret = FALSE; const IMAGE_DATA_DIRECTORY* dir; @@ -181,7 +364,7 @@ static BOOL pe_load_msc_debug_info(const struct process* pcs, */ static BOOL pe_load_export_debug_info(const struct process* pcs, struct module* module, - void* mapping, IMAGE_NT_HEADERS* nth) + void* mapping, const IMAGE_NT_HEADERS* nth) { unsigned int i; const IMAGE_EXPORT_DIRECTORY* exports; @@ -193,14 +376,12 @@ static BOOL pe_load_export_debug_info(const struct process* pcs, #if 0 /* Add start of DLL (better use the (yet unimplemented) Exe SymTag for this) */ /* FIXME: module.ModuleName isn't correctly set yet if it's passed in SymLoadModule */ - symt_new_public(module, NULL, module->module.ModuleName, base, 1, - TRUE /* FIXME */, TRUE /* FIXME */); + symt_new_public(module, NULL, module->module.ModuleName, base, 1); #endif /* Add entry point */ symt_new_public(module, NULL, "EntryPoint", - base + nth->OptionalHeader.AddressOfEntryPoint, 1, - TRUE, TRUE); + base + nth->OptionalHeader.AddressOfEntryPoint, 1); #if 0 /* FIXME: we'd better store addresses linked to sections rather than absolute values */ @@ -211,8 +392,7 @@ static BOOL pe_load_export_debug_info(const struct process* pcs, for (i = 0; i < nth->FileHeader.NumberOfSections; i++, section++) { symt_new_public(module, NULL, section->Name, - RtlImageRvaToVa(nth, mapping, section->VirtualAddress, NULL), - 1, TRUE /* FIXME */, TRUE /* FIXME */); + RtlImageRvaToVa(nth, mapping, section->VirtualAddress, NULL), 1); } #endif @@ -237,8 +417,7 @@ static BOOL pe_load_export_debug_info(const struct process* pcs, if (!names[i]) continue; symt_new_public(module, NULL, RtlImageRvaToVa(nth, mapping, names[i], NULL), - base + functions[ordinals[i]], - 1, TRUE /* FIXME */, TRUE /* FIXME */); + base + functions[ordinals[i]], 1); } for (i = 0; i < exports->NumberOfFunctions; i++) @@ -249,8 +428,7 @@ static BOOL pe_load_export_debug_info(const struct process* pcs, if ((ordinals[j] == i) && names[j]) break; if (j < exports->NumberOfNames) continue; snprintf(buffer, sizeof(buffer), "%d", i + exports->Base); - symt_new_public(module, NULL, buffer, base + (DWORD)functions[i], 1, - TRUE /* FIXME */, TRUE /* FIXME */); + symt_new_public(module, NULL, buffer, base + (DWORD)functions[i], 1); } } } @@ -284,7 +462,9 @@ BOOL pe_load_debug_info(const struct process* pcs, struct module* module) if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY)) { ret = pe_load_stabs(pcs, module, mapping, nth) || - pe_load_msc_debug_info(pcs, module, mapping, nth); + pe_load_dwarf(pcs, module, mapping, nth) || + pe_load_msc_debug_info(pcs, module, mapping, nth) || + pe_load_coff_symbol_table(module, nth, mapping); /* if we still have no debug info (we could only get SymExport at this * point), then do the SymExport except if we have an ELF container, * in which case we'll rely on the export's on the ELF side @@ -367,13 +547,13 @@ struct module* pe_load_native_module(struct process* pcs, const WCHAR* name, * pe_load_nt_header * */ -BOOL pe_load_nt_header(HANDLE hProc, DWORD base, IMAGE_NT_HEADERS* nth) +BOOL pe_load_nt_header(HANDLE hProc, DWORD64 base, IMAGE_NT_HEADERS* nth) { IMAGE_DOS_HEADER dos; - return ReadProcessMemory(hProc, (char*)base, &dos, sizeof(dos), NULL) && + return ReadProcessMemory(hProc, (char*)(DWORD_PTR)base, &dos, sizeof(dos), NULL) && dos.e_magic == IMAGE_DOS_SIGNATURE && - ReadProcessMemory(hProc, (char*)(base + dos.e_lfanew), + ReadProcessMemory(hProc, (char*)(DWORD_PTR)(base + dos.e_lfanew), nth, sizeof(*nth), NULL) && nth->Signature == IMAGE_NT_SIGNATURE; } @@ -383,7 +563,7 @@ BOOL pe_load_nt_header(HANDLE hProc, DWORD base, IMAGE_NT_HEADERS* nth) * */ struct module* pe_load_builtin_module(struct process* pcs, const WCHAR* name, - DWORD base, DWORD size) + DWORD64 base, DWORD64 size) { struct module* module = NULL; @@ -435,7 +615,7 @@ PVOID WINAPI ImageDirectoryEntryToDataEx( PVOID base, BOOLEAN image, USHORT dir, *size = nt->OptionalHeader.DataDirectory[dir].Size; if (image || addr < nt->OptionalHeader.SizeOfHeaders) return (char *)base + addr; - return RtlImageRvaToVa( nt, (HMODULE)base, addr, section ); + return RtlImageRvaToVa( nt, base, addr, section ); } /*********************************************************************** diff --git a/reactos/dll/win32/dbghelp/rosstubs.c b/reactos/dll/win32/dbghelp/rosstubs.c index d6084612536..f4917899f6d 100644 --- a/reactos/dll/win32/dbghelp/rosstubs.c +++ b/reactos/dll/win32/dbghelp/rosstubs.c @@ -309,42 +309,6 @@ SymGetHomeDirectoryW(DWORD dwType, return NULL; } -BOOL WINAPI -SymGetLineFromName64(HANDLE hProcess, - PCSTR pszModuleName, - PCSTR pszFileName, - DWORD dwLineNumber, - PLONG plDisplacement, - PIMAGEHLP_LINE64 Line) -{ - UNIMPLEMENTED; - return FALSE; -} - -BOOL WINAPI -SymGetLineFromName(HANDLE hProcess, - PCSTR pszModuleName, - PCSTR pszFileName, - DWORD dwLineNumber, - PLONG plDisplacement, - PIMAGEHLP_LINE Line) -{ - UNIMPLEMENTED; - return FALSE; -} - -BOOL WINAPI -SymGetLineFromNameW64(HANDLE hProcess, - PCWSTR pszModuleName, - PCWSTR pszFileName, - DWORD dwLineNumber, - PLONG lpDisplacement, - PIMAGEHLP_LINEW64 Line) -{ - UNIMPLEMENTED; - return FALSE; -} - BOOL WINAPI SymGetLineNextW64(HANDLE hProcess, PIMAGEHLP_LINEW64 Line) @@ -459,31 +423,6 @@ SymGetSourceVarFromTokenW( return FALSE; } -BOOL WINAPI -SymGetSymFromName64(HANDLE hProcess, - PCSTR pszName, - PIMAGEHLP_SYMBOL64 Symbol) -{ - UNIMPLEMENTED; - return FALSE; -} - -BOOL WINAPI -SymGetSymNext64(HANDLE hProcess, - PIMAGEHLP_SYMBOL64 Symbol) -{ - UNIMPLEMENTED; - return FALSE; -} - -BOOL WINAPI -SymGetSymPrev64(HANDLE hProcess, - PIMAGEHLP_SYMBOL64 Symbol) -{ - UNIMPLEMENTED; - return FALSE; -} - BOOL WINAPI SymGetSymbolFile(HANDLE hProcess, PCSTR pszSymPath, @@ -581,16 +520,6 @@ SymPrevW(HANDLE hProcess, return FALSE; } -BOOL -WINAPI -SymRefreshModuleList( - HANDLE hProcess) -{ - UNIMPLEMENTED; - return FALSE; -} - - PCHAR WINAPI SymSetHomeDirectory(HANDLE hProcess, PCSTR pszDir) @@ -766,15 +695,6 @@ SymSrvStoreSupplementW(HANDLE hProcess, return NULL; } -BOOL WINAPI -SymUnDName64(PIMAGEHLP_SYMBOL64 Symbol, - PSTR pszUndecoratedName, - DWORD dwUndecoratedNameLength) -{ - UNIMPLEMENTED; - return FALSE; -} - DWORD WINAPI UnDecorateSymbolNameW(PCWSTR DecoratedName, PWSTR pszUnDecoratedName, diff --git a/reactos/dll/win32/dbghelp/source.c b/reactos/dll/win32/dbghelp/source.c index 8eef33727cd..c8ecf26c9fc 100644 --- a/reactos/dll/win32/dbghelp/source.c +++ b/reactos/dll/win32/dbghelp/source.c @@ -26,9 +26,6 @@ #include "dbghelp_private.h" #include "wine/debug.h" -#ifdef HAVE_REGEX_H -# include -#endif WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); @@ -79,13 +76,18 @@ unsigned source_new(struct module* module, const char* base, const char* name) int len = strlen(full) + 1; if (module->sources_used + len + 1 > module->sources_alloc) { - /* Alloc by block of 256 bytes */ - module->sources_alloc = (module->sources_used + len + 1 + 255) & ~255; if (!module->sources) + { + module->sources_alloc = (module->sources_used + len + 1 + 255) & ~255; module->sources = HeapAlloc(GetProcessHeap(), 0, module->sources_alloc); + } else + { + module->sources_alloc = max( module->sources_alloc * 2, + (module->sources_used + len + 1 + 255) & ~255 ); module->sources = HeapReAlloc(GetProcessHeap(), 0, module->sources, module->sources_alloc); + } } ret = module->sources_used; memcpy(module->sources + module->sources_used, full, len); @@ -154,116 +156,6 @@ BOOL WINAPI SymEnumSourceFiles(HANDLE hProcess, ULONG64 ModBase, PCSTR Mask, return TRUE; } -static inline void re_append(char** mask, unsigned* len, char ch) -{ - *mask = HeapReAlloc(GetProcessHeap(), 0, *mask, ++(*len)); - (*mask)[*len - 2] = ch; -} - -static BOOL compile_regex(regex_t* re, const char* srcfile) -{ - char* mask; - unsigned len = 1; - - mask = HeapAlloc(GetProcessHeap(), 0, 1); - re_append(&mask, &len, '^'); - if (!srcfile || !*srcfile) re_append(&mask, &len, '*'); - else while (*srcfile) - { - switch (*srcfile) - { - case '\\': - case '/': - re_append(&mask, &len, '['); - re_append(&mask, &len, '\\'); - re_append(&mask, &len, '\\'); - re_append(&mask, &len, '/'); - re_append(&mask, &len, ']'); - break; - case '.': - re_append(&mask, &len, '\\'); - re_append(&mask, &len, '.'); - break; - default: - re_append(&mask, &len, *srcfile); - break; - } - srcfile++; - } - re_append(&mask, &len, '$'); - mask[len - 1] = '\0'; - len = regcomp(re, mask, REG_NOSUB); - HeapFree(GetProcessHeap(), 0, mask); - if (len) - { - FIXME("Couldn't compile %s\n", mask); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - return TRUE; -} - -/****************************************************************** - * SymEnumLines (DBGHELP.@) - * - */ -BOOL WINAPI SymEnumLines(HANDLE hProcess, ULONG64 base, PCSTR compiland, - PCSTR srcfile, PSYM_ENUMLINES_CALLBACK cb, PVOID user) -{ - struct module_pair pair; - struct hash_table_iter hti; - struct symt_ht* sym; - regex_t re; - struct line_info* dli; - void* ptr; - SRCCODEINFO sci; - const char* file; - - if (!cb) return FALSE; - if (!(dbghelp_options & SYMOPT_LOAD_LINES)) return TRUE; - - pair.pcs = process_find_by_handle(hProcess); - if (!pair.pcs) return FALSE; - if (compiland) FIXME("Unsupported yet (filtering on compiland %s)\n", compiland); - pair.requested = module_find_by_addr(pair.pcs, base, DMT_UNKNOWN); - if (!module_get_debug(&pair)) return FALSE; - if (!compile_regex(&re, srcfile)) return FALSE; - - sci.SizeOfStruct = sizeof(sci); - sci.ModBase = base; - - hash_table_iter_init(&pair.effective->ht_symbols, &hti, NULL); - while ((ptr = hash_table_iter_up(&hti))) - { - unsigned int i; - - sym = GET_ENTRY(ptr, struct symt_ht, hash_elt); - if (sym->symt.tag != SymTagFunction) continue; - - sci.FileName[0] = '\0'; - for (i=0; ivlines); i++) - { - dli = vector_at(&((struct symt_function*)sym)->vlines, i); - if (dli->is_source_file) - { - file = source_get(pair.effective, dli->u.source_file); - if (regexec(&re, file, 0, NULL, 0) != 0) file = ""; - strcpy(sci.FileName, file); - } - else if (sci.FileName[0]) - { - sci.Key = dli; - sci.Obj[0] = '\0'; /* FIXME */ - sci.LineNumber = dli->line_number; - sci.Address = dli->u.pc_offset; - if (!cb(&sci, user)) break; - } - } - } - regfree(&re); - return TRUE; -} - /****************************************************************** * SymGetSourceFileToken (DBGHELP.@) * diff --git a/reactos/dll/win32/dbghelp/stabs.c b/reactos/dll/win32/dbghelp/stabs.c index a7f0fefae8c..367b04c72dd 100644 --- a/reactos/dll/win32/dbghelp/stabs.c +++ b/reactos/dll/win32/dbghelp/stabs.c @@ -26,7 +26,7 @@ * The "stabs" debug format * by Julia Menapace, Jim Kingdon, David Mackenzie * of Cygnus Support - * available (hopefully) from http:\\sources.redhat.com\gdb\onlinedocs + * available (hopefully) from http://sources.redhat.com/gdb/onlinedocs */ #include "config.h" @@ -53,6 +53,10 @@ #include #include +#ifdef HAVE_MACH_O_NLIST_H +# include +#endif + #include "windef.h" #include "winbase.h" #include "winnls.h" @@ -65,9 +69,24 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_stabs); #define strtoull _strtoui64 +/* Masks for n_type field */ +#ifndef N_STAB +#define N_STAB 0xe0 +#endif +#ifndef N_TYPE +#define N_TYPE 0x1e +#endif +#ifndef N_EXT +#define N_EXT 0x01 +#endif + +/* Values for (n_type & N_TYPE) */ #ifndef N_UNDF #define N_UNDF 0x00 #endif +#ifndef N_ABS +#define N_ABS 0x02 +#endif #define N_GSYM 0x20 #define N_FUN 0x24 @@ -81,6 +100,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_stabs); #define N_SLINE 0x44 #define N_ENSYM 0x4e #define N_SO 0x64 +#define N_OSO 0x66 #define N_LSYM 0x80 #define N_BINCL 0x82 #define N_SOL 0x84 @@ -162,14 +182,18 @@ static int stabs_new_include(const char* file, unsigned long val) { if (num_include_def == num_alloc_include_def) { - num_alloc_include_def += 256; if (!include_defs) - include_defs = HeapAlloc(GetProcessHeap(), 0, + { + num_alloc_include_def = 256; + include_defs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(include_defs[0]) * num_alloc_include_def); + } else - include_defs = HeapReAlloc(GetProcessHeap(), 0, include_defs, + { + num_alloc_include_def *= 2; + include_defs = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, include_defs, sizeof(include_defs[0]) * num_alloc_include_def); - memset(include_defs + num_include_def, 0, sizeof(include_defs[0]) * 256); + } } include_defs[num_include_def].name = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(file) + 1), file); include_defs[num_include_def].value = val; @@ -244,13 +268,13 @@ static struct symt** stabs_find_ref(long filenr, long subnr) { if (cu_nrofentries <= subnr) { + cu_nrofentries = max( cu_nrofentries * 2, subnr + 1 ); if (!cu_vector) - cu_vector = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(cu_vector[0]) * (subnr+1)); + cu_vector = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(cu_vector[0]) * cu_nrofentries); else - cu_vector = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - cu_vector, sizeof(cu_vector[0]) * (subnr+1)); - cu_nrofentries = subnr + 1; + cu_vector = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + cu_vector, sizeof(cu_vector[0]) * cu_nrofentries); } ret = &cu_vector[subnr]; } @@ -263,13 +287,13 @@ static struct symt** stabs_find_ref(long filenr, long subnr) if (idef->nrofentries <= subnr) { + idef->nrofentries = max( idef->nrofentries * 2, subnr + 1 ); if (!idef->vector) - idef->vector = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(idef->vector[0]) * (subnr+1)); + idef->vector = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(idef->vector[0]) * idef->nrofentries); else - idef->vector = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - idef->vector, sizeof(idef->vector[0]) * (subnr+1)); - idef->nrofentries = subnr + 1; + idef->vector = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + idef->vector, sizeof(idef->vector[0]) * idef->nrofentries); } ret = &idef->vector[subnr]; } @@ -630,25 +654,21 @@ static inline int stabs_pts_read_aggregate(struct ParseTypedefData* ptd, PTS_ABORTIF(ptd, stabs_pts_read_type_def(ptd, NULL, &adt) == -1); - if (doadd) + if (doadd && adt) { char tmp[256]; - WCHAR* name; DWORD64 size; - symt_get_info(adt, TI_GET_SYMNAME, &name); strcpy(tmp, "__inherited_class_"); - WideCharToMultiByte(CP_ACP, 0, name, -1, - tmp + strlen(tmp), sizeof(tmp) - strlen(tmp), - NULL, NULL); - HeapFree(GetProcessHeap(), 0, name); + strcat(tmp, symt_get_name(adt)); + /* FIXME: TI_GET_LENGTH will not always work, especially when adt * has just been seen as a forward definition and not the real stuff * yet. * As we don't use much the size of members in structs, this may not * be much of a problem */ - symt_get_info(adt, TI_GET_LENGTH, &size); + symt_get_info(ptd->module, adt, TI_GET_LENGTH, &size); symt_add_udt_element(ptd->module, sdt, tmp, adt, ofs, (DWORD)size * 8); } PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); @@ -1094,6 +1114,12 @@ static struct symt* stabs_parse_type(const char* stab) return *stabs_read_type_enum(&c); } +enum pending_obj_kind +{ + PENDING_VAR, + PENDING_LINE, +}; + struct pending_loc_var { char name[256]; @@ -1102,44 +1128,99 @@ struct pending_loc_var struct location loc; }; -struct pending_block +struct pending_line { - struct pending_loc_var* vars; + int source_idx; + int line_num; + unsigned long offset; + unsigned long load_offset; +}; + +struct pending_object +{ + enum pending_obj_kind tag; + union { + struct pending_loc_var var; + struct pending_line line; + } u; +}; + +struct pending_list +{ + struct pending_object* objs; unsigned num; unsigned allocated; }; -static inline void pending_add(struct pending_block* pending, const char* name, - enum DataKind dt, const struct location* loc) +static inline void pending_make_room(struct pending_list* pending) { if (pending->num == pending->allocated) { - pending->allocated += 8; - if (!pending->vars) - pending->vars = HeapAlloc(GetProcessHeap(), 0, - pending->allocated * sizeof(pending->vars[0])); - else - pending->vars = HeapReAlloc(GetProcessHeap(), 0, pending->vars, - pending->allocated * sizeof(pending->vars[0])); + if (!pending->objs) + { + pending->allocated = 8; + pending->objs = HeapAlloc(GetProcessHeap(), 0, + pending->allocated * sizeof(pending->objs[0])); + } + else + { + pending->allocated *= 2; + pending->objs = HeapReAlloc(GetProcessHeap(), 0, pending->objs, + pending->allocated * sizeof(pending->objs[0])); + } } - stab_strcpy(pending->vars[pending->num].name, - sizeof(pending->vars[pending->num].name), name); - pending->vars[pending->num].type = stabs_parse_type(name); - pending->vars[pending->num].kind = dt; - pending->vars[pending->num].loc = *loc; +} + +static inline void pending_add_var(struct pending_list* pending, const char* name, + enum DataKind dt, const struct location* loc) +{ + pending_make_room(pending); + pending->objs[pending->num].tag = PENDING_VAR; + stab_strcpy(pending->objs[pending->num].u.var.name, + sizeof(pending->objs[pending->num].u.var.name), name); + pending->objs[pending->num].u.var.type = stabs_parse_type(name); + pending->objs[pending->num].u.var.kind = dt; + pending->objs[pending->num].u.var.loc = *loc; pending->num++; } -static void pending_flush(struct pending_block* pending, struct module* module, +static inline void pending_add_line(struct pending_list* pending, int source_idx, + int line_num, unsigned long offset, + unsigned long load_offset) +{ + pending_make_room(pending); + pending->objs[pending->num].tag = PENDING_LINE; + pending->objs[pending->num].u.line.source_idx = source_idx; + pending->objs[pending->num].u.line.line_num = line_num; + pending->objs[pending->num].u.line.offset = offset; + pending->objs[pending->num].u.line.load_offset = load_offset; + pending->num++; +} + +static void pending_flush(struct pending_list* pending, struct module* module, struct symt_function* func, struct symt_block* block) { unsigned int i; for (i = 0; i < pending->num; i++) { - symt_add_func_local(module, func, - pending->vars[i].kind, &pending->vars[i].loc, - block, pending->vars[i].type, pending->vars[i].name); + switch (pending->objs[i].tag) + { + case PENDING_VAR: + symt_add_func_local(module, func, + pending->objs[i].u.var.kind, &pending->objs[i].u.var.loc, + block, pending->objs[i].u.var.type, pending->objs[i].u.var.name); + break; + case PENDING_LINE: + if (module->type == DMT_MACHO) + pending->objs[i].u.line.offset -= func->address - pending->objs[i].u.line.load_offset; + symt_add_func_line(module, func, pending->objs[i].u.line.source_idx, + pending->objs[i].u.line.line_num, pending->objs[i].u.line.offset); + break; + default: + ERR("Unknown pending object tag %u\n", (unsigned)pending->objs[i].tag); + break; + } } pending->num = 0; } @@ -1156,7 +1237,7 @@ static void pending_flush(struct pending_block* pending, struct module* module, static void stabs_finalize_function(struct module* module, struct symt_function* func, unsigned long size) { - IMAGEHLP_LINE il; + IMAGEHLP_LINE64 il; struct location loc; if (!func) return; @@ -1175,9 +1256,25 @@ static void stabs_finalize_function(struct module* module, struct symt_function* if (size) func->size = size; } +static inline void stabbuf_append(char **buf, unsigned *buf_size, const char *str) +{ + unsigned str_len, buf_len; + + str_len = strlen(str); + buf_len = strlen(*buf); + + if(str_len+buf_len >= *buf_size) { + *buf_size += buf_len + str_len; + *buf = HeapReAlloc(GetProcessHeap(), 0, *buf, *buf_size); + } + + strcpy(*buf+buf_len, str); +} + BOOL stabs_parse(struct module* module, unsigned long load_offset, const void* pv_stab_ptr, int stablen, - const char* strs, int strtablen) + const char* strs, int strtablen, + stabs_def_cb callback, void* user) { struct symt_function* curr_func = NULL; struct symt_block* block = NULL; @@ -1195,16 +1292,19 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset, unsigned incl[32]; int incl_stk = -1; int source_idx = -1; - struct pending_block pending; + struct pending_list pending_block; + struct pending_list pending_func; BOOL ret = TRUE; struct location loc; + unsigned char type; nstab = stablen / sizeof(struct stab_nlist); strs_end = strs + strtablen; memset(srcpath, 0, sizeof(srcpath)); memset(stabs_basic, 0, sizeof(stabs_basic)); - memset(&pending, 0, sizeof(pending)); + memset(&pending_block, 0, sizeof(pending_block)); + memset(&pending_func, 0, sizeof(pending_func)); /* * Allocate a buffer into which we can build stab strings for cases @@ -1230,23 +1330,22 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset, * next record. Repeat the process until we find a stab without the * '/' character, as this indicates we have the whole thing. */ - unsigned len = strlen(ptr); - if (strlen(stabbuff) + len > stabbufflen) - { - stabbufflen += 65536; - stabbuff = HeapReAlloc(GetProcessHeap(), 0, stabbuff, stabbufflen); - } - strncat(stabbuff, ptr, len - 1); + stabbuf_append(&stabbuff, &stabbufflen, ptr); continue; } else if (stabbuff[0] != '\0') { - strcat(stabbuff, ptr); + stabbuf_append(&stabbuff, &stabbufflen, ptr); ptr = stabbuff; } + if (stab_ptr->n_type & N_STAB) + type = stab_ptr->n_type; + else + type = (stab_ptr->n_type & N_TYPE); + /* only symbol entries contain a typedef */ - switch (stab_ptr->n_type) + switch (type) { case N_GSYM: case N_LCSYM: @@ -1263,7 +1362,8 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset, */ if (ptr != stabbuff) { - strcpy(stabbuff, ptr); + stabbuff[0] = 0; + stabbuf_append(&stabbuff, &stabbufflen, ptr); ptr = stabbuff; } stab_strcpy(symname, sizeof(symname), ptr); @@ -1276,7 +1376,7 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset, } } - switch (stab_ptr->n_type) + switch (type) { case N_GSYM: /* @@ -1305,7 +1405,7 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset, { block = symt_open_func_block(module, curr_func, block, stab_ptr->n_value, 0); - pending_flush(&pending, module, curr_func, block); + pending_flush(&pending_block, module, curr_func, block); } break; case N_RBRAC: @@ -1356,6 +1456,22 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset, case 17: case 18: case 19: loc.reg = CV_REG_ST0 + stab_ptr->n_value - 12; break; + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 27: + case 28: loc.reg = CV_REG_XMM0 + stab_ptr->n_value - 21; break; + case 29: + case 30: + case 31: + case 32: + case 33: + case 34: + case 35: + case 36: loc.reg = CV_REG_MM0 + stab_ptr->n_value - 29; break; default: FIXME("Unknown register value (%lu)\n", stab_ptr->n_value); loc.reg = CV_REG_NONE; @@ -1373,7 +1489,7 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset, param_type); } else - pending_add(&pending, ptr, DataIsLocal, &loc); + pending_add_var(&pending_block, ptr, DataIsLocal, &loc); } break; case N_LSYM: @@ -1381,19 +1497,24 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset, loc.kind = loc_regrel; loc.reg = 0; /* FIXME */ loc.offset = stab_ptr->n_value; - if (curr_func != NULL) pending_add(&pending, ptr, DataIsLocal, &loc); + if (curr_func != NULL) pending_add_var(&pending_block, ptr, DataIsLocal, &loc); break; case N_SLINE: /* * This is a line number. These are always relative to the start * of the function (N_FUN), and this makes the lookup easier. */ + assert(source_idx >= 0); if (curr_func != NULL) { - assert(source_idx >= 0); + unsigned long offset = stab_ptr->n_value; + if (module->type == DMT_MACHO) + offset -= curr_func->address - load_offset; symt_add_func_line(module, curr_func, source_idx, - stab_ptr->n_desc, stab_ptr->n_value); + stab_ptr->n_desc, offset); } + else pending_add_line(&pending_func, source_idx, stab_ptr->n_desc, + stab_ptr->n_value, load_offset); break; case N_FUN: /* @@ -1428,6 +1549,7 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset, curr_func = symt_new_function(module, compiland, symname, load_offset + stab_ptr->n_value, 0, &func_type->symt); + pending_flush(&pending_func, module, curr_func, NULL); } else { @@ -1508,10 +1630,38 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset, break; case N_BNSYM: case N_ENSYM: + case N_OSO: /* Always ignore these, they seem to be used only on Darwin. */ break; + case N_ABS: +#ifdef N_SECT + case N_SECT: +#endif + /* FIXME: Other definition types (N_TEXT, N_DATA, N_BSS, ...)? */ + if (callback) + { + BOOL is_public = (stab_ptr->n_type & N_EXT); + BOOL is_global = is_public; + +#ifdef N_PEXT + /* "private extern"; shared among compilation units in a shared + * library, but not accessible from outside the library. */ + if (stab_ptr->n_type & N_PEXT) + { + is_public = FALSE; + is_global = TRUE; + } +#endif + + if (*ptr == '_') ptr++; + stab_strcpy(symname, sizeof(symname), ptr); + + callback(module, load_offset, symname, stab_ptr->n_value, + is_public, is_global, stab_ptr->n_other, compiland, user); + } + break; default: - ERR("Unknown stab type 0x%02x\n", stab_ptr->n_type); + ERR("Unknown stab type 0x%02x\n", type); break; } stabbuff[0] = '\0'; @@ -1529,7 +1679,8 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset, done: HeapFree(GetProcessHeap(), 0, stabbuff); stabs_free_includes(); - HeapFree(GetProcessHeap(), 0, pending.vars); + HeapFree(GetProcessHeap(), 0, pending_block.objs); + HeapFree(GetProcessHeap(), 0, pending_func.objs); return ret; } diff --git a/reactos/dll/win32/dbghelp/stack.c b/reactos/dll/win32/dbghelp/stack.c index 3c66fcbc04c..d53629e80b4 100644 --- a/reactos/dll/win32/dbghelp/stack.c +++ b/reactos/dll/win32/dbghelp/stack.c @@ -27,40 +27,45 @@ #include #include -#include "ntstatus.h" -#define WIN32_NO_STATUS #include "dbghelp_private.h" -#include "winternl.h" -#include "wine/winbase16.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); -enum st_mode {stm_start, stm_32bit, stm_16bit, stm_done}; - -static const char* wine_dbgstr_addr(const ADDRESS* addr) +static DWORD64 WINAPI addr_to_linear(HANDLE hProcess, HANDLE hThread, ADDRESS64* addr) { - if (!addr) return "(null)"; + LDT_ENTRY le; + switch (addr->Mode) { - case AddrModeFlat: - return wine_dbg_sprintf("flat<%08x>", addr->Offset); case AddrMode1616: - return wine_dbg_sprintf("1616<%04x:%04x>", addr->Segment, addr->Offset); + if (GetThreadSelectorEntry(hThread, addr->Segment, &le)) + return (le.HighWord.Bits.BaseHi << 24) + + (le.HighWord.Bits.BaseMid << 16) + le.BaseLow + LOWORD(addr->Offset); + break; case AddrMode1632: - return wine_dbg_sprintf("1632<%04x:%08x>", addr->Segment, addr->Offset); + if (GetThreadSelectorEntry(hThread, addr->Segment, &le)) + return (le.HighWord.Bits.BaseHi << 24) + + (le.HighWord.Bits.BaseMid << 16) + le.BaseLow + addr->Offset; + break; case AddrModeReal: - return wine_dbg_sprintf("real<%04x:%04x>", addr->Segment, addr->Offset); + return (DWORD)(LOWORD(addr->Segment) << 4) + addr->Offset; + case AddrModeFlat: + return addr->Offset; default: - return "unknown"; + FIXME("Unsupported (yet) mode (%x)\n", addr->Mode); + return 0; } + FIXME("Failed to linearize address %04x:%s (mode %x)\n", + addr->Segment, wine_dbgstr_longlong(addr->Offset), addr->Mode); + return 0; } static BOOL CALLBACK read_mem(HANDLE hProcess, DWORD addr, void* buffer, DWORD size, LPDWORD nread) { SIZE_T r; - if (!ReadProcessMemory(hProcess, (void*)addr, buffer, size, &r)) return FALSE; + if (!ReadProcessMemory(hProcess, (void*)(DWORD_PTR)addr, buffer, size, &r)) return FALSE; if (nread) *nread = r; return TRUE; } @@ -74,39 +79,6 @@ static BOOL CALLBACK read_mem64(HANDLE hProcess, DWORD64 addr, void* buffer, return TRUE; } -/* indexes in Reserved array */ -#define __CurrentMode 0 -#define __CurrentSwitch 1 -#define __NextSwitch 2 - -#define curr_mode (frame->Reserved[__CurrentMode]) -#define curr_switch (frame->Reserved[__CurrentSwitch]) -#define next_switch (frame->Reserved[__NextSwitch]) - -struct stack_walk_callback -{ - HANDLE hProcess; - HANDLE hThread; - BOOL is32; - union - { - struct - { - PREAD_PROCESS_MEMORY_ROUTINE f_read_mem; - PTRANSLATE_ADDRESS_ROUTINE f_xlat_adr; - PFUNCTION_TABLE_ACCESS_ROUTINE f_tabl_acs; - PGET_MODULE_BASE_ROUTINE f_modl_bas; - } s32; - struct - { - PREAD_PROCESS_MEMORY_ROUTINE64 f_read_mem; - PTRANSLATE_ADDRESS_ROUTINE64 f_xlat_adr; - PFUNCTION_TABLE_ACCESS_ROUTINE64 f_tabl_acs; - PGET_MODULE_BASE_ROUTINE64 f_modl_bas; - } s64; - } u; -}; - static inline void addr_32to64(const ADDRESS* addr32, ADDRESS64* addr64) { addr64->Offset = (ULONG64)addr32->Offset; @@ -121,379 +93,113 @@ static inline void addr_64to32(const ADDRESS64* addr64, ADDRESS* addr32) addr32->Mode = addr64->Mode; } -static inline BOOL sw_read_mem(struct stack_walk_callback* cb, DWORD addr, void* ptr, DWORD sz) +BOOL sw_read_mem(struct cpu_stack_walk* csw, DWORD64 addr, void* ptr, DWORD sz) { - if (cb->is32) - return cb->u.s32.f_read_mem(cb->hProcess, addr, ptr, sz, NULL); + if (csw->is32) + return csw->u.s32.f_read_mem(csw->hProcess, addr, ptr, sz, NULL); else - return cb->u.s64.f_read_mem(cb->hProcess, addr, ptr, sz, NULL); + return csw->u.s64.f_read_mem(csw->hProcess, addr, ptr, sz, NULL); } -static inline DWORD sw_xlat_addr(struct stack_walk_callback* cb, ADDRESS* addr) +DWORD64 sw_xlat_addr(struct cpu_stack_walk* csw, ADDRESS64* addr) { if (addr->Mode == AddrModeFlat) return addr->Offset; - if (cb->is32) return cb->u.s32.f_xlat_adr(cb->hProcess, cb->hThread, addr); - if (cb->u.s64.f_xlat_adr) + if (csw->is32) { - ADDRESS64 addr64; + ADDRESS addr32; - addr_32to64(addr, &addr64); - return cb->u.s64.f_xlat_adr(cb->hProcess, cb->hThread, &addr64); + addr_64to32(addr, &addr32); + return csw->u.s32.f_xlat_adr(csw->hProcess, csw->hThread, &addr32); } - return addr_to_linear(cb->hProcess, cb->hThread, addr); + else if (csw->u.s64.f_xlat_adr) + return csw->u.s64.f_xlat_adr(csw->hProcess, csw->hThread, addr); + return addr_to_linear(csw->hProcess, csw->hThread, addr); } -static inline void* sw_tabl_acs(struct stack_walk_callback* cb, DWORD addr) +void* sw_table_access(struct cpu_stack_walk* csw, DWORD64 addr) { - if (cb->is32) - return cb->u.s32.f_tabl_acs(cb->hProcess, addr); + if (csw->is32) + return csw->u.s32.f_tabl_acs(csw->hProcess, addr); else - return cb->u.s64.f_tabl_acs(cb->hProcess, addr); + return csw->u.s64.f_tabl_acs(csw->hProcess, addr); } -static inline DWORD sw_modl_bas(struct stack_walk_callback* cb, DWORD addr) +DWORD64 sw_module_base(struct cpu_stack_walk* csw, DWORD64 addr) { - if (cb->is32) - return cb->u.s32.f_modl_bas(cb->hProcess, addr); + if (csw->is32) + return csw->u.s32.f_modl_bas(csw->hProcess, addr); else - return cb->u.s64.f_modl_bas(cb->hProcess, addr); -} - -static BOOL stack_walk(struct stack_walk_callback* cb, LPSTACKFRAME frame) -{ - STACK32FRAME frame32; - STACK16FRAME frame16; - char ch; - ADDRESS tmp; - DWORD p; - WORD val; - BOOL do_switch; - - /* sanity check */ - if (curr_mode >= stm_done) return FALSE; - - TRACE("Enter: PC=%s Frame=%s Return=%s Stack=%s Mode=%s cSwitch=%08x nSwitch=%08x\n", - wine_dbgstr_addr(&frame->AddrPC), - wine_dbgstr_addr(&frame->AddrFrame), - wine_dbgstr_addr(&frame->AddrReturn), - wine_dbgstr_addr(&frame->AddrStack), - curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"), - curr_switch, next_switch); - - if (curr_mode == stm_start) - { - THREAD_BASIC_INFORMATION info; - - if ((frame->AddrPC.Mode == AddrModeFlat) && - (frame->AddrFrame.Mode != AddrModeFlat)) - { - WARN("Bad AddrPC.Mode / AddrFrame.Mode combination\n"); - goto done_err; - } - - /* Init done */ - curr_mode = (frame->AddrPC.Mode == AddrModeFlat) ? - stm_32bit : stm_16bit; - - /* cur_switch holds address of WOW32Reserved field in TEB in debuggee - * address space - */ - if (NtQueryInformationThread(cb->hThread, ThreadBasicInformation, &info, - sizeof(info), NULL) == STATUS_SUCCESS) - { - curr_switch = (unsigned long)info.TebBaseAddress + FIELD_OFFSET(TEB, WOW32Reserved); - if (!sw_read_mem(cb, curr_switch, &next_switch, sizeof(next_switch))) - { - WARN("Can't read TEB:WOW32Reserved\n"); - goto done_err; - } - if (curr_mode == stm_16bit) - { - if (!sw_read_mem(cb, next_switch, &frame32, sizeof(frame32))) - { - WARN("Bad stack frame 0x%08x\n", next_switch); - goto done_err; - } - curr_switch = (DWORD)frame32.frame16; - tmp.Mode = AddrMode1616; - tmp.Segment = SELECTOROF(curr_switch); - tmp.Offset = OFFSETOF(curr_switch); - if (!sw_read_mem(cb, sw_xlat_addr(cb, &tmp), &ch, sizeof(ch))) - curr_switch = 0xFFFFFFFF; - } - else - { - tmp.Mode = AddrMode1616; - tmp.Segment = SELECTOROF(next_switch); - tmp.Offset = OFFSETOF(next_switch); - p = sw_xlat_addr(cb, &tmp); - if (!sw_read_mem(cb, p, &frame16, sizeof(frame16))) - { - WARN("Bad stack frame 0x%08x\n", p); - goto done_err; - } - curr_switch = (DWORD)frame16.frame32; - - if (!sw_read_mem(cb, curr_switch, &ch, sizeof(ch))) - curr_switch = 0xFFFFFFFF; - } - } - else - /* FIXME: this will allow to work when we're not attached to a live target, - * but the 16 <=> 32 switch facility won't be available. - */ - curr_switch = 0; - frame->AddrReturn.Mode = frame->AddrStack.Mode = (curr_mode == stm_16bit) ? AddrMode1616 : AddrModeFlat; - /* don't set up AddrStack on first call. Either the caller has set it up, or - * we will get it in the next frame - */ - memset(&frame->AddrBStore, 0, sizeof(frame->AddrBStore)); - } - else - { - if (frame->AddrFrame.Offset == 0) goto done_err; - if (frame->AddrFrame.Mode == AddrModeFlat) - { - assert(curr_mode == stm_32bit); - do_switch = curr_switch && frame->AddrFrame.Offset >= curr_switch; - } - else - { - assert(curr_mode == stm_16bit); - do_switch = curr_switch && - frame->AddrFrame.Segment == SELECTOROF(curr_switch) && - frame->AddrFrame.Offset >= OFFSETOF(curr_switch); - } - - if (do_switch) - { - if (curr_mode == stm_16bit) - { - if (!sw_read_mem(cb, next_switch, &frame32, sizeof(frame32))) - { - WARN("Bad stack frame 0x%08x\n", next_switch); - goto done_err; - } - - frame->AddrPC.Mode = AddrModeFlat; - frame->AddrPC.Segment = 0; - frame->AddrPC.Offset = frame32.retaddr; - frame->AddrFrame.Mode = AddrModeFlat; - frame->AddrFrame.Segment = 0; - frame->AddrFrame.Offset = frame32.ebp; - - frame->AddrStack.Mode = AddrModeFlat; - frame->AddrStack.Segment = 0; - frame->AddrReturn.Mode = AddrModeFlat; - frame->AddrReturn.Segment = 0; - - next_switch = curr_switch; - tmp.Mode = AddrMode1616; - tmp.Segment = SELECTOROF(next_switch); - tmp.Offset = OFFSETOF(next_switch); - p = sw_xlat_addr(cb, &tmp); - - if (!sw_read_mem(cb, p, &frame16, sizeof(frame16))) - { - WARN("Bad stack frame 0x%08x\n", p); - goto done_err; - } - curr_switch = (DWORD)frame16.frame32; - curr_mode = stm_32bit; - if (!sw_read_mem(cb, curr_switch, &ch, sizeof(ch))) - curr_switch = 0; - } - else - { - tmp.Mode = AddrMode1616; - tmp.Segment = SELECTOROF(next_switch); - tmp.Offset = OFFSETOF(next_switch); - p = sw_xlat_addr(cb, &tmp); - - if (!sw_read_mem(cb, p, &frame16, sizeof(frame16))) - { - WARN("Bad stack frame 0x%08x\n", p); - goto done_err; - } - - TRACE("Got a 16 bit stack switch:" - "\n\tframe32: %08lx" - "\n\tedx:%08x ecx:%08x ebp:%08x" - "\n\tds:%04x es:%04x fs:%04x gs:%04x" - "\n\tcall_from_ip:%08x module_cs:%04x relay=%08x" - "\n\tentry_ip:%04x entry_point:%08x" - "\n\tbp:%04x ip:%04x cs:%04x\n", - (unsigned long)frame16.frame32, - frame16.edx, frame16.ecx, frame16.ebp, - frame16.ds, frame16.es, frame16.fs, frame16.gs, - frame16.callfrom_ip, frame16.module_cs, frame16.relay, - frame16.entry_ip, frame16.entry_point, - frame16.bp, frame16.ip, frame16.cs); - - - frame->AddrPC.Mode = AddrMode1616; - frame->AddrPC.Segment = frame16.cs; - frame->AddrPC.Offset = frame16.ip; - - frame->AddrFrame.Mode = AddrMode1616; - frame->AddrFrame.Segment = SELECTOROF(next_switch); - frame->AddrFrame.Offset = frame16.bp; - - frame->AddrStack.Mode = AddrMode1616; - frame->AddrStack.Segment = SELECTOROF(next_switch); - - frame->AddrReturn.Mode = AddrMode1616; - frame->AddrReturn.Segment = frame16.cs; - - next_switch = curr_switch; - if (!sw_read_mem(cb, next_switch, &frame32, sizeof(frame32))) - { - WARN("Bad stack frame 0x%08x\n", next_switch); - goto done_err; - } - curr_switch = (DWORD)frame32.frame16; - tmp.Mode = AddrMode1616; - tmp.Segment = SELECTOROF(curr_switch); - tmp.Offset = OFFSETOF(curr_switch); - - if (!sw_read_mem(cb, sw_xlat_addr(cb, &tmp), &ch, sizeof(ch))) - curr_switch = 0; - curr_mode = stm_16bit; - } - } - else - { - frame->AddrPC = frame->AddrReturn; - if (curr_mode == stm_16bit) - { - frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(WORD); - /* "pop up" previous BP value */ - if (!sw_read_mem(cb, sw_xlat_addr(cb, &frame->AddrFrame), - &val, sizeof(WORD))) - goto done_err; - frame->AddrFrame.Offset = val; - } - else - { - frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(DWORD); - /* "pop up" previous EBP value */ - if (!sw_read_mem(cb, frame->AddrFrame.Offset, - &frame->AddrFrame.Offset, sizeof(DWORD))) - goto done_err; - } - } - } - - if (curr_mode == stm_16bit) - { - unsigned int i; - - p = sw_xlat_addr(cb, &frame->AddrFrame); - if (!sw_read_mem(cb, p + sizeof(WORD), &val, sizeof(WORD))) - goto done_err; - frame->AddrReturn.Offset = val; - /* get potential cs if a far call was used */ - if (!sw_read_mem(cb, p + 2 * sizeof(WORD), &val, sizeof(WORD))) - goto done_err; - if (frame->AddrFrame.Offset & 1) - frame->AddrReturn.Segment = val; /* far call assumed */ - else - { - /* not explicitly marked as far call, - * but check whether it could be anyway - */ - if ((val & 7) == 7 && val != frame->AddrReturn.Segment) - { - LDT_ENTRY le; - - if (GetThreadSelectorEntry(cb->hThread, val, &le) && - (le.HighWord.Bits.Type & 0x08)) /* code segment */ - { - /* it is very uncommon to push a code segment cs as - * a parameter, so this should work in most cases - */ - frame->AddrReturn.Segment = val; - } - } - } - frame->AddrFrame.Offset &= ~1; - /* we "pop" parameters as 16 bit entities... of course, this won't - * work if the parameter is in fact bigger than 16bit, but - * there's no way to know that here - */ - for (i = 0; i < sizeof(frame->Params) / sizeof(frame->Params[0]); i++) - { - sw_read_mem(cb, p + (2 + i) * sizeof(WORD), &val, sizeof(val)); - frame->Params[i] = val; - } - } - else - { - if (!sw_read_mem(cb, frame->AddrFrame.Offset + sizeof(DWORD), - &frame->AddrReturn.Offset, sizeof(DWORD))) - { - WARN("Cannot read new frame offset %08x\n", frame->AddrFrame.Offset + (int)sizeof(DWORD)); - goto done_err; - } - sw_read_mem(cb, frame->AddrFrame.Offset + 2 * sizeof(DWORD), - frame->Params, sizeof(frame->Params)); - } - - frame->Far = TRUE; - frame->Virtual = TRUE; - p = sw_xlat_addr(cb, &frame->AddrPC); - if (p && sw_modl_bas(cb, p)) - frame->FuncTableEntry = sw_tabl_acs(cb, p); - else - frame->FuncTableEntry = NULL; - - TRACE("Leave: PC=%s Frame=%s Return=%s Stack=%s Mode=%s cSwitch=%08x nSwitch=%08x FuncTable=%p\n", - wine_dbgstr_addr(&frame->AddrPC), - wine_dbgstr_addr(&frame->AddrFrame), - wine_dbgstr_addr(&frame->AddrReturn), - wine_dbgstr_addr(&frame->AddrStack), - curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"), - curr_switch, next_switch, frame->FuncTableEntry); - - return TRUE; -done_err: - curr_mode = stm_done; - return FALSE; + return csw->u.s64.f_modl_bas(csw->hProcess, addr); } /*********************************************************************** * StackWalk (DBGHELP.@) */ BOOL WINAPI StackWalk(DWORD MachineType, HANDLE hProcess, HANDLE hThread, - LPSTACKFRAME frame, PVOID ctx, + LPSTACKFRAME frame32, PVOID ctx, PREAD_PROCESS_MEMORY_ROUTINE f_read_mem, PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine, PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine, PTRANSLATE_ADDRESS_ROUTINE f_xlat_adr) { - struct stack_walk_callback swcb; + struct cpu_stack_walk csw; + STACKFRAME64 frame64; + BOOL ret; + struct cpu* cpu; TRACE("(%d, %p, %p, %p, %p, %p, %p, %p, %p)\n", - MachineType, hProcess, hThread, frame, ctx, + MachineType, hProcess, hThread, frame32, ctx, f_read_mem, FunctionTableAccessRoutine, GetModuleBaseRoutine, f_xlat_adr); - if (MachineType != IMAGE_FILE_MACHINE_I386) + if (!(cpu = cpu_find(MachineType))) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - swcb.hProcess = hProcess; - swcb.hThread = hThread; - swcb.is32 = TRUE; - /* sigh... MS isn't even consistent in the func prototypes */ - swcb.u.s32.f_read_mem = (f_read_mem) ? f_read_mem : read_mem; - swcb.u.s32.f_xlat_adr = (f_xlat_adr) ? f_xlat_adr : addr_to_linear; - swcb.u.s32.f_tabl_acs = (FunctionTableAccessRoutine) ? FunctionTableAccessRoutine : SymFunctionTableAccess; - swcb.u.s32.f_modl_bas = (GetModuleBaseRoutine) ? GetModuleBaseRoutine : SymGetModuleBase; + addr_32to64(&frame32->AddrPC, &frame64.AddrPC); + addr_32to64(&frame32->AddrReturn, &frame64.AddrReturn); + addr_32to64(&frame32->AddrFrame, &frame64.AddrFrame); + addr_32to64(&frame32->AddrStack, &frame64.AddrStack); + addr_32to64(&frame32->AddrBStore, &frame64.AddrBStore); + frame64.FuncTableEntry = frame32->FuncTableEntry; /* FIXME */ + frame64.Far = frame32->Far; + frame64.Virtual = frame32->Virtual; + frame64.Reserved[0] = frame32->Reserved[0]; + frame64.Reserved[1] = frame32->Reserved[1]; + frame64.Reserved[2] = frame32->Reserved[2]; + /* we don't handle KdHelp */ - return stack_walk(&swcb, frame); + csw.hProcess = hProcess; + csw.hThread = hThread; + csw.is32 = TRUE; + /* sigh... MS isn't even consistent in the func prototypes */ + csw.u.s32.f_read_mem = (f_read_mem) ? f_read_mem : read_mem; + csw.u.s32.f_xlat_adr = f_xlat_adr; + csw.u.s32.f_tabl_acs = (FunctionTableAccessRoutine) ? FunctionTableAccessRoutine : SymFunctionTableAccess; + csw.u.s32.f_modl_bas = (GetModuleBaseRoutine) ? GetModuleBaseRoutine : SymGetModuleBase; + + if ((ret = cpu->stack_walk(&csw, &frame64))) + { + addr_64to32(&frame64.AddrPC, &frame32->AddrPC); + addr_64to32(&frame64.AddrReturn, &frame32->AddrReturn); + addr_64to32(&frame64.AddrFrame, &frame32->AddrFrame); + addr_64to32(&frame64.AddrStack, &frame32->AddrStack); + addr_64to32(&frame64.AddrBStore, &frame32->AddrBStore); + frame32->FuncTableEntry = frame64.FuncTableEntry; /* FIXME */ + frame32->Params[0] = frame64.Params[0]; + frame32->Params[1] = frame64.Params[1]; + frame32->Params[2] = frame64.Params[2]; + frame32->Params[3] = frame64.Params[3]; + frame32->Far = frame64.Far; + frame32->Virtual = frame64.Virtual; + frame32->Reserved[0] = frame64.Reserved[0]; + frame32->Reserved[1] = frame64.Reserved[1]; + frame32->Reserved[2] = frame64.Reserved[2]; + } + + return ret; } @@ -501,78 +207,49 @@ BOOL WINAPI StackWalk(DWORD MachineType, HANDLE hProcess, HANDLE hThread, * StackWalk64 (DBGHELP.@) */ BOOL WINAPI StackWalk64(DWORD MachineType, HANDLE hProcess, HANDLE hThread, - LPSTACKFRAME64 frame64, PVOID ctx, + LPSTACKFRAME64 frame, PVOID ctx, PREAD_PROCESS_MEMORY_ROUTINE64 f_read_mem, PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, PTRANSLATE_ADDRESS_ROUTINE64 f_xlat_adr) { - struct stack_walk_callback swcb; - STACKFRAME frame32; - BOOL ret; + struct cpu_stack_walk csw; + struct cpu* cpu; TRACE("(%d, %p, %p, %p, %p, %p, %p, %p, %p)\n", - MachineType, hProcess, hThread, frame64, ctx, + MachineType, hProcess, hThread, frame, ctx, f_read_mem, FunctionTableAccessRoutine, GetModuleBaseRoutine, f_xlat_adr); - if (MachineType != IMAGE_FILE_MACHINE_I386) + if (!(cpu = cpu_find(MachineType))) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - addr_64to32(&frame64->AddrPC, &frame32.AddrPC); - addr_64to32(&frame64->AddrReturn, &frame32.AddrReturn); - addr_64to32(&frame64->AddrFrame, &frame32.AddrFrame); - addr_64to32(&frame64->AddrStack, &frame32.AddrStack); - addr_64to32(&frame64->AddrBStore, &frame32.AddrBStore); - frame32.FuncTableEntry = frame64->FuncTableEntry; /* FIXME */ - frame32.Far = frame64->Far; - frame32.Virtual = frame64->Virtual; - frame32.Reserved[0] = (ULONG)frame64->Reserved[0]; - frame32.Reserved[1] = (ULONG)frame64->Reserved[1]; - frame32.Reserved[2] = (ULONG)frame64->Reserved[2]; - /* we don't handle KdHelp */ - - swcb.hProcess = hProcess; - swcb.hThread = hThread; - swcb.is32 = FALSE; + csw.hProcess = hProcess; + csw.hThread = hThread; + csw.is32 = FALSE; /* sigh... MS isn't even consistent in the func prototypes */ - swcb.u.s64.f_read_mem = (f_read_mem) ? f_read_mem : read_mem64; - swcb.u.s64.f_xlat_adr = f_xlat_adr; - swcb.u.s64.f_tabl_acs = (FunctionTableAccessRoutine) ? FunctionTableAccessRoutine : SymFunctionTableAccess64; - swcb.u.s64.f_modl_bas = (GetModuleBaseRoutine) ? GetModuleBaseRoutine : SymGetModuleBase64; + csw.u.s64.f_read_mem = (f_read_mem) ? f_read_mem : read_mem64; + csw.u.s64.f_xlat_adr = (f_xlat_adr) ? f_xlat_adr : addr_to_linear; + csw.u.s64.f_tabl_acs = (FunctionTableAccessRoutine) ? FunctionTableAccessRoutine : SymFunctionTableAccess64; + csw.u.s64.f_modl_bas = (GetModuleBaseRoutine) ? GetModuleBaseRoutine : SymGetModuleBase64; - ret = stack_walk(&swcb, &frame32); + if (!cpu->stack_walk(&csw, frame)) return FALSE; - addr_32to64(&frame32.AddrPC, &frame64->AddrPC); - addr_32to64(&frame32.AddrReturn, &frame64->AddrReturn); - addr_32to64(&frame32.AddrFrame, &frame64->AddrFrame); - addr_32to64(&frame32.AddrStack, &frame64->AddrStack); - addr_32to64(&frame32.AddrBStore, &frame64->AddrBStore); - frame64->FuncTableEntry = frame32.FuncTableEntry; /* FIXME */ - frame64->Params[0] = frame32.Params[0]; - frame64->Params[1] = frame32.Params[1]; - frame64->Params[2] = frame32.Params[2]; - frame64->Params[3] = frame32.Params[3]; - frame64->Far = frame32.Far; - frame64->Virtual = frame32.Virtual; - frame64->Reserved[0] = frame32.Reserved[0]; - frame64->Reserved[1] = frame32.Reserved[1]; - frame64->Reserved[2] = frame32.Reserved[2]; /* we don't handle KdHelp */ - frame64->KdHelp.Thread = 0xC000FADE; - frame64->KdHelp.ThCallbackStack = 0x10; - frame64->KdHelp.ThCallbackBStore = 0; - frame64->KdHelp.NextCallback = 0; - frame64->KdHelp.FramePointer = 0; - frame64->KdHelp.KiCallUserMode = 0xD000DAFE; - frame64->KdHelp.KeUserCallbackDispatcher = 0xE000F000; - frame64->KdHelp.SystemRangeStart = 0xC0000000; - frame64->KdHelp.Reserved[0] /* KiUserExceptionDispatcher */ = 0xE0005000; + frame->KdHelp.Thread = 0xC000FADE; + frame->KdHelp.ThCallbackStack = 0x10; + frame->KdHelp.ThCallbackBStore = 0; + frame->KdHelp.NextCallback = 0; + frame->KdHelp.FramePointer = 0; + frame->KdHelp.KiCallUserMode = 0xD000DAFE; + frame->KdHelp.KeUserCallbackDispatcher = 0xE000F000; + frame->KdHelp.SystemRangeStart = 0xC0000000; + frame->KdHelp.Reserved[0] /* KiUserExceptionDispatcher */ = 0xE0005000; - return ret; + return TRUE; } /****************************************************************** diff --git a/reactos/dll/win32/dbghelp/storage.c b/reactos/dll/win32/dbghelp/storage.c index baca0530b34..c7f06cc11bd 100644 --- a/reactos/dll/win32/dbghelp/storage.c +++ b/reactos/dll/win32/dbghelp/storage.c @@ -34,14 +34,16 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); struct pool_arena { - struct pool_arena* next; - char* current; + struct list entry; + char *current; + char *end; }; -void pool_init(struct pool* a, unsigned arena_size) +void pool_init(struct pool* a, size_t arena_size) { + list_init( &a->arena_list ); + list_init( &a->arena_full ); a->arena_size = arena_size; - a->first = NULL; } void pool_destroy(struct pool* pool) @@ -50,58 +52,73 @@ void pool_destroy(struct pool* pool) struct pool_arena* next; #ifdef USE_STATS - unsigned alloc, used, num; - + size_t alloc, used, num; + alloc = used = num = 0; - arena = pool->first; - while (arena) + LIST_FOR_EACH_ENTRY( arena, &pool->arena_list, struct pool_arena, entry ) { - alloc += pool->arena_size; + alloc += arena->end - (char *)arena; + used += arena->current - (char*)arena; + num++; + } + LIST_FOR_EACH_ENTRY( arena, &pool->arena_full, struct pool_arena, entry ) + { + alloc += arena->end - (char *)arena; used += arena->current - (char*)arena; num++; - arena = arena->next; } if (alloc == 0) alloc = 1; /* avoid division by zero */ - FIXME("STATS: pool %p has allocated %u kbytes, used %u kbytes in %u arenas,\n" - "\t\t\t\tnon-allocation ratio: %.2f%%\n", - pool, alloc >> 10, used >> 10, num, 100.0 - (float)used / (float)alloc * 100.0); + FIXME("STATS: pool %p has allocated %u kbytes, used %u kbytes in %u arenas, non-allocation ratio: %.2f%%\n", + pool, (unsigned)(alloc >> 10), (unsigned)(used >> 10), (unsigned)num, + 100.0 - (float)used / (float)alloc * 100.0); #endif - arena = pool->first; - while (arena) + LIST_FOR_EACH_ENTRY_SAFE( arena, next, &pool->arena_list, struct pool_arena, entry ) { - next = arena->next; + list_remove( &arena->entry ); + HeapFree(GetProcessHeap(), 0, arena); + } + LIST_FOR_EACH_ENTRY_SAFE( arena, next, &pool->arena_full, struct pool_arena, entry ) + { + list_remove( &arena->entry ); HeapFree(GetProcessHeap(), 0, arena); - arena = next; } - pool_init(pool, 0); } -void* pool_alloc(struct pool* pool, unsigned len) +void* pool_alloc(struct pool* pool, size_t len) { struct pool_arena* arena; void* ret; + size_t size; len = (len + 3) & ~3; /* round up size on DWORD boundary */ - assert(sizeof(struct pool_arena) + len <= pool->arena_size && len); - for (arena = pool->first; arena; arena = arena->next) + LIST_FOR_EACH_ENTRY( arena, &pool->arena_list, struct pool_arena, entry ) { - if ((char*)arena + pool->arena_size - arena->current >= len) + if (arena->end - arena->current >= len) { ret = arena->current; arena->current += len; + if (arena->current + 16 >= arena->end) + { + list_remove( &arena->entry ); + list_add_tail( &pool->arena_full, &arena->entry ); + } return ret; } } - arena = HeapAlloc(GetProcessHeap(), 0, pool->arena_size); - if (!arena) {ERR("OOM\n");return NULL;} + size = max( pool->arena_size, len ); + arena = HeapAlloc(GetProcessHeap(), 0, size + sizeof(struct pool_arena)); + if (!arena) return NULL; - ret = (char*)arena + sizeof(*arena); - arena->next = pool->first; - pool->first = arena; + ret = arena + 1; arena->current = (char*)ret + len; + arena->end = (char*)ret + size; + if (arena->current + 16 >= arena->end) + list_add_tail( &pool->arena_full, &arena->entry ); + else + list_add_head( &pool->arena_list, &arena->entry ); return ret; } @@ -298,7 +315,7 @@ unsigned sparse_array_length(const struct sparse_array* sa) return sa->elements.num_elts; } -unsigned hash_table_hash(const char* name, unsigned num_buckets) +static unsigned hash_table_hash(const char* name, unsigned num_buckets) { unsigned hash = 0; while (*name) diff --git a/reactos/dll/win32/dbghelp/symbol.c b/reactos/dll/win32/dbghelp/symbol.c index 280666d0694..07ba9a37cef 100644 --- a/reactos/dll/win32/dbghelp/symbol.c +++ b/reactos/dll/win32/dbghelp/symbol.c @@ -48,31 +48,99 @@ static inline int cmp_addr(ULONG64 a1, ULONG64 a2) return 0; } -static inline int cmp_sorttab_addr(const struct module* module, int idx, ULONG64 addr) +static inline int cmp_sorttab_addr(struct module* module, int idx, ULONG64 addr) { ULONG64 ref; - symt_get_info(&module->addr_sorttab[idx]->symt, TI_GET_ADDRESS, &ref); + symt_get_info(module, &module->addr_sorttab[idx]->symt, TI_GET_ADDRESS, &ref); return cmp_addr(ref, addr); } +struct module* symt_cmp_addr_module = NULL; + int symt_cmp_addr(const void* p1, const void* p2) { const struct symt* sym1 = *(const struct symt* const *)p1; const struct symt* sym2 = *(const struct symt* const *)p2; ULONG64 a1, a2; - symt_get_info(sym1, TI_GET_ADDRESS, &a1); - symt_get_info(sym2, TI_GET_ADDRESS, &a2); + symt_get_info(symt_cmp_addr_module, sym1, TI_GET_ADDRESS, &a1); + symt_get_info(symt_cmp_addr_module, sym2, TI_GET_ADDRESS, &a2); return cmp_addr(a1, a2); } -static inline void re_append(char** mask, unsigned* len, char ch) +DWORD symt_ptr2index(struct module* module, const struct symt* sym) { - *mask = HeapReAlloc(GetProcessHeap(), 0, *mask, ++(*len)); - (*mask)[*len - 2] = ch; +#ifdef _WIN64 + const struct symt** c; + int len = vector_length(&module->vsymt), i; + + /* FIXME: this is inefficient */ + for (i = 0; i < len; i++) + { + if (*(struct symt**)vector_at(&module->vsymt, i) == sym) + return i + 1; + } + /* not found */ + c = vector_add(&module->vsymt, &module->pool); + if (c) *c = sym; + return len + 1; +#else + return (DWORD)sym; +#endif } +struct symt* symt_index2ptr(struct module* module, DWORD id) +{ +#ifdef _WIN64 + if (!id-- || id >= vector_length(&module->vsymt)) return NULL; + return *(struct symt**)vector_at(&module->vsymt, id); +#else + return (struct symt*)id; +#endif +} + +static BOOL symt_grow_sorttab(struct module* module, unsigned sz) +{ + struct symt_ht** new; + unsigned int size; + + if (sz <= module->sorttab_size) return TRUE; + if (module->addr_sorttab) + { + size = module->sorttab_size * 2; + new = HeapReAlloc(GetProcessHeap(), 0, module->addr_sorttab, + size * sizeof(struct symt_ht*)); + } + else + { + size = 64; + new = HeapAlloc(GetProcessHeap(), 0, size * sizeof(struct symt_ht*)); + } + if (!new) return FALSE; + module->sorttab_size = size; + module->addr_sorttab = new; + return TRUE; +} + +static void symt_add_module_ht(struct module* module, struct symt_ht* ht) +{ + ULONG64 addr; + + hash_table_add(&module->ht_symbols, &ht->hash_elt); + /* Don't store in sorttab a symbol without address, they are of + * no use here (e.g. constant values) + */ + if (symt_get_info(module, &ht->symt, TI_GET_ADDRESS, &addr) && + symt_grow_sorttab(module, module->num_symbols + 1)) + { + module->addr_sorttab[module->num_symbols++] = ht; + module->sortlist_valid = FALSE; + } +} + +#ifdef HAVE_REGEX_H + /* transforms a dbghelp's regular expression into a POSIX one * Here are the valid dbghelp reg ex characters: * * 0 or more characters @@ -84,47 +152,138 @@ static inline void re_append(char** mask, unsigned* len, char ch) */ static void compile_regex(const char* str, int numchar, regex_t* re, BOOL _case) { - char* mask = HeapAlloc(GetProcessHeap(), 0, 1); - unsigned len = 1; + char *mask, *p; BOOL in_escape = FALSE; unsigned flags = REG_NOSUB; - re_append(&mask, &len, '^'); + if (numchar == -1) numchar = strlen( str ); + + p = mask = HeapAlloc( GetProcessHeap(), 0, 2 * numchar + 3 ); + *p++ = '^'; while (*str && numchar--) { /* FIXME: this shouldn't be valid on '-' */ if (in_escape) { - re_append(&mask, &len, '\\'); - re_append(&mask, &len, *str); + *p++ = '\\'; + *p++ = *str; in_escape = FALSE; } else switch (*str) { case '\\': in_escape = TRUE; break; - case '*': re_append(&mask, &len, '.'); re_append(&mask, &len, '*'); break; - case '?': re_append(&mask, &len, '.'); break; - case '#': re_append(&mask, &len, '*'); break; + case '*': *p++ = '.'; *p++ = '*'; break; + case '?': *p++ = '.'; break; + case '#': *p++ = '*'; break; /* escape some valid characters in dbghelp reg exp:s */ - case '$': re_append(&mask, &len, '\\'); re_append(&mask, &len, '$'); break; + case '$': *p++ = '\\'; *p++ = '$'; break; /* +, [, ], - are the same in dbghelp & POSIX, use them as any other char */ - default: re_append(&mask, &len, *str); break; + default: *p++ = *str; break; } str++; } if (in_escape) { - re_append(&mask, &len, '\\'); - re_append(&mask, &len, '\\'); + *p++ = '\\'; + *p++ = '\\'; } - re_append(&mask, &len, '$'); - mask[len - 1] = '\0'; + *p++ = '$'; + *p = 0; if (_case) flags |= REG_ICASE; if (regcomp(re, mask, flags)) FIXME("Couldn't compile %s\n", mask); HeapFree(GetProcessHeap(), 0, mask); } +static BOOL compile_file_regex(regex_t* re, const char* srcfile) +{ + char *mask, *p; + BOOL ret; + + if (!srcfile || !*srcfile) return regcomp(re, ".*", REG_NOSUB); + + p = mask = HeapAlloc(GetProcessHeap(), 0, 5 * strlen(srcfile) + 4); + *p++ = '^'; + while (*srcfile) + { + switch (*srcfile) + { + case '\\': + case '/': + *p++ = '['; + *p++ = '\\'; + *p++ = '\\'; + *p++ = '/'; + *p++ = ']'; + break; + case '.': + *p++ = '\\'; + *p++ = '.'; + break; + default: + *p++ = *srcfile; + break; + } + srcfile++; + } + *p++ = '$'; + *p = 0; + ret = !regcomp(re, mask, REG_NOSUB); + HeapFree(GetProcessHeap(), 0, mask); + if (!ret) + { + FIXME("Couldn't compile %s\n", mask); + SetLastError(ERROR_INVALID_PARAMETER); + } + return ret; +} + +static int match_regexp( const regex_t *re, const char *str ) +{ + return !regexec( re, str, 0, NULL, 0 ); +} + +#else /* HAVE_REGEX_H */ + +/* if we don't have regexp support, fall back to a simple string comparison */ + +typedef struct +{ + char *str; + BOOL icase; +} regex_t; + +static void compile_regex(const char* str, int numchar, regex_t* re, BOOL _case) +{ + if (numchar == -1) numchar = strlen( str ); + + re->str = HeapAlloc( GetProcessHeap(), 0, numchar + 1 ); + memcpy( re->str, str, numchar ); + re->str[numchar] = 0; + re->icase = _case; +} + +static BOOL compile_file_regex(regex_t* re, const char* srcfile) +{ + if (!srcfile || !*srcfile) re->str = NULL; + else compile_regex( srcfile, -1, re, FALSE ); + return TRUE; +} + +static int match_regexp( const regex_t *re, const char *str ) +{ + if (!re->str) return 1; + if (re->icase) return !lstrcmpiA( re->str, str ); + return !strcmp( re->str, str ); +} + +static void regfree( regex_t *re ) +{ + HeapFree( GetProcessHeap(), 0, re->str ); +} + +#endif /* HAVE_REGEX_H */ + struct symt_compiland* symt_new_compiland(struct module* module, unsigned long address, unsigned src_idx) { @@ -145,8 +304,7 @@ struct symt_compiland* symt_new_compiland(struct module* module, struct symt_public* symt_new_public(struct module* module, struct symt_compiland* compiland, const char* name, - unsigned long address, unsigned size, - BOOL in_code, BOOL is_func) + unsigned long address, unsigned size) { struct symt_public* sym; struct symt** p; @@ -160,13 +318,10 @@ struct symt_public* symt_new_public(struct module* module, { sym->symt.tag = SymTagPublicSymbol; sym->hash_elt.name = pool_strdup(&module->pool, name); - hash_table_add(&module->ht_symbols, &sym->hash_elt); - module->sortlist_valid = FALSE; sym->container = compiland ? &compiland->symt : NULL; sym->address = address; sym->size = size; - sym->in_code = in_code; - sym->is_function = is_func; + symt_add_module_ht(module, (struct symt_ht*)sym); if (compiland) { p = vector_add(&compiland->vchildren, &module->pool); @@ -192,19 +347,18 @@ struct symt_data* symt_new_global_variable(struct module* module, { sym->symt.tag = SymTagData; sym->hash_elt.name = pool_strdup(&module->pool, name); - hash_table_add(&module->ht_symbols, &sym->hash_elt); - module->sortlist_valid = FALSE; sym->kind = is_static ? DataIsFileStatic : DataIsGlobal; sym->container = compiland ? &compiland->symt : NULL; sym->type = type; sym->u.var.offset = addr; - if (type && size && symt_get_info(type, TI_GET_LENGTH, &tsz)) + if (type && size && symt_get_info(module, type, TI_GET_LENGTH, &tsz)) { if (tsz != size) FIXME("Size mismatch for %s.%s between type (%s) and src (%lu)\n", debugstr_w(module->module.ModuleName), name, wine_dbgstr_longlong(tsz), size); } + symt_add_module_ht(module, (struct symt_ht*)sym); if (compiland) { p = vector_add(&compiland->vchildren, &module->pool); @@ -231,14 +385,13 @@ struct symt_function* symt_new_function(struct module* module, { sym->symt.tag = SymTagFunction; sym->hash_elt.name = pool_strdup(&module->pool, name); - hash_table_add(&module->ht_symbols, &sym->hash_elt); - module->sortlist_valid = FALSE; sym->container = &compiland->symt; sym->address = addr; sym->type = sig_type; sym->size = size; vector_init(&sym->vlines, sizeof(struct line_info), 64); vector_init(&sym->vchildren, sizeof(struct symt*), 8); + symt_add_module_ht(module, (struct symt_ht*)sym); if (compiland) { p = vector_add(&compiland->vchildren, &module->pool); @@ -363,7 +516,7 @@ struct symt_block* symt_open_func_block(struct module* module, } struct symt_block* symt_close_func_block(struct module* module, - struct symt_function* func, + const struct symt_function* func, struct symt_block* block, unsigned pc) { assert(func); @@ -395,7 +548,7 @@ struct symt_hierarchy_point* symt_add_function_point(struct module* module, return sym; } -BOOL symt_normalize_function(struct module* module, struct symt_function* func) +BOOL symt_normalize_function(struct module* module, const struct symt_function* func) { unsigned len; struct line_info* dli; @@ -432,12 +585,11 @@ struct symt_thunk* symt_new_thunk(struct module* module, { sym->symt.tag = SymTagThunk; sym->hash_elt.name = pool_strdup(&module->pool, name); - hash_table_add(&module->ht_symbols, &sym->hash_elt); - module->sortlist_valid = FALSE; sym->container = &compiland->symt; sym->address = addr; sym->size = size; sym->ordinal = ord; + symt_add_module_ht(module, (struct symt_ht*)sym); if (compiland) { struct symt** p; @@ -462,12 +614,11 @@ struct symt_data* symt_new_constant(struct module* module, { sym->symt.tag = SymTagData; sym->hash_elt.name = pool_strdup(&module->pool, name); - hash_table_add(&module->ht_symbols, &sym->hash_elt); - module->sortlist_valid = FALSE; sym->kind = DataIsConstant; sym->container = compiland ? &compiland->symt : NULL; sym->type = type; sym->u.value = *v; + symt_add_module_ht(module, (struct symt_ht*)sym); if (compiland) { struct symt** p; @@ -491,11 +642,10 @@ struct symt_hierarchy_point* symt_new_label(struct module* module, { sym->symt.tag = SymTagLabel; sym->hash_elt.name = pool_strdup(&module->pool, name); - hash_table_add(&module->ht_symbols, &sym->hash_elt); - module->sortlist_valid = FALSE; sym->loc.kind = loc_absolute; sym->loc.offset = address; sym->parent = compiland ? &compiland->symt : NULL; + symt_add_module_ht(module, (struct symt_ht*)sym); if (compiland) { struct symt** p; @@ -507,20 +657,21 @@ struct symt_hierarchy_point* symt_new_label(struct module* module, } /* expect sym_info->MaxNameLen to be set before being called */ -static void symt_fill_sym_info(const struct module_pair* pair, +static void symt_fill_sym_info(struct module_pair* pair, const struct symt_function* func, const struct symt* sym, SYMBOL_INFO* sym_info) { const char* name; DWORD64 size; - if (!symt_get_info(sym, TI_GET_TYPE, &sym_info->TypeIndex)) + if (!symt_get_info(pair->effective, sym, TI_GET_TYPE, &sym_info->TypeIndex)) sym_info->TypeIndex = 0; - sym_info->info = (DWORD)sym; + sym_info->info = symt_ptr2index(pair->effective, sym); sym_info->Reserved[0] = sym_info->Reserved[1] = 0; - if (!symt_get_info(sym, TI_GET_LENGTH, &size) && + if (!symt_get_info(pair->effective, sym, TI_GET_LENGTH, &size) && (!sym_info->TypeIndex || - !symt_get_info((struct symt*)sym_info->TypeIndex, TI_GET_LENGTH, &size))) + !symt_get_info(pair->effective, symt_index2ptr(pair->effective, sym_info->TypeIndex), + TI_GET_LENGTH, &size))) size = 0; sym_info->Size = (DWORD)size; sym_info->ModBase = pair->requested->module.BaseOfImage; @@ -569,7 +720,7 @@ static void symt_fill_sym_info(const struct module_pair* pair, break; case DataIsGlobal: case DataIsFileStatic: - symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address); + symt_get_info(pair->effective, sym, TI_GET_ADDRESS, &sym_info->Address); sym_info->Register = 0; break; case DataIsConstant: @@ -582,7 +733,8 @@ static void symt_fill_sym_info(const struct module_pair* pair, case VT_UI4: sym_info->Value = (ULONG)data->u.value.n1.n2.n3.ulVal; break; case VT_UI2: sym_info->Value = (ULONG)data->u.value.n1.n2.n3.uiVal; break; case VT_UI1: sym_info->Value = (ULONG)data->u.value.n1.n2.n3.bVal; break; - case VT_I1 | VT_BYREF: sym_info->Value = (ULONG)data->u.value.n1.n2.n3.byref; break; + case VT_I1 | VT_BYREF: sym_info->Value = (ULONG64)(DWORD_PTR)data->u.value.n1.n2.n3.byref; break; + case VT_EMPTY: sym_info->Value = 0; break; default: FIXME("Unsupported variant type (%u)\n", data->u.value.n1.n2.vt); sym_info->Value = 0; @@ -596,18 +748,18 @@ static void symt_fill_sym_info(const struct module_pair* pair, break; case SymTagPublicSymbol: sym_info->Flags |= SYMFLAG_EXPORT; - symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address); + symt_get_info(pair->effective, sym, TI_GET_ADDRESS, &sym_info->Address); break; case SymTagFunction: sym_info->Flags |= SYMFLAG_FUNCTION; - symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address); + symt_get_info(pair->effective, sym, TI_GET_ADDRESS, &sym_info->Address); break; case SymTagThunk: sym_info->Flags |= SYMFLAG_THUNK; - symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address); + symt_get_info(pair->effective, sym, TI_GET_ADDRESS, &sym_info->Address); break; default: - symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address); + symt_get_info(pair->effective, sym, TI_GET_ADDRESS, &sym_info->Address); sym_info->Register = 0; break; } @@ -641,7 +793,7 @@ struct sym_enum char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; }; -static BOOL send_symbol(const struct sym_enum* se, const struct module_pair* pair, +static BOOL send_symbol(const struct sym_enum* se, struct module_pair* pair, const struct symt_function* func, const struct symt* sym) { symt_fill_sym_info(pair, func, sym, se->sym_info); @@ -662,8 +814,7 @@ static BOOL symt_enum_module(struct module_pair* pair, const regex_t* regex, while ((ptr = hash_table_iter_up(&hti))) { sym = GET_ENTRY(ptr, struct symt_ht, hash_elt); - if (sym->hash_elt.name && - regexec(regex, sym->hash_elt.name, 0, NULL, 0) == 0) + if (sym->hash_elt.name && match_regexp(regex, sym->hash_elt.name)) { se->sym_info->SizeOfStruct = sizeof(SYMBOL_INFO); se->sym_info->MaxNameLen = sizeof(se->buffer) - sizeof(SYMBOL_INFO); @@ -673,6 +824,26 @@ static BOOL symt_enum_module(struct module_pair* pair, const regex_t* regex, return FALSE; } +static inline unsigned where_to_insert(struct module* module, unsigned high, const struct symt_ht* elt) +{ + unsigned low = 0, mid = high / 2; + ULONG64 addr; + + if (!high) return 0; + symt_get_info(module, &elt->symt, TI_GET_ADDRESS, &addr); + do + { + switch (cmp_sorttab_addr(module, mid, addr)) + { + case 0: return mid; + case -1: low = mid + 1; break; + case 1: high = mid; break; + } + mid = low + (high - low) / 2; + } while (low < high); + return mid; +} + /*********************************************************************** * resort_symbols * @@ -680,55 +851,53 @@ static BOOL symt_enum_module(struct module_pair* pair, const regex_t* regex, */ static BOOL resort_symbols(struct module* module) { - void* ptr; - struct symt_ht* sym; - struct hash_table_iter hti; - ULONG64 addr; - - if (!(module->module.NumSyms = module->ht_symbols.num_elts)) + if (!(module->module.NumSyms = module->num_symbols)) return FALSE; - - if (module->addr_sorttab) - module->addr_sorttab = HeapReAlloc(GetProcessHeap(), 0, - module->addr_sorttab, - module->module.NumSyms * sizeof(struct symt_ht*)); - else - module->addr_sorttab = HeapAlloc(GetProcessHeap(), 0, - module->module.NumSyms * sizeof(struct symt_ht*)); - if (!module->addr_sorttab) return FALSE; - module->num_sorttab = 0; - hash_table_iter_init(&module->ht_symbols, &hti, NULL); - while ((ptr = hash_table_iter_up(&hti))) + /* FIXME: what's the optimal value here ??? */ + if (module->num_sorttab && module->num_symbols <= module->num_sorttab + 30) { - sym = GET_ENTRY(ptr, struct symt_ht, hash_elt); - assert(sym); - /* Don't store in sorttab symbol without address, they are of - * no use here (e.g. constant values) - * As the number of those symbols is very couple (a couple per module) - * we don't bother for the unused spots at the end of addr_sorttab - */ - if (symt_get_info(&sym->symt, TI_GET_ADDRESS, &addr)) - module->addr_sorttab[module->num_sorttab++] = sym; + int i, delta, ins_idx = module->num_sorttab, prev_ins_idx; + struct symt_ht* tmp[30]; + + delta = module->num_symbols - module->num_sorttab; + memcpy(tmp, &module->addr_sorttab[module->num_sorttab], delta * sizeof(struct symt_ht*)); + symt_cmp_addr_module = module; + qsort(tmp, delta, sizeof(struct symt_ht*), symt_cmp_addr); + + for (i = delta - 1; i >= 0; i--) + { + prev_ins_idx = ins_idx; + ins_idx = where_to_insert(module, prev_ins_idx = ins_idx, tmp[i]); + memmove(&module->addr_sorttab[ins_idx + i + 1], + &module->addr_sorttab[ins_idx], + (prev_ins_idx - ins_idx) * sizeof(struct symt_ht*)); + module->addr_sorttab[ins_idx + i] = tmp[i]; + } } - qsort(module->addr_sorttab, module->num_sorttab, sizeof(struct symt_ht*), symt_cmp_addr); + else + { + symt_cmp_addr_module = module; + qsort(module->addr_sorttab, module->num_symbols, sizeof(struct symt_ht*), symt_cmp_addr); + } + module->num_sorttab = module->num_symbols; return module->sortlist_valid = TRUE; } -static void symt_get_length(struct symt* symt, ULONG64* size) +static void symt_get_length(struct module* module, const struct symt* symt, ULONG64* size) { DWORD type_index; - if (symt_get_info(symt, TI_GET_LENGTH, size) && *size) + if (symt_get_info(module, symt, TI_GET_LENGTH, size) && *size) return; - if (symt_get_info(symt, TI_GET_TYPE, &type_index) && - symt_get_info((struct symt*)type_index, TI_GET_LENGTH, size)) return; + if (symt_get_info(module, symt, TI_GET_TYPE, &type_index) && + symt_get_info(module, symt_index2ptr(module, type_index), TI_GET_LENGTH, size)) return; *size = 0x1000; /* arbitrary value */ } /* assume addr is in module */ -struct symt_ht* symt_find_nearest(struct module* module, DWORD addr) +struct symt_ht* symt_find_nearest(struct module* module, DWORD_PTR addr) { int mid, high, low; ULONG64 ref_addr, ref_size; @@ -744,12 +913,12 @@ struct symt_ht* symt_find_nearest(struct module* module, DWORD addr) low = 0; high = module->num_sorttab; - symt_get_info(&module->addr_sorttab[0]->symt, TI_GET_ADDRESS, &ref_addr); + symt_get_info(module, &module->addr_sorttab[0]->symt, TI_GET_ADDRESS, &ref_addr); if (addr < ref_addr) return NULL; if (high) { - symt_get_info(&module->addr_sorttab[high - 1]->symt, TI_GET_ADDRESS, &ref_addr); - symt_get_length(&module->addr_sorttab[high - 1]->symt, &ref_size); + symt_get_info(module, &module->addr_sorttab[high - 1]->symt, TI_GET_ADDRESS, &ref_addr); + symt_get_length(module, &module->addr_sorttab[high - 1]->symt, &ref_size); if (addr >= ref_addr + ref_size) return NULL; } @@ -770,7 +939,7 @@ struct symt_ht* symt_find_nearest(struct module* module, DWORD addr) */ if (module->addr_sorttab[low]->symt.tag == SymTagPublicSymbol) { - symt_get_info(&module->addr_sorttab[low]->symt, TI_GET_ADDRESS, &ref_addr); + symt_get_info(module, &module->addr_sorttab[low]->symt, TI_GET_ADDRESS, &ref_addr); if (low > 0 && module->addr_sorttab[low - 1]->symt.tag != SymTagPublicSymbol && !cmp_sorttab_addr(module, low - 1, ref_addr)) @@ -781,9 +950,9 @@ struct symt_ht* symt_find_nearest(struct module* module, DWORD addr) low++; } /* finally check that we fit into the found symbol */ - symt_get_info(&module->addr_sorttab[low]->symt, TI_GET_ADDRESS, &ref_addr); + symt_get_info(module, &module->addr_sorttab[low]->symt, TI_GET_ADDRESS, &ref_addr); if (addr < ref_addr) return NULL; - symt_get_length(&module->addr_sorttab[low]->symt, &ref_size); + symt_get_length(module, &module->addr_sorttab[low]->symt, &ref_size); if (addr >= ref_addr + ref_size) return NULL; return module->addr_sorttab[low]; @@ -812,7 +981,7 @@ static BOOL symt_enum_locals_helper(struct module_pair* pair, } break; case SymTagData: - if (regexec(preg, symt_get_name(lsym), 0, NULL, 0) == 0) + if (match_regexp(preg, symt_get_name(lsym))) { if (send_symbol(se, pair, func, lsym)) return FALSE; } @@ -900,6 +1069,7 @@ static BOOL sym_enum(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Mask, regex_t mod_regex, sym_regex; pair.pcs = process_find_by_handle(hProcess); + if (!pair.pcs) return FALSE; if (BaseOfDll == 0) { /* do local variables ? */ @@ -916,22 +1086,22 @@ static BOOL sym_enum(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Mask, { if (pair.requested->type == DMT_PE && module_get_debug(&pair)) { - if (regexec(&mod_regex, pair.requested->module_name, 0, NULL, 0) == 0 && + if (match_regexp(&mod_regex, pair.requested->module_name) && symt_enum_module(&pair, &sym_regex, se)) break; } } /* not found in PE modules, retry on the ELF ones */ - if (!pair.requested && (dbghelp_options & SYMOPT_WINE_WITH_ELF_MODULES)) + if (!pair.requested && (dbghelp_options & SYMOPT_WINE_WITH_NATIVE_MODULES)) { for (pair.requested = pair.pcs->lmodules; pair.requested; pair.requested = pair.requested->next) { - if (pair.requested->type == DMT_ELF && + if ((pair.requested->type == DMT_ELF || pair.requested->type == DMT_MACHO) && !module_get_containee(pair.pcs, pair.requested) && module_get_debug(&pair)) { - if (regexec(&mod_regex, pair.requested->module_name, 0, NULL, 0) == 0 && + if (match_regexp(&mod_regex, pair.requested->module_name) && symt_enum_module(&pair, &sym_regex, se)) break; } @@ -1046,7 +1216,7 @@ struct sym_enumerate static BOOL CALLBACK sym_enumerate_cb(PSYMBOL_INFO syminfo, ULONG size, void* ctx) { - struct sym_enumerate* se = (struct sym_enumerate*)ctx; + struct sym_enumerate* se = ctx; return (se->cb)(syminfo->Name, syminfo->Address, syminfo->Size, se->ctx); } @@ -1073,7 +1243,7 @@ struct sym_enumerate64 static BOOL CALLBACK sym_enumerate_cb64(PSYMBOL_INFO syminfo, ULONG size, void* ctx) { - struct sym_enumerate64* se = (struct sym_enumerate64*)ctx; + struct sym_enumerate64* se = ctx; return (se->cb)(syminfo->Name, syminfo->Address, syminfo->Size, se->ctx); } @@ -1250,11 +1420,12 @@ BOOL WINAPI SymFromName(HANDLE hProcess, PCSTR Name, PSYMBOL_INFO Symbol) } /* not found in PE modules, retry on the ELF ones */ - if (dbghelp_options & SYMOPT_WINE_WITH_ELF_MODULES) + if (dbghelp_options & SYMOPT_WINE_WITH_NATIVE_MODULES) { for (module = pcs->lmodules; module; module = module->next) { - if (module->type == DMT_ELF && !module_get_containee(pcs, module) && + if ((module->type == DMT_ELF || module->type == DMT_MACHO) && + !module_get_containee(pcs, module) && find_name(pcs, module, Name, Symbol)) return TRUE; } @@ -1262,6 +1433,28 @@ BOOL WINAPI SymFromName(HANDLE hProcess, PCSTR Name, PSYMBOL_INFO Symbol) return FALSE; } +/*********************************************************************** + * SymGetSymFromName64 (DBGHELP.@) + */ +BOOL WINAPI SymGetSymFromName64(HANDLE hProcess, PCSTR Name, PIMAGEHLP_SYMBOL64 Symbol) +{ + char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; + SYMBOL_INFO*si = (SYMBOL_INFO*)buffer; + size_t len; + + if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE; + si->SizeOfStruct = sizeof(*si); + si->MaxNameLen = MAX_SYM_NAME; + if (!SymFromName(hProcess, Name, si)) return FALSE; + + Symbol->Address = si->Address; + Symbol->Size = si->Size; + Symbol->Flags = si->Flags; + len = min(Symbol->MaxNameLength, si->MaxNameLen); + lstrcpynA(Symbol->Name, si->Name, len); + return TRUE; +} + /*********************************************************************** * SymGetSymFromName (DBGHELP.@) */ @@ -1290,7 +1483,7 @@ BOOL WINAPI SymGetSymFromName(HANDLE hProcess, PCSTR Name, PIMAGEHLP_SYMBOL Symb * fills information about a file */ BOOL symt_fill_func_line_info(const struct module* module, const struct symt_function* func, - DWORD addr, IMAGEHLP_LINE* line) + DWORD64 addr, IMAGEHLP_LINE64* line) { struct line_info* dli = NULL; BOOL found = FALSE; @@ -1320,9 +1513,9 @@ BOOL symt_fill_func_line_info(const struct module* module, const struct symt_fun } /*********************************************************************** - * SymGetSymNext (DBGHELP.@) + * SymGetSymNext64 (DBGHELP.@) */ -BOOL WINAPI SymGetSymNext(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol) +BOOL WINAPI SymGetSymNext64(HANDLE hProcess, PIMAGEHLP_SYMBOL64 Symbol) { /* algo: * get module from Symbol.Address @@ -1336,41 +1529,33 @@ BOOL WINAPI SymGetSymNext(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol) } /*********************************************************************** - * SymGetSymPrev (DBGHELP.@) + * SymGetSymNext (DBGHELP.@) */ - -BOOL WINAPI SymGetSymPrev(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol) +BOOL WINAPI SymGetSymNext(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol) { FIXME("(%p, %p): stub\n", hProcess, Symbol); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } -/****************************************************************** - * SymGetLineFromAddr (DBGHELP.@) - * +/*********************************************************************** + * SymGetSymPrev64 (DBGHELP.@) */ -BOOL WINAPI SymGetLineFromAddr(HANDLE hProcess, DWORD dwAddr, - PDWORD pdwDisplacement, PIMAGEHLP_LINE Line) +BOOL WINAPI SymGetSymPrev64(HANDLE hProcess, PIMAGEHLP_SYMBOL64 Symbol) { - struct module_pair pair; - struct symt_ht* symt; + FIXME("(%p, %p): stub\n", hProcess, Symbol); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} - TRACE("%p %08x %p %p\n", hProcess, dwAddr, pdwDisplacement, Line); - - if (Line->SizeOfStruct < sizeof(*Line)) return FALSE; - - pair.pcs = process_find_by_handle(hProcess); - if (!pair.pcs) return FALSE; - pair.requested = module_find_by_addr(pair.pcs, dwAddr, DMT_UNKNOWN); - if (!module_get_debug(&pair)) return FALSE; - if ((symt = symt_find_nearest(pair.effective, dwAddr)) == NULL) return FALSE; - - if (symt->symt.tag != SymTagFunction) return FALSE; - if (!symt_fill_func_line_info(pair.effective, (struct symt_function*)symt, - dwAddr, Line)) return FALSE; - *pdwDisplacement = dwAddr - Line->Address; - return TRUE; +/*********************************************************************** + * SymGetSymPrev (DBGHELP.@) + */ +BOOL WINAPI SymGetSymPrev(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol) +{ + FIXME("(%p, %p): stub\n", hProcess, Symbol); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; } /****************************************************************** @@ -1390,16 +1575,16 @@ static void copy_line_64_from_32(IMAGEHLP_LINE64* l64, const IMAGEHLP_LINE* l32) * copy_line_W64_from_32 (internal) * */ -static void copy_line_W64_from_32(struct process* pcs, IMAGEHLP_LINEW64* l64, const IMAGEHLP_LINE* l32) +static void copy_line_W64_from_64(struct process* pcs, IMAGEHLP_LINEW64* l64w, const IMAGEHLP_LINE64* l64) { unsigned len; - l64->Key = l32->Key; - l64->LineNumber = l32->LineNumber; - len = MultiByteToWideChar(CP_ACP, 0, l32->FileName, -1, NULL, 0); - if ((l64->FileName = fetch_buffer(pcs, len * sizeof(WCHAR)))) - MultiByteToWideChar(CP_ACP, 0, l32->FileName, -1, l64->FileName, len); - l64->Address = l32->Address; + l64w->Key = l64->Key; + l64w->LineNumber = l64->LineNumber; + len = MultiByteToWideChar(CP_ACP, 0, l64->FileName, -1, NULL, 0); + if ((l64w->FileName = fetch_buffer(pcs, len * sizeof(WCHAR)))) + MultiByteToWideChar(CP_ACP, 0, l64->FileName, -1, l64w->FileName, len); + l64w->Address = l64->Address; } /****************************************************************** @@ -1415,6 +1600,22 @@ static void copy_line_32_from_64(IMAGEHLP_LINE* l32, const IMAGEHLP_LINE64* l64) l32->Address = l64->Address; } +/****************************************************************** + * SymGetLineFromAddr (DBGHELP.@) + * + */ +BOOL WINAPI SymGetLineFromAddr(HANDLE hProcess, DWORD dwAddr, + PDWORD pdwDisplacement, PIMAGEHLP_LINE Line) +{ + IMAGEHLP_LINE64 il64; + + il64.SizeOfStruct = sizeof(il64); + if (!SymGetLineFromAddr64(hProcess, dwAddr, pdwDisplacement, &il64)) + return FALSE; + copy_line_32_from_64(Line, &il64); + return TRUE; +} + /****************************************************************** * SymGetLineFromAddr64 (DBGHELP.@) * @@ -1422,14 +1623,23 @@ static void copy_line_32_from_64(IMAGEHLP_LINE* l32, const IMAGEHLP_LINE64* l64) BOOL WINAPI SymGetLineFromAddr64(HANDLE hProcess, DWORD64 dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line) { - IMAGEHLP_LINE line32; + struct module_pair pair; + struct symt_ht* symt; + + TRACE("%p %s %p %p\n", hProcess, wine_dbgstr_longlong(dwAddr), pdwDisplacement, Line); if (Line->SizeOfStruct < sizeof(*Line)) return FALSE; - if (!validate_addr64(dwAddr)) return FALSE; - line32.SizeOfStruct = sizeof(line32); - if (!SymGetLineFromAddr(hProcess, (DWORD)dwAddr, pdwDisplacement, &line32)) - return FALSE; - copy_line_64_from_32(Line, &line32); + + pair.pcs = process_find_by_handle(hProcess); + if (!pair.pcs) return FALSE; + pair.requested = module_find_by_addr(pair.pcs, dwAddr, DMT_UNKNOWN); + if (!module_get_debug(&pair)) return FALSE; + if ((symt = symt_find_nearest(pair.effective, dwAddr)) == NULL) return FALSE; + + if (symt->symt.tag != SymTagFunction) return FALSE; + if (!symt_fill_func_line_info(pair.effective, (struct symt_function*)symt, + dwAddr, Line)) return FALSE; + *pdwDisplacement = dwAddr - Line->Address; return TRUE; } @@ -1440,24 +1650,20 @@ BOOL WINAPI SymGetLineFromAddr64(HANDLE hProcess, DWORD64 dwAddr, BOOL WINAPI SymGetLineFromAddrW64(HANDLE hProcess, DWORD64 dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINEW64 Line) { - struct process* pcs = process_find_by_handle(hProcess); - IMAGEHLP_LINE line32; + IMAGEHLP_LINE64 il64; - if (!pcs) return FALSE; - if (Line->SizeOfStruct < sizeof(*Line)) return FALSE; - if (!validate_addr64(dwAddr)) return FALSE; - line32.SizeOfStruct = sizeof(line32); - if (!SymGetLineFromAddr(hProcess, (DWORD)dwAddr, pdwDisplacement, &line32)) + il64.SizeOfStruct = sizeof(il64); + if (!SymGetLineFromAddr64(hProcess, dwAddr, pdwDisplacement, &il64)) return FALSE; - copy_line_W64_from_32(pcs, Line, &line32); + copy_line_W64_from_64(process_find_by_handle(hProcess), Line, &il64); return TRUE; } /****************************************************************** - * SymGetLinePrev (DBGHELP.@) + * SymGetLinePrev64 (DBGHELP.@) * */ -BOOL WINAPI SymGetLinePrev(HANDLE hProcess, PIMAGEHLP_LINE Line) +BOOL WINAPI SymGetLinePrev64(HANDLE hProcess, PIMAGEHLP_LINE64 Line) { struct module_pair pair; struct line_info* li; @@ -1473,7 +1679,7 @@ BOOL WINAPI SymGetLinePrev(HANDLE hProcess, PIMAGEHLP_LINE Line) if (!module_get_debug(&pair)) return FALSE; if (Line->Key == 0) return FALSE; - li = (struct line_info*)Line->Key; + li = Line->Key; /* things are a bit complicated because when we encounter a DLIT_SOURCEFILE * element we have to go back until we find the prev one to get the real * source file name for the DLIT_OFFSET element just before @@ -1504,26 +1710,26 @@ BOOL WINAPI SymGetLinePrev(HANDLE hProcess, PIMAGEHLP_LINE Line) } /****************************************************************** - * SymGetLinePrev64 (DBGHELP.@) + * SymGetLinePrev (DBGHELP.@) * */ -BOOL WINAPI SymGetLinePrev64(HANDLE hProcess, PIMAGEHLP_LINE64 Line) +BOOL WINAPI SymGetLinePrev(HANDLE hProcess, PIMAGEHLP_LINE Line) { - IMAGEHLP_LINE line32; + IMAGEHLP_LINE64 line64; - line32.SizeOfStruct = sizeof(line32); - copy_line_32_from_64(&line32, Line); - if (!SymGetLinePrev(hProcess, &line32)) return FALSE; - copy_line_64_from_32(Line, &line32); + line64.SizeOfStruct = sizeof(line64); + copy_line_64_from_32(&line64, Line); + if (!SymGetLinePrev64(hProcess, &line64)) return FALSE; + copy_line_32_from_64(Line, &line64); return TRUE; } - -BOOL symt_get_func_line_next(const struct module* module, PIMAGEHLP_LINE line) + +BOOL symt_get_func_line_next(const struct module* module, PIMAGEHLP_LINE64 line) { struct line_info* li; if (line->Key == 0) return FALSE; - li = (struct line_info*)line->Key; + li = line->Key; while (!li->is_last) { li++; @@ -1540,10 +1746,10 @@ BOOL symt_get_func_line_next(const struct module* module, PIMAGEHLP_LINE line) } /****************************************************************** - * SymGetLineNext (DBGHELP.@) + * SymGetLineNext64 (DBGHELP.@) * */ -BOOL WINAPI SymGetLineNext(HANDLE hProcess, PIMAGEHLP_LINE Line) +BOOL WINAPI SymGetLineNext64(HANDLE hProcess, PIMAGEHLP_LINE64 Line) { struct module_pair pair; @@ -1561,20 +1767,20 @@ BOOL WINAPI SymGetLineNext(HANDLE hProcess, PIMAGEHLP_LINE Line) } /****************************************************************** - * SymGetLineNext64 (DBGHELP.@) + * SymGetLineNext (DBGHELP.@) * */ -BOOL WINAPI SymGetLineNext64(HANDLE hProcess, PIMAGEHLP_LINE64 Line) +BOOL WINAPI SymGetLineNext(HANDLE hProcess, PIMAGEHLP_LINE Line) { - IMAGEHLP_LINE line32; + IMAGEHLP_LINE64 line64; - line32.SizeOfStruct = sizeof(line32); - copy_line_32_from_64(&line32, Line); - if (!SymGetLineNext(hProcess, &line32)) return FALSE; - copy_line_64_from_32(Line, &line32); + line64.SizeOfStruct = sizeof(line64); + copy_line_64_from_32(&line64, Line); + if (!SymGetLineNext64(hProcess, &line64)) return FALSE; + copy_line_32_from_64(Line, &line64); return TRUE; } - + /*********************************************************************** * SymFunctionTableAccess (DBGHELP.@) */ @@ -1598,7 +1804,15 @@ PVOID WINAPI SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase) */ BOOL WINAPI SymUnDName(PIMAGEHLP_SYMBOL sym, PSTR UnDecName, DWORD UnDecNameLength) { - TRACE("(%p %s %u)\n", sym, UnDecName, UnDecNameLength); + return UnDecorateSymbolName(sym->Name, UnDecName, UnDecNameLength, + UNDNAME_COMPLETE) != 0; +} + +/*********************************************************************** + * SymUnDName64 (DBGHELP.@) + */ +BOOL WINAPI SymUnDName64(PIMAGEHLP_SYMBOL64 sym, PSTR UnDecName, DWORD UnDecNameLength) +{ return UnDecorateSymbolName(sym->Name, UnDecName, UnDecNameLength, UNDNAME_COMPLETE) != 0; } @@ -1645,7 +1859,7 @@ BOOL WINAPI SymMatchString(PCSTR string, PCSTR re, BOOL _case) TRACE("%s %s %c\n", string, re, _case ? 'Y' : 'N'); compile_regex(re, -1, &preg, _case); - ret = regexec(&preg, string, 0, NULL, 0) == 0; + ret = match_regexp(&preg, string); regfree(&preg); return ret; } @@ -1762,3 +1976,88 @@ BOOL WINAPI SymSetScopeFromAddr(HANDLE hProcess, ULONG64 addr) if (!(pcs = process_find_by_handle(hProcess))) return FALSE; return TRUE; } + +/****************************************************************** + * SymEnumLines (DBGHELP.@) + * + */ +BOOL WINAPI SymEnumLines(HANDLE hProcess, ULONG64 base, PCSTR compiland, + PCSTR srcfile, PSYM_ENUMLINES_CALLBACK cb, PVOID user) +{ + struct module_pair pair; + struct hash_table_iter hti; + struct symt_ht* sym; + regex_t re; + struct line_info* dli; + void* ptr; + SRCCODEINFO sci; + const char* file; + + if (!cb) return FALSE; + if (!(dbghelp_options & SYMOPT_LOAD_LINES)) return TRUE; + + pair.pcs = process_find_by_handle(hProcess); + if (!pair.pcs) return FALSE; + if (compiland) FIXME("Unsupported yet (filtering on compiland %s)\n", compiland); + pair.requested = module_find_by_addr(pair.pcs, base, DMT_UNKNOWN); + if (!module_get_debug(&pair)) return FALSE; + if (!compile_file_regex(&re, srcfile)) return FALSE; + + sci.SizeOfStruct = sizeof(sci); + sci.ModBase = base; + + hash_table_iter_init(&pair.effective->ht_symbols, &hti, NULL); + while ((ptr = hash_table_iter_up(&hti))) + { + unsigned int i; + + sym = GET_ENTRY(ptr, struct symt_ht, hash_elt); + if (sym->symt.tag != SymTagFunction) continue; + + sci.FileName[0] = '\0'; + for (i=0; ivlines); i++) + { + dli = vector_at(&((struct symt_function*)sym)->vlines, i); + if (dli->is_source_file) + { + file = source_get(pair.effective, dli->u.source_file); + if (!match_regexp(&re, file)) file = ""; + strcpy(sci.FileName, file); + } + else if (sci.FileName[0]) + { + sci.Key = dli; + sci.Obj[0] = '\0'; /* FIXME */ + sci.LineNumber = dli->line_number; + sci.Address = dli->u.pc_offset; + if (!cb(&sci, user)) break; + } + } + } + regfree(&re); + return TRUE; +} + +BOOL WINAPI SymGetLineFromName(HANDLE hProcess, PCSTR ModuleName, PCSTR FileName, + DWORD dwLineNumber, PLONG plDisplacement, PIMAGEHLP_LINE Line) +{ + FIXME("(%p) (%s, %s, %d %p %p): stub\n", hProcess, ModuleName, FileName, + dwLineNumber, plDisplacement, Line); + return FALSE; +} + +BOOL WINAPI SymGetLineFromName64(HANDLE hProcess, PCSTR ModuleName, PCSTR FileName, + DWORD dwLineNumber, PLONG lpDisplacement, PIMAGEHLP_LINE64 Line) +{ + FIXME("(%p) (%s, %s, %d %p %p): stub\n", hProcess, ModuleName, FileName, + dwLineNumber, lpDisplacement, Line); + return FALSE; +} + +BOOL WINAPI SymGetLineFromNameW64(HANDLE hProcess, PCWSTR ModuleName, PCWSTR FileName, + DWORD dwLineNumber, PLONG plDisplacement, PIMAGEHLP_LINEW64 Line) +{ + FIXME("(%p) (%s, %s, %d %p %p): stub\n", hProcess, debugstr_w(ModuleName), debugstr_w(FileName), + dwLineNumber, plDisplacement, Line); + return FALSE; +} diff --git a/reactos/dll/win32/dbghelp/type.c b/reactos/dll/win32/dbghelp/type.c index 947eb49095e..2ef4bb45095 100644 --- a/reactos/dll/win32/dbghelp/type.c +++ b/reactos/dll/win32/dbghelp/type.c @@ -304,6 +304,21 @@ struct symt_array* symt_new_array(struct module* module, int min, int max, return sym; } +static inline DWORD symt_array_count(struct module* module, const struct symt_array* array) +{ + if (array->end < 0) + { + DWORD64 elem_size; + /* One could want to also set the array->end field in array, but we won't do it + * as long as all the get_type() helpers use const objects + */ + if (symt_get_info(module, array->base_type, TI_GET_LENGTH, &elem_size) && elem_size) + return -array->end / (DWORD)elem_size; + return 0; + } + return array->end - array->start + 1; +} + struct symt_function_signature* symt_new_function_signature(struct module* module, struct symt* ret_type, enum CV_call_e call_conv) @@ -400,9 +415,9 @@ BOOL WINAPI SymEnumTypes(HANDLE hProcess, ULONG64 BaseOfDll, for (i=0; ivtypes); i++) { type = *(struct symt**)vector_at(&pair.effective->vtypes, i); - sym_info->TypeIndex = (DWORD)type; + sym_info->TypeIndex = symt_ptr2index(pair.effective, type); sym_info->info = 0; /* FIXME */ - symt_get_info(type, TI_GET_LENGTH, &size); + symt_get_info(pair.effective, type, TI_GET_LENGTH, &size); sym_info->Size = size; sym_info->ModBase = pair.requested->module.BaseOfImage; sym_info->Flags = 0; /* FIXME */ @@ -462,8 +477,8 @@ BOOL WINAPI SymEnumTypesW(HANDLE hProcess, ULONG64 BaseOfDll, * * Retrieves information about a symt (either symbol or type) */ -BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, - void* pInfo) +BOOL symt_get_info(struct module* module, const struct symt* type, + IMAGEHLP_SYMBOL_TYPE_INFO req, void* pInfo) { unsigned len; @@ -495,7 +510,7 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, for (i = 0; i < tifp->Count; i++) { if (!(pt = vector_at(v, tifp->Start + i))) return FALSE; - tifp->ChildId[i] = (DWORD)*pt; + tifp->ChildId[i] = symt_ptr2index(module, *pt); } } break; @@ -522,7 +537,7 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, case SymTagFuncDebugStart: case SymTagFuncDebugEnd: case SymTagLabel: - if (!symt_get_info(((const struct symt_hierarchy_point*)type)->parent, + if (!symt_get_info(module, ((const struct symt_hierarchy_point*)type)->parent, req, pInfo)) return FALSE; X(ULONG64) += ((const struct symt_hierarchy_point*)type)->loc.offset; @@ -597,8 +612,7 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, switch (type->tag) { case SymTagArrayType: - X(DWORD) = ((const struct symt_array*)type)->end - - ((const struct symt_array*)type)->start + 1; + X(DWORD) = symt_array_count(module, (const struct symt_array*)type); break; case SymTagFunctionType: /* this seems to be wrong for (future) C++ methods, where 'this' parameter @@ -639,18 +653,17 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, return FALSE; X(DWORD64) = ((const struct symt_data*)type)->u.member.length; break; - case SymTagArrayType: - if (!symt_get_info(((const struct symt_array*)type)->base_type, + case SymTagArrayType: + if (!symt_get_info(module, ((const struct symt_array*)type)->base_type, TI_GET_LENGTH, pInfo)) return FALSE; - X(DWORD64) *= ((const struct symt_array*)type)->end - - ((const struct symt_array*)type)->start + 1; + X(DWORD64) *= symt_array_count(module, (const struct symt_array*)type); break; case SymTagPublicSymbol: X(DWORD64) = ((const struct symt_public*)type)->size; break; case SymTagTypedef: - return symt_get_info(((const struct symt_typedef*)type)->type, TI_GET_LENGTH, pInfo); + return symt_get_info(module, ((const struct symt_typedef*)type)->type, TI_GET_LENGTH, pInfo); case SymTagThunk: X(DWORD64) = ((const struct symt_thunk*)type)->size; break; @@ -670,19 +683,19 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, switch (type->tag) { case SymTagBlock: - X(DWORD) = (DWORD)((const struct symt_block*)type)->container; + X(DWORD) = symt_ptr2index(module, ((const struct symt_block*)type)->container); break; case SymTagData: - X(DWORD) = (DWORD)((const struct symt_data*)type)->container; + X(DWORD) = symt_ptr2index(module, ((const struct symt_data*)type)->container); break; case SymTagFunction: - X(DWORD) = (DWORD)((const struct symt_function*)type)->container; + X(DWORD) = symt_ptr2index(module, ((const struct symt_function*)type)->container); break; case SymTagThunk: - X(DWORD) = (DWORD)((const struct symt_thunk*)type)->container; + X(DWORD) = symt_ptr2index(module, ((const struct symt_thunk*)type)->container); break; case SymTagFunctionArgType: - X(DWORD) = (DWORD)((const struct symt_function_arg_type*)type)->container; + X(DWORD) = symt_ptr2index(module, ((const struct symt_function_arg_type*)type)->container); break; default: FIXME("Unsupported sym-tag %s for get-lexical-parent\n", @@ -750,29 +763,29 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, { /* hierarchical => hierarchical */ case SymTagArrayType: - X(DWORD) = (DWORD)((const struct symt_array*)type)->base_type; + X(DWORD) = symt_ptr2index(module, ((const struct symt_array*)type)->base_type); break; case SymTagPointerType: - X(DWORD) = (DWORD)((const struct symt_pointer*)type)->pointsto; + X(DWORD) = symt_ptr2index(module, ((const struct symt_pointer*)type)->pointsto); break; case SymTagFunctionType: - X(DWORD) = (DWORD)((const struct symt_function_signature*)type)->rettype; + X(DWORD) = symt_ptr2index(module, ((const struct symt_function_signature*)type)->rettype); break; case SymTagTypedef: - X(DWORD) = (DWORD)((const struct symt_typedef*)type)->type; + X(DWORD) = symt_ptr2index(module, ((const struct symt_typedef*)type)->type); break; /* lexical => hierarchical */ case SymTagData: - X(DWORD) = (DWORD)((const struct symt_data*)type)->type; + X(DWORD) = symt_ptr2index(module, ((const struct symt_data*)type)->type); break; case SymTagFunction: - X(DWORD) = (DWORD)((const struct symt_function*)type)->type; + X(DWORD) = symt_ptr2index(module, ((const struct symt_function*)type)->type); break; case SymTagEnum: - X(DWORD) = (DWORD)((const struct symt_enum*)type)->base_type; + X(DWORD) = symt_ptr2index(module, ((const struct symt_enum*)type)->base_type); break; case SymTagFunctionArgType: - X(DWORD) = (DWORD)((const struct symt_function_arg_type*)type)->arg_type; + X(DWORD) = symt_ptr2index(module, ((const struct symt_function_arg_type*)type)->arg_type); break; default: FIXME("Unsupported sym-tag %s for get-type\n", @@ -806,7 +819,7 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, break; case TI_GET_ARRAYINDEXTYPEID: if (type->tag != SymTagArrayType) return FALSE; - X(DWORD) = (DWORD)((const struct symt_array*)type)->index_type; + X(DWORD) = symt_ptr2index(module, ((const struct symt_array*)type)->index_type); break; case TI_GET_CLASSPARENTID: @@ -854,7 +867,7 @@ BOOL WINAPI SymGetTypeInfo(HANDLE hProcess, DWORD64 ModBase, return FALSE; } - return symt_get_info((struct symt*)TypeId, GetType, pInfo); + return symt_get_info(pair.effective, symt_index2ptr(pair.effective, TypeId), GetType, pInfo); } /****************************************************************** @@ -865,15 +878,15 @@ BOOL WINAPI SymGetTypeFromName(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Name, PSYMBOL_INFO Symbol) { struct process* pcs = process_find_by_handle(hProcess); - struct module* module; + struct module_pair pair; struct symt* type; if (!pcs) return FALSE; - module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN); - if (!module) return FALSE; - type = symt_find_type_by_name(module, SymTagNull, Name); + pair.requested = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN); + if (!module_get_debug(&pair)) return FALSE; + type = symt_find_type_by_name(pair.effective, SymTagNull, Name); if (!type) return FALSE; - Symbol->TypeIndex = (DWORD)type; + Symbol->TypeIndex = symt_ptr2index(pair.effective, type); return TRUE; } diff --git a/reactos/dll/win32/dbghelp/version.rc b/reactos/dll/win32/dbghelp/version.rc new file mode 100644 index 00000000000..1818010180e --- /dev/null +++ b/reactos/dll/win32/dbghelp/version.rc @@ -0,0 +1,26 @@ +/* + * Copyright 2009 Louis Lenders + * + * 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 WINE_FILEDESCRIPTION_STR "Wine Image Helper" +#define WINE_FILENAME_STR "dbghelp.dll" +#define WINE_FILEVERSION 5,1,2600,3264 +#define WINE_FILEVERSION_STR "5.1.2600.3264" +#define WINE_PRODUCTVERSION 5,1,2600,3264 +#define WINE_PRODUCTVERSION_STR "5.1.2600.3264" + +#include "wine/wine_common_ver.rc" diff --git a/reactos/include/psdk/winternl.h b/reactos/include/psdk/winternl.h index f101f04bc74..1496b0f7f1f 100644 --- a/reactos/include/psdk/winternl.h +++ b/reactos/include/psdk/winternl.h @@ -871,20 +871,20 @@ typedef struct _UNWIND_HISTORY_TABLE { */ /* This is used by NtQuerySystemInformation */ -typedef struct _SYSTEM_THREAD_INFORMATION{ - FILETIME ftKernelTime; - FILETIME ftUserTime; - FILETIME ftCreateTime; - DWORD dwTickCount; - DWORD dwStartAddress; - DWORD dwOwningPID; - DWORD dwThreadID; - DWORD dwCurrentPriority; - DWORD dwBasePriority; - DWORD dwContextSwitches; - DWORD dwThreadState; - DWORD dwWaitReason; - DWORD dwUnknown; +typedef struct _SYSTEM_THREAD_INFORMATION +{ /* win32/win64 */ + LARGE_INTEGER KernelTime; /* 00/00 */ + LARGE_INTEGER UserTime; /* 08/08 */ + LARGE_INTEGER CreateTime; /* 10/10 */ + DWORD dwTickCount; /* 18/18 */ + LPVOID StartAddress; /* 1c/20 */ + CLIENT_ID ClientId; /* 20/28 */ + DWORD dwCurrentPriority; /* 28/38 */ + DWORD dwBasePriority; /* 2c/3c */ + DWORD dwContextSwitches; /* 30/40 */ + DWORD dwThreadState; /* 34/44 */ + DWORD dwWaitReason; /* 38/48 */ + DWORD dwUnknown; /* 3c/4c */ } SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION; typedef struct _IO_STATUS_BLOCK { @@ -1195,38 +1195,39 @@ typedef struct _VM_COUNTERS_ { SIZE_T QuotaNonPagedPoolUsage; SIZE_T PagefileUsage; SIZE_T PeakPagefileUsage; + SIZE_T PrivatePageCount; } VM_COUNTERS, *PVM_COUNTERS; typedef struct _SYSTEM_PROCESS_INFORMATION { -#ifdef __WINESRC__ - DWORD dwOffset; - DWORD dwThreadCount; - DWORD dwUnknown1[6]; - FILETIME ftCreationTime; - FILETIME ftUserTime; - FILETIME ftKernelTime; - UNICODE_STRING ProcessName; - DWORD dwBasePriority; - DWORD dwProcessID; - DWORD dwParentProcessID; - DWORD dwHandleCount; - DWORD dwUnknown3; - DWORD dwUnknown4; - VM_COUNTERS vmCounters; - IO_COUNTERS ioCounters; - SYSTEM_THREAD_INFORMATION ti[1]; +#ifdef __WINESRC__ /* win32/win64 */ + ULONG NextEntryOffset; /* 00/00 */ + DWORD dwThreadCount; /* 04/04 */ + DWORD dwUnknown1[6]; /* 08/08 */ + LARGE_INTEGER CreationTime; /* 20/20 */ + LARGE_INTEGER UserTime; /* 28/28 */ + LARGE_INTEGER KernelTime; /* 30/30 */ + UNICODE_STRING ProcessName; /* 38/38 */ + DWORD dwBasePriority; /* 40/48 */ + HANDLE UniqueProcessId; /* 44/50 */ + HANDLE ParentProcessId; /* 48/58 */ + ULONG HandleCount; /* 4c/60 */ + DWORD dwUnknown3; /* 50/64 */ + DWORD dwUnknown4; /* 54/68 */ + VM_COUNTERS vmCounters; /* 58/70 */ + IO_COUNTERS ioCounters; /* 88/d0 */ + SYSTEM_THREAD_INFORMATION ti[1]; /* b8/100 */ #else - ULONG NextEntryOffset; - BYTE Reserved1[52]; - PVOID Reserved2[3]; - HANDLE UniqueProcessId; - PVOID Reserved3; - ULONG HandleCount; - BYTE Reserved4[4]; - PVOID Reserved5[11]; - SIZE_T PeakPagefileUsage; - SIZE_T PrivatePageCount; - LARGE_INTEGER Reserved6[6]; + ULONG NextEntryOffset; /* 00/00 */ + BYTE Reserved1[52]; /* 04/04 */ + PVOID Reserved2[3]; /* 38/38 */ + HANDLE UniqueProcessId; /* 44/50 */ + PVOID Reserved3; /* 48/58 */ + ULONG HandleCount; /* 4c/60 */ + BYTE Reserved4[4]; /* 50/64 */ + PVOID Reserved5[11]; /* 54/68 */ + SIZE_T PeakPagefileUsage; /* 80/c0 */ + SIZE_T PrivatePageCount; /* 84/c8 */ + LARGE_INTEGER Reserved6[6]; /* 88/d0 */ #endif } SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION; diff --git a/reactos/include/reactos/wine/mscvpdb.h b/reactos/include/reactos/wine/mscvpdb.h index 9d52a655b56..2aefa879a90 100644 --- a/reactos/include/reactos/wine/mscvpdb.h +++ b/reactos/include/reactos/wine/mscvpdb.h @@ -1642,14 +1642,28 @@ struct startend unsigned int end; }; +#define LT2_LINES_BLOCK 0x000000f2 +#define LT2_FILES_BLOCK 0x000000f4 + /* there's a new line tab structure from MS Studio 2005 and after - * it's made of: - * DWORD 000000f4 - * DWORD lineblk_offset (counting bytes after this field) - * an array of codeview_linetab2_file structures - * an array (starting at ) of codeview_linetab2_block structures + * it's made of a list of codeview_linetab2 blocks. + * We've only seen (so far) list with a single LT2_FILES_BLOCK and several + * LT2_LINES_BLOCK. The LT2_FILES block has been encountered either as first + * or last block of the list. + * A LT2_FILES contains one or several codeview_linetab2_file:s */ +struct codeview_linetab2 +{ + DWORD header; + DWORD size_of_block; +}; + +static inline const struct codeview_linetab2* codeview_linetab2_next_block(const struct codeview_linetab2* lt2) +{ + return (const struct codeview_linetab2*)((const char*)(lt2 + 1) + lt2->size_of_block); +} + struct codeview_linetab2_file { DWORD offset; /* offset in string table for filename */ @@ -1658,16 +1672,21 @@ struct codeview_linetab2_file WORD pad0; /* always 0 */ }; -struct codeview_linetab2_block +struct codeview_lt2blk_files { - DWORD header; /* 0x000000f2 */ - DWORD size_of_block; /* next block is at # bytes after this field */ - DWORD start; /* start address of function with line numbers */ - DWORD seg; /* segment of function with line numbers */ - DWORD size; /* size of function with line numbers */ - DWORD file_offset; /* offset for accessing corresponding codeview_linetab2_file */ - DWORD nlines; /* number of lines in this block */ - DWORD size_lines; /* number of bytes following for line number information */ + struct codeview_linetab2 lt2; /* LT2_FILES */ + struct codeview_linetab2_file file[1]; +}; + +struct codeview_lt2blk_lines +{ + struct codeview_linetab2 lt2; /* LT2_LINE_BLOCK */ + DWORD start; /* start address of function with line numbers */ + DWORD seg; /* segment of function with line numbers */ + DWORD size; /* size of function with line numbers */ + DWORD file_offset; /* offset for accessing corresponding codeview_linetab2_file */ + DWORD nlines; /* number of lines in this block */ + DWORD size_lines; /* number of bytes following for line number information */ struct { DWORD offset; /* offset (from :) for line number */ DWORD lineno; /* the line number (OR:ed with 0x80000000 why ???) */ From d70bf73ec13704f8f46a904aaca44f87ce40cddb Mon Sep 17 00:00:00 2001 From: Christoph von Wittich Date: Mon, 15 Mar 2010 17:59:46 +0000 Subject: [PATCH 32/61] [NTDLL_WINETEST] partial sync of ntdll_winetest to match newer structs in winternl svn path=/trunk/; revision=46213 --- rostests/winetests/ntdll/info.c | 196 ++++++++++++++++++++++++-------- 1 file changed, 149 insertions(+), 47 deletions(-) diff --git a/rostests/winetests/ntdll/info.c b/rostests/winetests/ntdll/info.c index f61196eed74..c7d451c70b3 100755 --- a/rostests/winetests/ntdll/info.c +++ b/rostests/winetests/ntdll/info.c @@ -23,6 +23,9 @@ static NTSTATUS (WINAPI * pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); static NTSTATUS (WINAPI * pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG); +static NTSTATUS (WINAPI * pNtQueryInformationThread)(HANDLE, THREADINFOCLASS, PVOID, ULONG, PULONG); +static NTSTATUS (WINAPI * pNtSetInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG); +static NTSTATUS (WINAPI * pNtSetInformationThread)(HANDLE, THREADINFOCLASS, PVOID, ULONG); static NTSTATUS (WINAPI * pNtReadVirtualMemory)(HANDLE, const void*, void*, SIZE_T, SIZE_T*); /* one_before_last_pid is used to be able to compare values of a still running process @@ -44,12 +47,15 @@ static BOOL InitFunctionPtrs(void) HMODULE hntdll = GetModuleHandle("ntdll"); if (!hntdll) { - skip("Not running on NT\n"); + win_skip("Not running on NT\n"); return FALSE; } NTDLL_GET_PROC(NtQuerySystemInformation); NTDLL_GET_PROC(NtQueryInformationProcess); + NTDLL_GET_PROC(NtQueryInformationThread); + NTDLL_GET_PROC(NtSetInformationProcess); + NTDLL_GET_PROC(NtSetInformationThread); NTDLL_GET_PROC(NtReadVirtualMemory); return TRUE; @@ -122,18 +128,22 @@ static void test_query_performance(void) { NTSTATUS status; ULONG ReturnLength; - SYSTEM_PERFORMANCE_INFORMATION spi; + ULONGLONG buffer[sizeof(SYSTEM_PERFORMANCE_INFORMATION)/sizeof(ULONGLONG) + 1]; - status = pNtQuerySystemInformation(SystemPerformanceInformation, &spi, 0, &ReturnLength); + status = pNtQuerySystemInformation(SystemPerformanceInformation, buffer, 0, &ReturnLength); ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); - status = pNtQuerySystemInformation(SystemPerformanceInformation, &spi, sizeof(spi), &ReturnLength); + status = pNtQuerySystemInformation(SystemPerformanceInformation, buffer, + sizeof(SYSTEM_PERFORMANCE_INFORMATION), &ReturnLength); ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); - ok( sizeof(spi) == ReturnLength, "Inconsistent length %d\n", ReturnLength); + ok( ReturnLength == sizeof(SYSTEM_PERFORMANCE_INFORMATION), "Inconsistent length %d\n", ReturnLength); - status = pNtQuerySystemInformation(SystemPerformanceInformation, &spi, sizeof(spi) + 2, &ReturnLength); + status = pNtQuerySystemInformation(SystemPerformanceInformation, buffer, + sizeof(SYSTEM_PERFORMANCE_INFORMATION) + 2, &ReturnLength); ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); - ok( sizeof(spi) == ReturnLength, "Inconsistent length %d\n", ReturnLength); + ok( ReturnLength == sizeof(SYSTEM_PERFORMANCE_INFORMATION) || + ReturnLength == sizeof(SYSTEM_PERFORMANCE_INFORMATION) + 2, + "Inconsistent length %d\n", ReturnLength); /* Not return values yet, as struct members are unknown */ } @@ -227,7 +237,7 @@ static void test_query_process(void) /* Copy of our winternl.h structure turned into a private one */ typedef struct _SYSTEM_PROCESS_INFORMATION_PRIVATE { - DWORD dwOffset; + ULONG NextEntryOffset; DWORD dwThreadCount; DWORD dwUnknown1[6]; FILETIME ftCreationTime; @@ -235,9 +245,9 @@ static void test_query_process(void) FILETIME ftKernelTime; UNICODE_STRING ProcessName; DWORD dwBasePriority; - DWORD dwProcessID; - DWORD dwParentProcessID; - DWORD dwHandleCount; + HANDLE UniqueProcessId; + HANDLE ParentProcessId; + ULONG HandleCount; DWORD dwUnknown3; DWORD dwUnknown4; VM_COUNTERS vmCounters; @@ -261,15 +271,15 @@ static void test_query_process(void) ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); spi = spi_buf; - /* Get the first dwOffset, from this we can deduce the OS version we're running + /* Get the first NextEntryOffset, from this we can deduce the OS version we're running * * W2K/WinXP/W2K3: - * dwOffset for a process is 184 + (no. of threads) * sizeof(SYSTEM_THREAD_INFORMATION) + * NextEntryOffset for a process is 184 + (no. of threads) * sizeof(SYSTEM_THREAD_INFORMATION) * NT: - * dwOffset for a process is 136 + (no. of threads) * sizeof(SYSTEM_THREAD_INFORMATION) + * NextEntryOffset for a process is 136 + (no. of threads) * sizeof(SYSTEM_THREAD_INFORMATION) * Wine (with every windows version): - * dwOffset for a process is 0 if just this test is running - * dwOffset for a process is 184 + (no. of threads) * sizeof(SYSTEM_THREAD_INFORMATION) + + * 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 * @@ -278,9 +288,9 @@ static void test_query_process(void) pNtQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi), &ReturnLength); - is_nt = ( spi->dwOffset - (sbi.NumberOfProcessors * sizeof(SYSTEM_THREAD_INFORMATION)) == 136); + is_nt = ( spi->NextEntryOffset - (sbi.NumberOfProcessors * sizeof(SYSTEM_THREAD_INFORMATION)) == 136); - if (is_nt) skip("Windows version is NT, we will skip thread tests\n"); + if (is_nt) win_skip("Windows version is NT, we will skip thread tests\n"); /* Check if we have some return values * @@ -294,7 +304,7 @@ static void test_query_process(void) { i++; - last_pid = spi->dwProcessID; + last_pid = (DWORD_PTR)spi->UniqueProcessId; ok( spi->dwThreadCount > 0, "Expected some threads for this process, got 0\n"); @@ -306,17 +316,17 @@ static void test_query_process(void) for ( j = 0; j < spi->dwThreadCount; j++) { k++; - ok ( spi->ti[j].dwOwningPID == spi->dwProcessID, - "The owning pid of the thread (%d) doesn't equal the pid (%d) of the process\n", - spi->ti[j].dwOwningPID, spi->dwProcessID); + 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); } } - if (!spi->dwOffset) break; + if (!spi->NextEntryOffset) break; one_before_last_pid = last_pid; - spi = (SYSTEM_PROCESS_INFORMATION_PRIVATE*)((char*)spi + spi->dwOffset); + 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); @@ -545,12 +555,12 @@ static void test_query_process_basic(void) ULONG ReturnLength; typedef struct _PROCESS_BASIC_INFORMATION_PRIVATE { - DWORD ExitStatus; - DWORD PebBaseAddress; - DWORD AffinityMask; - DWORD BasePriority; - ULONG UniqueProcessId; - ULONG InheritedFromUniqueProcessId; + DWORD_PTR ExitStatus; + PPEB PebBaseAddress; + DWORD_PTR AffinityMask; + DWORD_PTR BasePriority; + ULONG_PTR UniqueProcessId; + ULONG_PTR InheritedFromUniqueProcessId; } PROCESS_BASIC_INFORMATION_PRIVATE, *PPROCESS_BASIC_INFORMATION_PRIVATE; PROCESS_BASIC_INFORMATION_PRIVATE pbi; @@ -604,7 +614,7 @@ static void test_query_process_basic(void) ok( sizeof(pbi) == ReturnLength, "Inconsistent length %d\n", ReturnLength); /* Check if we have some return values */ - trace("ProcessID : %d\n", pbi.UniqueProcessId); + trace("ProcessID : %lx\n", pbi.UniqueProcessId); ok( pbi.UniqueProcessId > 0, "Expected a ProcessID > 0, got 0\n"); } @@ -613,30 +623,30 @@ static void test_query_process_vm(void) NTSTATUS status; ULONG ReturnLength; VM_COUNTERS pvi; + ULONG old_size = FIELD_OFFSET(VM_COUNTERS,PrivatePageCount); status = pNtQueryInformationProcess(NULL, ProcessVmCounters, NULL, sizeof(pvi), NULL); ok( status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_HANDLE, "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_HANDLE(W2K3), got %08x\n", status); - status = pNtQueryInformationProcess(NULL, ProcessVmCounters, &pvi, sizeof(pvi), NULL); + status = pNtQueryInformationProcess(NULL, ProcessVmCounters, &pvi, old_size, NULL); ok( status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got %08x\n", status); /* Windows XP and W2K3 will report success for a size of 44 AND 48 ! Windows W2K will only report success for 44. - For now we only care for 44, which is sizeof(VM_COUNTERS) - If an app depends on it, we have to implement this in ntdll/process.c + For now we only care for 44, which is FIELD_OFFSET(VM_COUNTERS,PrivatePageCount)) */ status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessVmCounters, &pvi, 24, &ReturnLength); ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); - status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessVmCounters, &pvi, sizeof(pvi), &ReturnLength); + status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessVmCounters, &pvi, old_size, &ReturnLength); ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); - ok( sizeof(pvi) == ReturnLength, "Inconsistent length %d\n", ReturnLength); + ok( old_size == ReturnLength, "Inconsistent length %d\n", ReturnLength); status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessVmCounters, &pvi, 46, &ReturnLength); ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); - ok( sizeof(pvi) == ReturnLength, "Inconsistent length %d\n", ReturnLength); + ok( ReturnLength == old_size || ReturnLength == sizeof(pvi), "Inconsistent length %d\n", ReturnLength); /* Check if we have some return values */ trace("WorkingSetSize : %ld\n", pvi.WorkingSetSize); @@ -656,7 +666,7 @@ static void test_query_process_io(void) status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessIoCounters, &pii, sizeof(pii), &ReturnLength); if (status == STATUS_NOT_SUPPORTED) { - skip("ProcessIoCounters information class is not supported\n"); + win_skip("ProcessIoCounters information class is not supported\n"); return; } @@ -746,6 +756,7 @@ static void test_query_process_handlecount(void) NTSTATUS status; ULONG ReturnLength; DWORD handlecount; + BYTE buffer[2 * sizeof(DWORD)]; HANDLE process; status = pNtQueryInformationProcess(NULL, ProcessHandleCount, NULL, sizeof(handlecount), NULL); @@ -773,8 +784,9 @@ static void test_query_process_handlecount(void) ok( sizeof(handlecount) == ReturnLength, "Inconsistent length %d\n", ReturnLength); CloseHandle(process); - status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessHandleCount, &handlecount, sizeof(handlecount) * 2, &ReturnLength); - ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); + status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessHandleCount, buffer, sizeof(buffer), &ReturnLength); + ok( status == STATUS_INFO_LENGTH_MISMATCH || status == STATUS_SUCCESS, + "Expected STATUS_INFO_LENGTH_MISMATCH or STATUS_SUCCESS, got %08x\n", status); ok( sizeof(handlecount) == ReturnLength, "Inconsistent length %d\n", ReturnLength); /* Check if we have some return values */ @@ -797,7 +809,7 @@ static void test_query_process_image_file_name(void) status = pNtQueryInformationProcess(NULL, ProcessImageFileName, &image_file_name, sizeof(image_file_name), NULL); if (status == STATUS_INVALID_INFO_CLASS) { - skip("ProcessImageFileName is not supported\n"); + win_skip("ProcessImageFileName is not supported\n"); return; } ok( status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got %08x\n", status); @@ -818,6 +830,7 @@ static void test_query_process_image_file_name(void) file_nameA[len] = '\0'; HeapFree(GetProcessHeap(), 0, buffer); trace("process image file name: %s\n", file_nameA); + todo_wine ok(strncmp(file_nameA, "\\Device\\", 8) == 0, "Process image name should be an NT path beginning with \\Device\\ (is %s)\n", file_nameA); HeapFree(GetProcessHeap(), 0, file_nameA); } @@ -865,18 +878,104 @@ static void test_readvirtualmemory(void) ok( readcount == 12, "Expected to read 12 bytes, got %ld\n",readcount); ok( strcmp(teststring, buffer) == 0, "Expected read memory to be the same as original memory\n"); - /* this test currently crashes wine with "wine client error:: read: Bad address" - * because the reply from wine server is directly read into the buffer and that fails with EFAULT - */ /* illegal local address */ - /*status = pNtReadVirtualMemory(process, teststring, (void *)0x1234, 12, &readcount); - ok( status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", status); + status = pNtReadVirtualMemory(process, teststring, (void *)0x1234, 12, &readcount); + ok( status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got %08x\n", status); ok( readcount == 0, "Expected to read 0 bytes, got %ld\n",readcount); - */ CloseHandle(process); } +static void test_affinity(void) +{ + NTSTATUS status; + PROCESS_BASIC_INFORMATION pbi; + DWORD_PTR proc_affinity, thread_affinity; + THREAD_BASIC_INFORMATION tbi; + SYSTEM_INFO si; + + GetSystemInfo(&si); + status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessBasicInformation, &pbi, sizeof(pbi), NULL ); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + proc_affinity = (DWORD_PTR)pbi.Reserved2[0]; + ok( proc_affinity == (1 << si.dwNumberOfProcessors) - 1, "Unexpected process affinity\n" ); + proc_affinity = 1 << si.dwNumberOfProcessors; + status = pNtSetInformationProcess( GetCurrentProcess(), ProcessAffinityMask, &proc_affinity, sizeof(proc_affinity) ); + ok( status == STATUS_INVALID_PARAMETER, + "Expected STATUS_INVALID_PARAMETER, got %08x\n", status); + + proc_affinity = 0; + status = pNtSetInformationProcess( GetCurrentProcess(), ProcessAffinityMask, &proc_affinity, sizeof(proc_affinity) ); + ok( status == STATUS_INVALID_PARAMETER, + "Expected STATUS_INVALID_PARAMETER, got %08x\n", status); + + status = pNtQueryInformationThread( GetCurrentThread(), ThreadBasicInformation, &tbi, sizeof(tbi), NULL ); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( tbi.AffinityMask == (1 << si.dwNumberOfProcessors) - 1, "Unexpected thread affinity\n" ); + thread_affinity = 1 << si.dwNumberOfProcessors; + status = pNtSetInformationThread( GetCurrentThread(), ThreadAffinityMask, &thread_affinity, sizeof(thread_affinity) ); + ok( status == STATUS_INVALID_PARAMETER, + "Expected STATUS_INVALID_PARAMETER, got %08x\n", status); + thread_affinity = 0; + status = pNtSetInformationThread( GetCurrentThread(), ThreadAffinityMask, &thread_affinity, sizeof(thread_affinity) ); + ok( status == STATUS_INVALID_PARAMETER, + "Expected STATUS_INVALID_PARAMETER, got %08x\n", status); + + thread_affinity = 1; + status = pNtSetInformationThread( GetCurrentThread(), ThreadAffinityMask, &thread_affinity, sizeof(thread_affinity) ); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + status = pNtQueryInformationThread( GetCurrentThread(), ThreadBasicInformation, &tbi, sizeof(tbi), NULL ); + ok( tbi.AffinityMask == 1, "Unexpected thread affinity\n" ); + + /* NOTE: Pre-Vista does not recognize the "all processors" flag (all bits set) */ + thread_affinity = ~0UL; + status = pNtSetInformationThread( GetCurrentThread(), ThreadAffinityMask, &thread_affinity, sizeof(thread_affinity) ); + ok( broken(status == STATUS_INVALID_PARAMETER) || status == STATUS_SUCCESS, + "Expected STATUS_SUCCESS, got %08x\n", status); + + if (si.dwNumberOfProcessors <= 1) + { + skip("only one processor, skipping affinity testing\n"); + return; + } + + /* Test thread affinity mask resulting from "all processors" flag */ + if (status == STATUS_SUCCESS) + { + status = pNtQueryInformationThread( GetCurrentThread(), ThreadBasicInformation, &tbi, sizeof(tbi), NULL ); + ok( broken(tbi.AffinityMask == 1) || tbi.AffinityMask == (1 << si.dwNumberOfProcessors) - 1, + "Unexpected thread affinity\n" ); + } + else + skip("Cannot test thread affinity mask for 'all processors' flag\n"); + + proc_affinity = 2; + status = pNtSetInformationProcess( GetCurrentProcess(), ProcessAffinityMask, &proc_affinity, sizeof(proc_affinity) ); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessBasicInformation, &pbi, sizeof(pbi), NULL ); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + proc_affinity = (DWORD_PTR)pbi.Reserved2[0]; + ok( proc_affinity == 2, "Unexpected process affinity\n" ); + /* Setting the process affinity changes the thread affinity to match */ + status = pNtQueryInformationThread( GetCurrentThread(), ThreadBasicInformation, &tbi, sizeof(tbi), NULL ); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( tbi.AffinityMask == 2, "Unexpected thread affinity\n" ); + /* The thread affinity is restricted to the process affinity */ + thread_affinity = 1; + status = pNtSetInformationThread( GetCurrentThread(), ThreadAffinityMask, &thread_affinity, sizeof(thread_affinity) ); + ok( status == STATUS_INVALID_PARAMETER, + "Expected STATUS_INVALID_PARAMETER, got %08x\n", status); + + proc_affinity = (1 << si.dwNumberOfProcessors) - 1; + status = pNtSetInformationProcess( GetCurrentProcess(), ProcessAffinityMask, &proc_affinity, sizeof(proc_affinity) ); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + /* Resetting the process affinity also resets the thread affinity */ + status = pNtQueryInformationThread( GetCurrentThread(), ThreadBasicInformation, &tbi, sizeof(tbi), NULL ); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( tbi.AffinityMask == (1 << si.dwNumberOfProcessors) - 1, + "Unexpected thread affinity\n" ); +} + START_TEST(info) { if(!InitFunctionPtrs()) @@ -961,4 +1060,7 @@ START_TEST(info) /* belongs into it's own file */ trace("Starting test_readvirtualmemory()\n"); test_readvirtualmemory(); + + trace("Starting test_affinity()\n"); + test_affinity(); } From 5ca64ba60f87095d9ce731825f44bf298b2fabf4 Mon Sep 17 00:00:00 2001 From: Christoph von Wittich Date: Mon, 15 Mar 2010 22:04:15 +0000 Subject: [PATCH 33/61] [KERNEL32] sync parameter validation for SearchPath with wine 1.1.40 svn path=/trunk/; revision=46214 --- reactos/dll/win32/kernel32/file/dir.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/reactos/dll/win32/kernel32/file/dir.c b/reactos/dll/win32/kernel32/file/dir.c index c89afb6e465..97c04470e75 100644 --- a/reactos/dll/win32/kernel32/file/dir.c +++ b/reactos/dll/win32/kernel32/file/dir.c @@ -837,6 +837,12 @@ SearchPathA ( DWORD RetValue = 0; NTSTATUS Status = STATUS_SUCCESS; + if (!lpFileName) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + RtlInitAnsiString (&Path, (LPSTR)lpPath); RtlInitAnsiString (&FileName, @@ -985,6 +991,12 @@ SearchPathW(LPCWSTR lpPath, { DWORD ret = 0; + if (!lpFileName || !lpFileName[0]) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + /* If the name contains an explicit path, ignore the path */ if (ContainsPath(lpFileName)) { From d9f9773b77cbb9a649276b50e8ce253b80b16f06 Mon Sep 17 00:00:00 2001 From: Christoph von Wittich Date: Mon, 15 Mar 2010 22:13:19 +0000 Subject: [PATCH 34/61] [NTDLL_WINETEST] sync ntdll_winetest to wine 1.1.40 svn path=/trunk/; revision=46215 --- rostests/winetests/ntdll/atom.c | 1 + rostests/winetests/ntdll/change.c | 5 +- rostests/winetests/ntdll/directory.c | 293 ++++++++++ rostests/winetests/ntdll/error.c | 6 - rostests/winetests/ntdll/exception.c | 510 +++++++++++++++-- rostests/winetests/ntdll/file.c | 769 +++++++++++++++++++++++++- rostests/winetests/ntdll/ntdll.rbuild | 2 + rostests/winetests/ntdll/om.c | 69 +++ rostests/winetests/ntdll/reg.c | 692 ++++++++++++++++++++++- rostests/winetests/ntdll/rtl.c | 205 +++++-- rostests/winetests/ntdll/string.c | 33 +- rostests/winetests/ntdll/testlist.c | 2 + rostests/winetests/ntdll/time.c | 7 +- 13 files changed, 2479 insertions(+), 115 deletions(-) create mode 100644 rostests/winetests/ntdll/directory.c diff --git a/rostests/winetests/ntdll/atom.c b/rostests/winetests/ntdll/atom.c index 220ea40482f..821054849b2 100755 --- a/rostests/winetests/ntdll/atom.c +++ b/rostests/winetests/ntdll/atom.c @@ -34,6 +34,7 @@ #include "winbase.h" #include "winreg.h" #include "winnls.h" +#include "winuser.h" #include "wine/test.h" #include "winternl.h" diff --git a/rostests/winetests/ntdll/change.c b/rostests/winetests/ntdll/change.c index f395962ec23..ed7f22c9e61 100644 --- a/rostests/winetests/ntdll/change.c +++ b/rostests/winetests/ntdll/change.c @@ -295,15 +295,14 @@ static void test_ntncdf_async(void) ok(U(iosb).Status == 0x01234567, "status set too soon\n"); ok(iosb.Information == 0x12345678, "info set too soon\n"); - todo_wine { r = pNtCancelIoFile(hdir, &iosb); ok( r == STATUS_SUCCESS, "cancel failed\n"); CloseHandle(hdir); ok(U(iosb).Status == STATUS_SUCCESS, "status wrong\n"); - ok(U(iosb2).Status == STATUS_CANCELLED, "status wrong\n"); - } + todo_wine ok(U(iosb2).Status == STATUS_CANCELLED, "status wrong\n"); + ok(iosb.Information == 0, "info wrong\n"); ok(iosb2.Information == 0, "info wrong\n"); diff --git a/rostests/winetests/ntdll/directory.c b/rostests/winetests/ntdll/directory.c new file mode 100644 index 00000000000..a77a4b45326 --- /dev/null +++ b/rostests/winetests/ntdll/directory.c @@ -0,0 +1,293 @@ +/* Unit test suite for Ntdll directory functions + * + * Copyright 2007 Jeff Latimer + * Copyright 2007 Andrey Turkin + * Copyright 2008 Jeff Zaroyko + * Copyright 2009 Dan Kegel + * + * 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 + * + * NOTES + * We use function pointers here as there is no import library for NTDLL on + * windows. + */ + +#include +#include + +#include "ntstatus.h" +/* Define WIN32_NO_STATUS so MSVC does not give us duplicate macro + * definition errors when we get to winnt.h + */ +#define WIN32_NO_STATUS + +#include "wine/test.h" +#include "winternl.h" + +static NTSTATUS (WINAPI *pNtClose)( PHANDLE ); +static NTSTATUS (WINAPI *pNtOpenFile) ( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, ULONG, ULONG ); +static NTSTATUS (WINAPI *pNtQueryDirectoryFile)(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK, + PVOID,ULONG,FILE_INFORMATION_CLASS,BOOLEAN,PUNICODE_STRING,BOOLEAN); +static BOOLEAN (WINAPI *pRtlCreateUnicodeStringFromAsciiz)(PUNICODE_STRING,LPCSTR); +static BOOL (WINAPI *pRtlDosPathNameToNtPathName_U)( LPCWSTR, PUNICODE_STRING, PWSTR*, CURDIR* ); +static VOID (WINAPI *pRtlInitUnicodeString)( PUNICODE_STRING, LPCWSTR ); +static VOID (WINAPI *pRtlFreeUnicodeString)( PUNICODE_STRING ); +static NTSTATUS (WINAPI *pRtlMultiByteToUnicodeN)( LPWSTR dst, DWORD dstlen, LPDWORD reslen, + LPCSTR src, DWORD srclen ); +static NTSTATUS (WINAPI *pRtlWow64EnableFsRedirection)( BOOLEAN enable ); +static NTSTATUS (WINAPI *pRtlWow64EnableFsRedirectionEx)( ULONG disable, ULONG *old_value ); + +/* The attribute sets to test */ +struct testfile_s { + int todo; /* set if it doesn't work on wine yet */ + const DWORD attr; /* desired attribute */ + const char *name; /* filename to use */ + const char *target; /* what to point to (only for reparse pts) */ + const char *description; /* for error messages */ + int nfound; /* How many were found (expect 1) */ + WCHAR nameW[20]; /* unicode version of name (filled in later) */ +} testfiles[] = { + { 0, FILE_ATTRIBUTE_NORMAL, "n.tmp", NULL, "normal" }, + { 1, FILE_ATTRIBUTE_HIDDEN, "h.tmp", NULL, "hidden" }, + { 1, FILE_ATTRIBUTE_SYSTEM, "s.tmp", NULL, "system" }, + { 0, FILE_ATTRIBUTE_DIRECTORY, "d.tmp", NULL, "directory" }, + { 0, 0, NULL } +}; +static const int max_test_dir_size = 20; /* size of above plus some for .. etc */ + +/* Create a test directory full of attribute test files, clear counts */ +static void set_up_attribute_test(const char *testdirA) +{ + int i; + + ok(CreateDirectoryA(testdirA, NULL), + "couldn't create dir '%s', error %d\n", testdirA, GetLastError()); + + for (i=0; testfiles[i].name; i++) { + char buf[MAX_PATH]; + pRtlMultiByteToUnicodeN(testfiles[i].nameW, sizeof(testfiles[i].nameW), NULL, testfiles[i].name, strlen(testfiles[i].name)+1); + + sprintf(buf, "%s\\%s", testdirA, testfiles[i].name); + testfiles[i].nfound = 0; + if (testfiles[i].attr & FILE_ATTRIBUTE_DIRECTORY) { + ok(CreateDirectoryA(buf, NULL), + "couldn't create dir '%s', error %d\n", buf, GetLastError()); + } else { + HANDLE h = CreateFileA(buf, + GENERIC_READ|GENERIC_WRITE, + 0, NULL, CREATE_ALWAYS, + testfiles[i].attr, 0); + ok( h != INVALID_HANDLE_VALUE, "failed to create temp file '%s'\n", buf ); + CloseHandle(h); + } + } +} + +/* Remove the given test directory and the attribute test files, if any */ +static void tear_down_attribute_test(const char *testdirA) +{ + int i; + + for (i=0; testfiles[i].name; i++) { + int ret; + char buf[MAX_PATH]; + sprintf(buf, "%s\\%s", testdirA, testfiles[i].name); + if (testfiles[i].attr & FILE_ATTRIBUTE_DIRECTORY) { + ret = RemoveDirectory(buf); + ok(ret || (GetLastError() == ERROR_PATH_NOT_FOUND), + "Failed to rmdir %s, error %d\n", buf, GetLastError()); + } else { + ret = DeleteFile(buf); + ok(ret || (GetLastError() == ERROR_PATH_NOT_FOUND), + "Failed to rm %s, error %d\n", buf, GetLastError()); + } + } + RemoveDirectoryA(testdirA); +} + +/* Match one found file against testfiles[], increment count if found */ +static void tally_test_file(FILE_BOTH_DIRECTORY_INFORMATION *dir_info) +{ + int i; + DWORD attribmask = + (FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_REPARSE_POINT); + DWORD attrib = dir_info->FileAttributes & attribmask; + WCHAR *nameW = dir_info->FileName; + int namelen = dir_info->FileNameLength / sizeof(WCHAR); + + if (nameW[0] == '.') + return; + + for (i=0; testfiles[i].name; i++) { + int len = strlen(testfiles[i].name); + if (namelen != len || memcmp(nameW, testfiles[i].nameW, len*sizeof(WCHAR))) + continue; + if (testfiles[i].todo) { + todo_wine + ok (attrib == (testfiles[i].attr & attribmask), "file %s: expected %s (%x), got %x (is your linux new enough?)\n", testfiles[i].name, testfiles[i].description, testfiles[i].attr, attrib); + } else { + ok (attrib == (testfiles[i].attr & attribmask), "file %s: expected %s (%x), got %x (is your linux new enough?)\n", testfiles[i].name, testfiles[i].description, testfiles[i].attr, attrib); + } + testfiles[i].nfound++; + break; + } + ok(testfiles[i].name != NULL, "unexpected file found\n"); +} + +static void test_NtQueryDirectoryFile(void) +{ + OBJECT_ATTRIBUTES attr; + UNICODE_STRING ntdirname; + char testdirA[MAX_PATH]; + WCHAR testdirW[MAX_PATH]; + HANDLE dirh; + IO_STATUS_BLOCK io; + UINT data_pos; + UINT data_len; /* length of dir data */ + BYTE data[8192]; /* directory data */ + FILE_BOTH_DIRECTORY_INFORMATION *dir_info; + DWORD status; + int numfiles; + int i; + + /* Clean up from prior aborted run, if any, then set up test files */ + ok(GetTempPathA(MAX_PATH, testdirA), "couldn't get temp dir\n"); + strcat(testdirA, "NtQueryDirectoryFile.tmp"); + tear_down_attribute_test(testdirA); + set_up_attribute_test(testdirA); + + /* Read the directory and note which files are found */ + pRtlMultiByteToUnicodeN(testdirW, sizeof(testdirW), NULL, testdirA, strlen(testdirA)+1); + if (!pRtlDosPathNameToNtPathName_U(testdirW, &ntdirname, NULL, NULL)) + { + ok(0,"RtlDosPathNametoNtPathName_U failed\n"); + goto done; + } + InitializeObjectAttributes(&attr, &ntdirname, OBJ_CASE_INSENSITIVE, 0, NULL); + status = pNtOpenFile( &dirh, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, + FILE_OPEN, + FILE_SYNCHRONOUS_IO_NONALERT|FILE_OPEN_FOR_BACKUP_INTENT|FILE_DIRECTORY_FILE); + ok (status == STATUS_SUCCESS, "failed to open dir '%s', ret 0x%x, error %d\n", testdirA, status, GetLastError()); + if (status != STATUS_SUCCESS) { + skip("can't test if we can't open the directory\n"); + goto done; + } + + pNtQueryDirectoryFile( dirh, NULL, NULL, NULL, &io, data, sizeof(data), + FileBothDirectoryInformation, FALSE, NULL, TRUE ); + ok (U(io).Status == STATUS_SUCCESS, "filed to query directory; status %x\n", U(io).Status); + data_len = io.Information; + ok (data_len >= sizeof(FILE_BOTH_DIRECTORY_INFORMATION), "not enough data in directory\n"); + + data_pos = 0; + numfiles = 0; + while ((data_pos < data_len) && (numfiles < max_test_dir_size)) { + dir_info = (FILE_BOTH_DIRECTORY_INFORMATION *)(data + data_pos); + + tally_test_file(dir_info); + + if (dir_info->NextEntryOffset == 0) { + pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, sizeof(data), + FileBothDirectoryInformation, FALSE, NULL, FALSE ); + if (U(io).Status == STATUS_NO_MORE_FILES) + break; + ok (U(io).Status == STATUS_SUCCESS, "filed to query directory; status %x\n", U(io).Status); + data_len = io.Information; + if (data_len < sizeof(FILE_BOTH_DIRECTORY_INFORMATION)) + break; + data_pos = 0; + } else { + data_pos += dir_info->NextEntryOffset; + } + numfiles++; + } + ok(numfiles < max_test_dir_size, "too many loops\n"); + + for (i=0; testfiles[i].name; i++) + ok(testfiles[i].nfound == 1, "Wrong number %d of %s files found\n", + testfiles[i].nfound, testfiles[i].description); + + pNtClose(dirh); +done: + tear_down_attribute_test(testdirA); + pRtlFreeUnicodeString(&ntdirname); +} + +static void test_redirection(void) +{ + ULONG old, cur; + NTSTATUS status; + + if (!pRtlWow64EnableFsRedirection || !pRtlWow64EnableFsRedirectionEx) + { + skip( "Wow64 redirection not supported\n" ); + return; + } + status = pRtlWow64EnableFsRedirectionEx( FALSE, &old ); + if (status == STATUS_NOT_IMPLEMENTED) + { + skip( "Wow64 redirection not supported\n" ); + return; + } + ok( !status, "RtlWow64EnableFsRedirectionEx failed status %x\n", status ); + + status = pRtlWow64EnableFsRedirectionEx( FALSE, &cur ); + ok( !status, "RtlWow64EnableFsRedirectionEx failed status %x\n", status ); + ok( !cur, "RtlWow64EnableFsRedirectionEx got %u\n", cur ); + + status = pRtlWow64EnableFsRedirectionEx( TRUE, &cur ); + ok( !status, "RtlWow64EnableFsRedirectionEx failed status %x\n", status ); + status = pRtlWow64EnableFsRedirectionEx( TRUE, &cur ); + ok( !status, "RtlWow64EnableFsRedirectionEx failed status %x\n", status ); + ok( cur == 1, "RtlWow64EnableFsRedirectionEx got %u\n", cur ); + + status = pRtlWow64EnableFsRedirection( TRUE ); + ok( !status, "RtlWow64EnableFsRedirectionEx failed status %x\n", status ); + status = pRtlWow64EnableFsRedirectionEx( TRUE, &cur ); + ok( !status, "RtlWow64EnableFsRedirectionEx failed status %x\n", status ); + ok( !cur, "RtlWow64EnableFsRedirectionEx got %u\n", cur ); + + status = pRtlWow64EnableFsRedirection( FALSE ); + ok( !status, "RtlWow64EnableFsRedirectionEx failed status %x\n", status ); + status = pRtlWow64EnableFsRedirectionEx( FALSE, &cur ); + ok( !status, "RtlWow64EnableFsRedirectionEx failed status %x\n", status ); + ok( cur == 1, "RtlWow64EnableFsRedirectionEx got %u\n", cur ); + + pRtlWow64EnableFsRedirectionEx( old, &cur ); +} + +START_TEST(directory) +{ + HMODULE hntdll = GetModuleHandleA("ntdll.dll"); + if (!hntdll) + { + skip("not running on NT, skipping test\n"); + return; + } + + pNtClose = (void *)GetProcAddress(hntdll, "NtClose"); + pNtOpenFile = (void *)GetProcAddress(hntdll, "NtOpenFile"); + pNtQueryDirectoryFile = (void *)GetProcAddress(hntdll, "NtQueryDirectoryFile"); + pRtlCreateUnicodeStringFromAsciiz = (void *)GetProcAddress(hntdll, "RtlCreateUnicodeStringFromAsciiz"); + pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(hntdll, "RtlDosPathNameToNtPathName_U"); + pRtlInitUnicodeString = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString"); + pRtlFreeUnicodeString = (void *)GetProcAddress(hntdll, "RtlFreeUnicodeString"); + pRtlMultiByteToUnicodeN = (void *)GetProcAddress(hntdll,"RtlMultiByteToUnicodeN"); + pRtlWow64EnableFsRedirection = (void *)GetProcAddress(hntdll,"RtlWow64EnableFsRedirection"); + pRtlWow64EnableFsRedirectionEx = (void *)GetProcAddress(hntdll,"RtlWow64EnableFsRedirectionEx"); + + test_NtQueryDirectoryFile(); + test_redirection(); +} diff --git a/rostests/winetests/ntdll/error.c b/rostests/winetests/ntdll/error.c index b65d7d0ccd7..ee8b9b27d73 100755 --- a/rostests/winetests/ntdll/error.c +++ b/rostests/winetests/ntdll/error.c @@ -892,12 +892,6 @@ static void run_error_tests(void) cmp2(STATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE, ERROR_CTX_SHADOW_ENDED_BY_MODE_CHANGE); cmp2(STATUS_CTX_SHADOW_NOT_RUNNING, ERROR_CTX_SHADOW_NOT_RUNNING); cmp2(STATUS_LICENSE_VIOLATION, ERROR_CTX_LICENSE_NOT_AVAILABLE); -#if 0 - /* FIXME - unknown STATUS values, see bug 1001 */ - cmp(STATUS_ENDPOINT_CLOSED, ERROR_DEV_NOT_EXIST); - cmp(STATUS_DISCONNECTED, ERROR_DEV_NOT_EXIST); - cmp(STATUS_NONEXISTENT_NET_NAME, ERROR_DEV_NOT_EXIST); -#endif cmp2(STATUS_NETWORK_SESSION_EXPIRED, ERROR_NO_USER_SESSION_KEY); cmp2(STATUS_FILES_OPEN, ERROR_OPEN_FILES); cmp2(STATUS_SXS_SECTION_NOT_FOUND, ERROR_SXS_SECTION_NOT_FOUND); diff --git a/rostests/winetests/ntdll/exception.c b/rostests/winetests/ntdll/exception.c index 6ed641c6dad..7f215ed9168 100644 --- a/rostests/winetests/ntdll/exception.c +++ b/rostests/winetests/ntdll/exception.c @@ -25,6 +25,8 @@ #define _WIN32_WINNT 0x500 /* For NTSTATUS */ #endif +#define NONAMELESSUNION +#define NONAMELESSSTRUCT #include "ntstatus.h" #define WIN32_NO_STATUS #include "windef.h" @@ -35,10 +37,7 @@ #include "wine/exception.h" #include "wine/test.h" -#ifdef __i386__ -static int my_argc; -static char** my_argv; -static int test_stage; +static void *code_mem; static struct _TEB * (WINAPI *pNtCurrentTeb)(void); static NTSTATUS (WINAPI *pNtGetContextThread)(HANDLE,CONTEXT*); @@ -48,7 +47,21 @@ static PVOID (WINAPI *pRtlAddVectoredExceptionHandler)(ULONG first, PVECTORE static ULONG (WINAPI *pRtlRemoveVectoredExceptionHandler)(PVOID handler); static NTSTATUS (WINAPI *pNtReadVirtualMemory)(HANDLE, const void*, void*, SIZE_T, SIZE_T*); static NTSTATUS (WINAPI *pNtTerminateProcess)(HANDLE handle, LONG exit_code); -static void *code_mem; +static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG); +static NTSTATUS (WINAPI *pNtSetInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG); + +#ifdef __i386__ + +#ifndef __WINE_WINTRNL_H +#define ProcessExecuteFlags 0x22 +#define MEM_EXECUTE_OPTION_DISABLE 0x01 +#define MEM_EXECUTE_OPTION_ENABLE 0x02 +#define MEM_EXECUTE_OPTION_PERMANENT 0x08 +#endif + +static int my_argc; +static char** my_argv; +static int test_stage; /* Test various instruction combinations that cause a protection fault on the i386, * and check what the resulting exception looks like. @@ -116,11 +129,11 @@ static const struct exception { { 0x0e, 0x17, 0x58, 0xc3 }, /* 18: pushl %cs; popl %ss; popl %eax; ret */ 1, 1, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } }, - /* 19: test overlong instruction (limit is 16 bytes) */ + /* 19: test overlong instruction (limit is 15 bytes, 5 on Win7) */ { { 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0xfa,0xc3 }, 0, 16, STATUS_ILLEGAL_INSTRUCTION, 0 }, - { { 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0xfa,0xc3 }, - 0, 15, STATUS_PRIVILEGED_INSTRUCTION, 0 }, + { { 0x64,0x64,0x64,0x64,0xfa,0xc3 }, + 0, 5, STATUS_PRIVILEGED_INSTRUCTION, 0 }, /* test invalid interrupt */ { { 0xcd, 0xff, 0xc3 }, /* 21: int $0xff; ret */ @@ -180,23 +193,30 @@ static int got_exception; static BOOL have_vectored_api; static void run_exception_test(void *handler, const void* context, - const void *code, unsigned int code_size) + const void *code, unsigned int code_size, + DWORD access) { struct { EXCEPTION_REGISTRATION_RECORD frame; const void *context; } exc_frame; void (*func)(void) = code_mem; + DWORD oldaccess, oldaccess2; exc_frame.frame.Handler = handler; exc_frame.frame.Prev = pNtCurrentTeb()->Tib.ExceptionList; exc_frame.context = context; memcpy(code_mem, code, code_size); + if(access) + VirtualProtect(code_mem, code_size, access, &oldaccess); pNtCurrentTeb()->Tib.ExceptionList = &exc_frame.frame; func(); pNtCurrentTeb()->Tib.ExceptionList = exc_frame.frame.Prev; + + if(access) + VirtualProtect(code_mem, code_size, oldaccess, &oldaccess2); } static LONG CALLBACK rtlraiseexception_vectored_handler(EXCEPTION_POINTERS *ExceptionInfo) @@ -394,7 +414,7 @@ static void test_prot_fault(void) { got_exception = 0; run_exception_test(handler, &exceptions[i], &exceptions[i].code, - sizeof(exceptions[i].code)); + sizeof(exceptions[i].code), 0); if (!i && !got_exception) { trace( "No exception, assuming win9x, no point in testing further\n" ); @@ -583,7 +603,7 @@ static void test_exceptions(void) } /* test handling of debug registers */ - run_exception_test(dreg_handler, NULL, &segfault_code, sizeof(segfault_code)); + run_exception_test(dreg_handler, NULL, &segfault_code, sizeof(segfault_code), 0); ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; res = pNtGetContextThread(GetCurrentThread(), &ctx); @@ -593,17 +613,17 @@ static void test_exceptions(void) /* test single stepping behavior */ got_exception = 0; - run_exception_test(single_step_handler, NULL, &single_stepcode, sizeof(single_stepcode)); + run_exception_test(single_step_handler, NULL, &single_stepcode, sizeof(single_stepcode), 0); ok(got_exception == 3, "expected 3 single step exceptions, got %d\n", got_exception); /* test alignment exceptions */ got_exception = 0; - run_exception_test(align_check_handler, NULL, align_check_code, sizeof(align_check_code)); + run_exception_test(align_check_handler, NULL, align_check_code, sizeof(align_check_code), 0); ok(got_exception == 0, "got %d alignment faults, expected 0\n", got_exception); /* test direction flag */ got_exception = 0; - run_exception_test(direction_flag_handler, NULL, direction_flag_code, sizeof(direction_flag_code)); + run_exception_test(direction_flag_handler, NULL, direction_flag_code, sizeof(direction_flag_code), 0); ok(got_exception == 1, "got %d exceptions, expected 1\n", got_exception); /* test single stepping over hardware breakpoint */ @@ -615,11 +635,11 @@ static void test_exceptions(void) ok( res == STATUS_SUCCESS, "NtSetContextThread faild with %x\n", res); got_exception = 0; - run_exception_test(bpx_handler, NULL, dummy_code, sizeof(dummy_code)); + run_exception_test(bpx_handler, NULL, dummy_code, sizeof(dummy_code), 0); ok( got_exception == 4,"expected 4 exceptions, got %d\n", got_exception); /* test int3 handling */ - run_exception_test(int3_handler, NULL, int3_code, sizeof(int3_code)); + run_exception_test(int3_handler, NULL, int3_code, sizeof(int3_code), 0); } static void test_debugger(void) @@ -638,7 +658,7 @@ static void test_debugger(void) if(!pNtGetContextThread || !pNtSetContextThread || !pNtReadVirtualMemory || !pNtTerminateProcess) { - skip("NtGetContextThread, NtSetContextThread, NtReadVirtualMemory or NtTerminateProcess not found\n)"); + skip("NtGetContextThread, NtSetContextThread, NtReadVirtualMemory or NtTerminateProcess not found\n"); return; } @@ -825,7 +845,7 @@ static void test_simd_exceptions(void) /* test if CPU & OS can do sse */ stage = 1; got_exception = 0; - run_exception_test(simd_fault_handler, &stage, sse_check, sizeof(sse_check)); + run_exception_test(simd_fault_handler, &stage, sse_check, sizeof(sse_check), 0); if(got_exception) { skip("system doesn't support SSE\n"); return; @@ -835,7 +855,7 @@ static void test_simd_exceptions(void) stage = 2; got_exception = 0; run_exception_test(simd_fault_handler, &stage, simd_exception_test, - sizeof(simd_exception_test)); + sizeof(simd_exception_test), 0); ok( got_exception == 1, "got exception: %i, should be 1\n", got_exception); } @@ -901,27 +921,450 @@ static void test_fpu_exceptions(void) struct fpu_exception_info info; memset(&info, 0, sizeof(info)); - run_exception_test(fpu_exception_handler, &info, fpu_exception_test_ie, sizeof(fpu_exception_test_ie)); + run_exception_test(fpu_exception_handler, &info, fpu_exception_test_ie, sizeof(fpu_exception_test_ie), 0); ok(info.exception_code == EXCEPTION_FLT_STACK_CHECK, "Got exception code %#x, expected EXCEPTION_FLT_STACK_CHECK\n", info.exception_code); ok(info.exception_offset == 0x19, "Got exception offset %#x, expected 0x19\n", info.exception_offset); ok(info.eip_offset == 0x1b, "Got EIP offset %#x, expected 0x1b\n", info.eip_offset); memset(&info, 0, sizeof(info)); - run_exception_test(fpu_exception_handler, &info, fpu_exception_test_de, sizeof(fpu_exception_test_de)); + run_exception_test(fpu_exception_handler, &info, fpu_exception_test_de, sizeof(fpu_exception_test_de), 0); ok(info.exception_code == EXCEPTION_FLT_DIVIDE_BY_ZERO, "Got exception code %#x, expected EXCEPTION_FLT_DIVIDE_BY_ZERO\n", info.exception_code); ok(info.exception_offset == 0x17, "Got exception offset %#x, expected 0x17\n", info.exception_offset); ok(info.eip_offset == 0x19, "Got EIP offset %#x, expected 0x19\n", info.eip_offset); } -#endif /* __i386__ */ +struct dpe_exception_info { + BOOL exception_caught; + DWORD exception_info; +}; + +static DWORD dpe_exception_handler(EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, + CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher) +{ + DWORD old_prot; + struct dpe_exception_info *info = *(struct dpe_exception_info **)(frame + 1); + + ok(rec->ExceptionCode == EXCEPTION_ACCESS_VIOLATION, + "Exception code %08x\n", rec->ExceptionCode); + ok(rec->NumberParameters == 2, + "Parameter count: %d\n", rec->NumberParameters); + ok((LPVOID)rec->ExceptionInformation[1] == code_mem, + "Exception address: %p, expected %p\n", + (LPVOID)rec->ExceptionInformation[1], code_mem); + + info->exception_info = rec->ExceptionInformation[0]; + info->exception_caught = TRUE; + + VirtualProtect(code_mem, 1, PAGE_EXECUTE_READWRITE, &old_prot); + return ExceptionContinueExecution; +} + +static void test_dpe_exceptions(void) +{ + static char single_ret[] = {0xC3}; + struct dpe_exception_info info; + NTSTATUS stat; + BOOL has_hw_support; + BOOL is_permanent = FALSE, can_test_without = TRUE, can_test_with = TRUE; + DWORD val; + ULONG len; + + /* Query DEP with len to small */ + stat = pNtQueryInformationProcess(GetCurrentProcess(), ProcessExecuteFlags, &val, sizeof val - 1, &len); + if(stat == STATUS_INVALID_INFO_CLASS) + { + skip("This software platform does not support DEP\n"); + return; + } + ok(stat == STATUS_INFO_LENGTH_MISMATCH, "buffer too small: %08x\n", stat); + + /* Query DEP */ + stat = pNtQueryInformationProcess(GetCurrentProcess(), ProcessExecuteFlags, &val, sizeof val, &len); + ok(stat == STATUS_SUCCESS, "querying DEP: status %08x\n", stat); + if(stat == STATUS_SUCCESS) + { + ok(len == sizeof val, "returned length: %d\n", len); + if(val & MEM_EXECUTE_OPTION_PERMANENT) + { + skip("toggling DEP impossible - status locked\n"); + is_permanent = TRUE; + if(val & MEM_EXECUTE_OPTION_DISABLE) + can_test_without = FALSE; + else + can_test_with = FALSE; + } + } + + if(!is_permanent) + { + /* Enable DEP */ + val = MEM_EXECUTE_OPTION_DISABLE; + stat = pNtSetInformationProcess(GetCurrentProcess(), ProcessExecuteFlags, &val, sizeof val); + ok(stat == STATUS_SUCCESS, "enabling DEP: status %08x\n", stat); + } + + if(can_test_with) + { + /* Try access to locked page with DEP on*/ + info.exception_caught = FALSE; + run_exception_test(dpe_exception_handler, &info, single_ret, sizeof(single_ret), PAGE_NOACCESS); + ok(info.exception_caught == TRUE, "Execution of disabled memory succeeded\n"); + ok(info.exception_info == EXCEPTION_READ_FAULT || + info.exception_info == EXCEPTION_EXECUTE_FAULT, + "Access violation type: %08x\n", (unsigned)info.exception_info); + has_hw_support = info.exception_info == EXCEPTION_EXECUTE_FAULT; + trace("DEP hardware support: %s\n", has_hw_support?"Yes":"No"); + + /* Try execution of data with DEP on*/ + info.exception_caught = FALSE; + run_exception_test(dpe_exception_handler, &info, single_ret, sizeof(single_ret), PAGE_READWRITE); + if(has_hw_support) + { + ok(info.exception_caught == TRUE, "Execution of data memory succeeded\n"); + ok(info.exception_info == EXCEPTION_EXECUTE_FAULT, + "Access violation type: %08x\n", (unsigned)info.exception_info); + } + else + ok(info.exception_caught == FALSE, "Execution trapped without hardware support\n"); + } + else + skip("DEP is in AlwaysOff state\n"); + + if(!is_permanent) + { + /* Disable DEP */ + val = MEM_EXECUTE_OPTION_ENABLE; + stat = pNtSetInformationProcess(GetCurrentProcess(), ProcessExecuteFlags, &val, sizeof val); + ok(stat == STATUS_SUCCESS, "disabling DEP: status %08x\n", stat); + } + + /* page is read without exec here */ + if(can_test_without) + { + /* Try execution of data with DEP off */ + info.exception_caught = FALSE; + run_exception_test(dpe_exception_handler, &info, single_ret, sizeof(single_ret), PAGE_READWRITE); + ok(info.exception_caught == FALSE, "Execution trapped with DEP turned off\n"); + + /* Try access to locked page with DEP off - error code is different than + with hardware DEP on */ + info.exception_caught = FALSE; + run_exception_test(dpe_exception_handler, &info, single_ret, sizeof(single_ret), PAGE_NOACCESS); + ok(info.exception_caught == TRUE, "Execution of disabled memory succeeded\n"); + ok(info.exception_info == EXCEPTION_READ_FAULT, + "Access violation type: %08x\n", (unsigned)info.exception_info); + } + else + skip("DEP is in AlwaysOn state\n"); + + if(!is_permanent) + { + /* Turn off DEP permanently */ + val = MEM_EXECUTE_OPTION_ENABLE | MEM_EXECUTE_OPTION_PERMANENT; + stat = pNtSetInformationProcess(GetCurrentProcess(), ProcessExecuteFlags, &val, sizeof val); + ok(stat == STATUS_SUCCESS, "disabling DEP permanently: status %08x\n", stat); + } + + /* Try to turn off DEP */ + val = MEM_EXECUTE_OPTION_ENABLE; + stat = pNtSetInformationProcess(GetCurrentProcess(), ProcessExecuteFlags, &val, sizeof val); + ok(stat == STATUS_ACCESS_DENIED, "disabling DEP while permanent: status %08x\n", stat); + + /* Try to turn on DEP */ + val = MEM_EXECUTE_OPTION_DISABLE; + stat = pNtSetInformationProcess(GetCurrentProcess(), ProcessExecuteFlags, &val, sizeof val); + ok(stat == STATUS_ACCESS_DENIED, "enabling DEP while permanent: status %08x\n", stat); +} + +#elif defined(__x86_64__) + +#define UNW_FLAG_NHANDLER 0 +#define UNW_FLAG_EHANDLER 1 +#define UNW_FLAG_UHANDLER 2 +#define UNW_FLAG_CHAININFO 4 + +#define UWOP_PUSH_NONVOL 0 +#define UWOP_ALLOC_LARGE 1 +#define UWOP_ALLOC_SMALL 2 +#define UWOP_SET_FPREG 3 +#define UWOP_SAVE_NONVOL 4 +#define UWOP_SAVE_NONVOL_FAR 5 +#define UWOP_SAVE_XMM128 8 +#define UWOP_SAVE_XMM128_FAR 9 +#define UWOP_PUSH_MACHFRAME 10 + +struct results +{ + int rip_offset; /* rip offset from code start */ + int rbp_offset; /* rbp offset from stack pointer */ + int handler; /* expect handler to be set? */ + int rip; /* expected final rip value */ + int frame; /* expected frame return value */ + int regs[8][2]; /* expected values for registers */ +}; + +struct unwind_test +{ + const BYTE *function; + size_t function_size; + const BYTE *unwind_info; + const struct results *results; + unsigned int nb_results; +}; + +enum regs +{ + rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, + r8, r9, r10, r11, r12, r13, r14, r15 +}; + +static const char * const reg_names[16] = +{ + "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" +}; + +#define UWOP(code,info) (UWOP_##code | ((info) << 4)) + +static void call_virtual_unwind( int testnum, const struct unwind_test *test ) +{ + static const int code_offset = 1024; + static const int unwind_offset = 2048; + void *handler, *data; + CONTEXT context; + RUNTIME_FUNCTION runtime_func; + KNONVOLATILE_CONTEXT_POINTERS ctx_ptr; + UINT i, j, k; + ULONG64 fake_stack[256]; + ULONG64 frame, orig_rip, orig_rbp, unset_reg; + UINT unwind_size = 4 + 2 * test->unwind_info[2] + 8; + + memcpy( (char *)code_mem + code_offset, test->function, test->function_size ); + memcpy( (char *)code_mem + unwind_offset, test->unwind_info, unwind_size ); + + runtime_func.BeginAddress = code_offset; + runtime_func.EndAddress = code_offset + test->function_size; + runtime_func.UnwindData = unwind_offset; + + trace( "code: %p stack: %p\n", code_mem, fake_stack ); + + for (i = 0; i < test->nb_results; i++) + { + memset( &ctx_ptr, 0, sizeof(ctx_ptr) ); + memset( &context, 0x55, sizeof(context) ); + memset( &unset_reg, 0x55, sizeof(unset_reg) ); + for (j = 0; j < 256; j++) fake_stack[j] = j * 8; + + context.Rsp = (ULONG_PTR)fake_stack; + context.Rbp = (ULONG_PTR)fake_stack + test->results[i].rbp_offset; + orig_rbp = context.Rbp; + orig_rip = (ULONG64)code_mem + code_offset + test->results[i].rip_offset; + + trace( "%u/%u: rip=%p (%02x) rbp=%p rsp=%p\n", testnum, i, + (void *)orig_rip, *(BYTE *)orig_rip, (void *)orig_rbp, (void *)context.Rsp ); + + data = (void *)0xdeadbeef; + handler = RtlVirtualUnwind( UNW_FLAG_EHANDLER, (ULONG64)code_mem, orig_rip, + &runtime_func, &context, &data, &frame, &ctx_ptr ); + if (test->results[i].handler) + { + ok( (char *)handler == (char *)code_mem + 0x200, + "%u/%u: wrong handler %p/%p\n", testnum, i, handler, (char *)code_mem + 0x200 ); + if (handler) ok( *(DWORD *)data == 0x08070605, + "%u/%u: wrong handler data %p\n", testnum, i, data ); + } + else + { + ok( handler == NULL, "%u/%u: handler %p instead of NULL\n", testnum, i, handler ); + ok( data == (void *)0xdeadbeef, "%u/%u: handler data set to %p\n", testnum, i, data ); + } + + ok( context.Rip == test->results[i].rip, "%u/%u: wrong rip %p/%x\n", + testnum, i, (void *)context.Rip, test->results[i].rip ); + ok( frame == (ULONG64)fake_stack + test->results[i].frame, "%u/%u: wrong frame %p/%p\n", + testnum, i, (void *)frame, (char *)fake_stack + test->results[i].frame ); + + for (j = 0; j < 16; j++) + { + static const UINT nb_regs = sizeof(test->results[i].regs) / sizeof(test->results[i].regs[0]); + + for (k = 0; k < nb_regs; k++) + { + if (test->results[i].regs[k][0] == -1) + { + k = nb_regs; + break; + } + if (test->results[i].regs[k][0] == j) break; + } + + if (j == rsp) /* rsp is special */ + { + ok( !ctx_ptr.u2.IntegerContext[j], + "%u/%u: rsp should not be set in ctx_ptr\n", testnum, i ); + ok( context.Rsp == (ULONG64)fake_stack + test->results[i].regs[k][1], + "%u/%u: register rsp wrong %p/%p\n", + testnum, i, (void *)context.Rsp, (char *)fake_stack + test->results[i].regs[k][1] ); + continue; + } + + if (ctx_ptr.u2.IntegerContext[j]) + { + ok( k < nb_regs, "%u/%u: register %s should not be set to %lx\n", + testnum, i, reg_names[j], *(&context.Rax + j) ); + if (k < nb_regs) + ok( *(&context.Rax + j) == test->results[i].regs[k][1], + "%u/%u: register %s wrong %p/%x\n", + testnum, i, reg_names[j], (void *)*(&context.Rax + j), test->results[i].regs[k][1] ); + } + else + { + ok( k == nb_regs, "%u/%u: register %s should be set\n", testnum, i, reg_names[j] ); + if (j == rbp) + ok( context.Rbp == orig_rbp, "%u/%u: register rbp wrong %p/unset\n", + testnum, i, (void *)context.Rbp ); + else + ok( *(&context.Rax + j) == unset_reg, + "%u/%u: register %s wrong %p/unset\n", + testnum, i, reg_names[j], (void *)*(&context.Rax + j)); + } + } + } +} + +static void test_virtual_unwind(void) +{ + static const BYTE function_0[] = + { + 0xff, 0xf5, /* 00: push %rbp */ + 0x48, 0x81, 0xec, 0x10, 0x01, 0x00, 0x00, /* 02: sub $0x110,%rsp */ + 0x48, 0x8d, 0x6c, 0x24, 0x30, /* 09: lea 0x30(%rsp),%rbp */ + 0x48, 0x89, 0x9d, 0xf0, 0x00, 0x00, 0x00, /* 0e: mov %rbx,0xf0(%rbp) */ + 0x48, 0x89, 0xb5, 0xf8, 0x00, 0x00, 0x00, /* 15: mov %rsi,0xf8(%rbp) */ + 0x90, /* 1c: nop */ + 0x48, 0x8b, 0x9d, 0xf0, 0x00, 0x00, 0x00, /* 1d: mov 0xf0(%rbp),%rbx */ + 0x48, 0x8b, 0xb5, 0xf8, 0x00, 0x00, 0x00, /* 24: mov 0xf8(%rbp),%rsi */ + 0x48, 0x8d, 0xa5, 0xe0, 0x00, 0x00, 0x00, /* 2b: lea 0xe0(%rbp),%rsp */ + 0x5d, /* 32: pop %rbp */ + 0xc3 /* 33: ret */ + }; + + static const BYTE unwind_info_0[] = + { + 1 | (UNW_FLAG_EHANDLER << 3), /* version + flags */ + 0x1c, /* prolog size */ + 8, /* opcode count */ + (0x03 << 4) | rbp, /* frame reg rbp offset 0x30 */ + + 0x1c, UWOP(SAVE_NONVOL, rsi), 0x25, 0, /* 1c: mov %rsi,0x128(%rsp) */ + 0x15, UWOP(SAVE_NONVOL, rbx), 0x24, 0, /* 15: mov %rbx,0x120(%rsp) */ + 0x0e, UWOP(SET_FPREG, rbp), /* 0e: lea 0x30(%rsp),rbp */ + 0x09, UWOP(ALLOC_LARGE, 0), 0x22, 0, /* 09: sub $0x110,%rsp */ + 0x02, UWOP(PUSH_NONVOL, rbp), /* 02: push %rbp */ + + 0x00, 0x02, 0x00, 0x00, /* handler */ + 0x05, 0x06, 0x07, 0x08, /* data */ + }; + + static const struct results results_0[] = + { + /* offset rbp handler rip frame registers */ + { 0x00, 0x40, FALSE, 0x000, 0x000, { {rsp,0x008}, {-1,-1} }}, + { 0x02, 0x40, FALSE, 0x008, 0x000, { {rsp,0x010}, {rbp,0x000}, {-1,-1} }}, + { 0x09, 0x40, FALSE, 0x118, 0x000, { {rsp,0x120}, {rbp,0x110}, {-1,-1} }}, + { 0x0e, 0x40, FALSE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {-1,-1} }}, + { 0x15, 0x40, FALSE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {rbx,0x130}, {-1,-1} }}, + { 0x1c, 0x40, TRUE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {rbx,0x130}, {rsi,0x138}, {-1,-1}}}, + { 0x1d, 0x40, TRUE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {rbx,0x130}, {rsi,0x138}, {-1,-1}}}, + { 0x24, 0x40, TRUE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {rbx,0x130}, {rsi,0x138}, {-1,-1}}}, + { 0x2b, 0x40, FALSE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {-1,-1}}}, + { 0x32, 0x40, FALSE, 0x008, 0x010, { {rsp,0x010}, {rbp,0x000}, {-1,-1}}}, + { 0x33, 0x40, FALSE, 0x000, 0x010, { {rsp,0x008}, {-1,-1}}}, + }; + + + static const BYTE function_1[] = + { + 0x53, /* 00: push %rbx */ + 0x55, /* 01: push %rbp */ + 0x56, /* 02: push %rsi */ + 0x57, /* 03: push %rdi */ + 0x41, 0x54, /* 04: push %r12 */ + 0x48, 0x83, 0xec, 0x30, /* 06: sub $0x30,%rsp */ + 0x90, 0x90, /* 0a: nop; nop */ + 0x48, 0x83, 0xc4, 0x30, /* 0c: add $0x30,%rsp */ + 0x41, 0x5c, /* 10: pop %r12 */ + 0x5f, /* 12: pop %rdi */ + 0x5e, /* 13: pop %rsi */ + 0x5d, /* 14: pop %rbp */ + 0x5b, /* 15: pop %rbx */ + 0xc3 /* 16: ret */ + }; + + static const BYTE unwind_info_1[] = + { + 1 | (UNW_FLAG_EHANDLER << 3), /* version + flags */ + 0x0a, /* prolog size */ + 6, /* opcode count */ + 0, /* frame reg */ + + 0x0a, UWOP(ALLOC_SMALL, 5), /* 0a: sub $0x30,%rsp */ + 0x06, UWOP(PUSH_NONVOL, r12), /* 06: push %r12 */ + 0x04, UWOP(PUSH_NONVOL, rdi), /* 04: push %rdi */ + 0x03, UWOP(PUSH_NONVOL, rsi), /* 03: push %rsi */ + 0x02, UWOP(PUSH_NONVOL, rbp), /* 02: push %rbp */ + 0x01, UWOP(PUSH_NONVOL, rbx), /* 01: push %rbx */ + + 0x00, 0x02, 0x00, 0x00, /* handler */ + 0x05, 0x06, 0x07, 0x08, /* data */ + }; + + static const struct results results_1[] = + { + /* offset rbp handler rip frame registers */ + { 0x00, 0x50, FALSE, 0x000, 0x000, { {rsp,0x008}, {-1,-1} }}, + { 0x01, 0x50, FALSE, 0x008, 0x000, { {rsp,0x010}, {rbx,0x000}, {-1,-1} }}, + { 0x02, 0x50, FALSE, 0x010, 0x000, { {rsp,0x018}, {rbx,0x008}, {rbp,0x000}, {-1,-1} }}, + { 0x03, 0x50, FALSE, 0x018, 0x000, { {rsp,0x020}, {rbx,0x010}, {rbp,0x008}, {rsi,0x000}, {-1,-1} }}, + { 0x04, 0x50, FALSE, 0x020, 0x000, { {rsp,0x028}, {rbx,0x018}, {rbp,0x010}, {rsi,0x008}, {rdi,0x000}, {-1,-1} }}, + { 0x06, 0x50, FALSE, 0x028, 0x000, { {rsp,0x030}, {rbx,0x020}, {rbp,0x018}, {rsi,0x010}, {rdi,0x008}, {r12,0x000}, {-1,-1} }}, + { 0x0a, 0x50, TRUE, 0x058, 0x000, { {rsp,0x060}, {rbx,0x050}, {rbp,0x048}, {rsi,0x040}, {rdi,0x038}, {r12,0x030}, {-1,-1} }}, + { 0x0c, 0x50, FALSE, 0x058, 0x000, { {rsp,0x060}, {rbx,0x050}, {rbp,0x048}, {rsi,0x040}, {rdi,0x038}, {r12,0x030}, {-1,-1} }}, + { 0x10, 0x50, FALSE, 0x028, 0x000, { {rsp,0x030}, {rbx,0x020}, {rbp,0x018}, {rsi,0x010}, {rdi,0x008}, {r12,0x000}, {-1,-1} }}, + { 0x12, 0x50, FALSE, 0x020, 0x000, { {rsp,0x028}, {rbx,0x018}, {rbp,0x010}, {rsi,0x008}, {rdi,0x000}, {-1,-1} }}, + { 0x13, 0x50, FALSE, 0x018, 0x000, { {rsp,0x020}, {rbx,0x010}, {rbp,0x008}, {rsi,0x000}, {-1,-1} }}, + { 0x14, 0x50, FALSE, 0x010, 0x000, { {rsp,0x018}, {rbx,0x008}, {rbp,0x000}, {-1,-1} }}, + { 0x15, 0x50, FALSE, 0x008, 0x000, { {rsp,0x010}, {rbx,0x000}, {-1,-1} }}, + { 0x16, 0x50, FALSE, 0x000, 0x000, { {rsp,0x008}, {-1,-1} }}, + }; + + static const struct unwind_test tests[] = + { + { function_0, sizeof(function_0), unwind_info_0, + results_0, sizeof(results_0)/sizeof(results_0[0]) }, + { function_1, sizeof(function_1), unwind_info_1, + results_1, sizeof(results_1)/sizeof(results_1[0]) } + }; + unsigned int i; + + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) + call_virtual_unwind( i, &tests[i] ); +} + +#endif /* __x86_64__ */ START_TEST(exception) { -#ifdef __i386__ HMODULE hntdll = GetModuleHandleA("ntdll.dll"); + code_mem = VirtualAlloc(NULL, 65536, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if(!code_mem) { + trace("VirtualAlloc failed\n"); + return; + } + pNtCurrentTeb = (void *)GetProcAddress( hntdll, "NtCurrentTeb" ); pNtGetContextThread = (void *)GetProcAddress( hntdll, "NtGetContextThread" ); pNtSetContextThread = (void *)GetProcAddress( hntdll, "NtSetContextThread" ); @@ -932,6 +1375,12 @@ START_TEST(exception) "RtlAddVectoredExceptionHandler" ); pRtlRemoveVectoredExceptionHandler = (void *)GetProcAddress( hntdll, "RtlRemoveVectoredExceptionHandler" ); + pNtQueryInformationProcess = (void*)GetProcAddress( hntdll, + "NtQueryInformationProcess" ); + pNtSetInformationProcess = (void*)GetProcAddress( hntdll, + "NtSetInformationProcess" ); + +#ifdef __i386__ if (!pNtCurrentTeb) { skip( "NtCurrentTeb not found\n" ); @@ -943,13 +1392,6 @@ START_TEST(exception) else skip("RtlAddVectoredExceptionHandler or RtlRemoveVectoredExceptionHandler not found\n"); - /* 1024 byte should be sufficient */ - code_mem = VirtualAlloc(NULL, 1024, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); - if(!code_mem) { - trace("VirtualAlloc failed\n"); - return; - } - my_argc = winetest_get_mainargs( &my_argv ); if (my_argc >= 4) { @@ -993,7 +1435,13 @@ START_TEST(exception) test_debugger(); test_simd_exceptions(); test_fpu_exceptions(); + test_dpe_exceptions(); + +#elif defined(__x86_64__) + + test_virtual_unwind(); - VirtualFree(code_mem, 1024, MEM_RELEASE); #endif + + VirtualFree(code_mem, 0, MEM_FREE); } diff --git a/rostests/winetests/ntdll/file.c b/rostests/winetests/ntdll/file.c index 164c2da2430..3d28d80342d 100644 --- a/rostests/winetests/ntdll/file.c +++ b/rostests/winetests/ntdll/file.c @@ -34,16 +34,24 @@ #include "wine/test.h" #include "winternl.h" +#include "winuser.h" #ifndef IO_COMPLETION_ALL_ACCESS #define IO_COMPLETION_ALL_ACCESS 0x001F0003 #endif -static NTSTATUS (WINAPI *pRtlFreeUnicodeString)( PUNICODE_STRING ); +static BOOL (WINAPI * pGetVolumePathNameW)(LPCWSTR, LPWSTR, DWORD); +static UINT (WINAPI *pGetSystemWow64DirectoryW)( LPWSTR, UINT ); + +static VOID (WINAPI *pRtlFreeUnicodeString)( PUNICODE_STRING ); static VOID (WINAPI *pRtlInitUnicodeString)( PUNICODE_STRING, LPCWSTR ); static BOOL (WINAPI *pRtlDosPathNameToNtPathName_U)( LPCWSTR, PUNICODE_STRING, PWSTR*, CURDIR* ); +static NTSTATUS (WINAPI *pRtlWow64EnableFsRedirectionEx)( ULONG, ULONG * ); + static NTSTATUS (WINAPI *pNtCreateMailslotFile)( PHANDLE, ULONG, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, ULONG, ULONG, ULONG, PLARGE_INTEGER ); +static NTSTATUS (WINAPI *pNtCreateFile)(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,PIO_STATUS_BLOCK,PLARGE_INTEGER,ULONG,ULONG,ULONG,ULONG,PVOID,ULONG); +static NTSTATUS (WINAPI *pNtOpenFile)(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,PIO_STATUS_BLOCK,ULONG,ULONG); static NTSTATUS (WINAPI *pNtDeleteFile)(POBJECT_ATTRIBUTES ObjectAttributes); static NTSTATUS (WINAPI *pNtReadFile)(HANDLE hFile, HANDLE hEvent, PIO_APC_ROUTINE apc, void* apc_user, @@ -54,6 +62,8 @@ static NTSTATUS (WINAPI *pNtWriteFile)(HANDLE hFile, HANDLE hEvent, PIO_STATUS_BLOCK io_status, const void* buffer, ULONG length, PLARGE_INTEGER offset, PULONG key); +static NTSTATUS (WINAPI *pNtCancelIoFile)(HANDLE hFile, PIO_STATUS_BLOCK io_status); +static NTSTATUS (WINAPI *pNtCancelIoFileEx)(HANDLE hFile, PIO_STATUS_BLOCK iosb, PIO_STATUS_BLOCK io_status); static NTSTATUS (WINAPI *pNtClose)( PHANDLE ); static NTSTATUS (WINAPI *pNtCreateIoCompletion)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, ULONG); @@ -62,6 +72,9 @@ static NTSTATUS (WINAPI *pNtQueryIoCompletion)(HANDLE, IO_COMPLETION_INFORMATION static NTSTATUS (WINAPI *pNtRemoveIoCompletion)(HANDLE, PULONG_PTR, PULONG_PTR, PIO_STATUS_BLOCK, PLARGE_INTEGER); static NTSTATUS (WINAPI *pNtSetIoCompletion)(HANDLE, ULONG_PTR, ULONG_PTR, NTSTATUS, ULONG); static NTSTATUS (WINAPI *pNtSetInformationFile)(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS); +static NTSTATUS (WINAPI *pNtQueryInformationFile)(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS); +static NTSTATUS (WINAPI *pNtQueryDirectoryFile)(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK, + PVOID,ULONG,FILE_INFORMATION_CLASS,BOOLEAN,PUNICODE_STRING,BOOLEAN); static inline BOOL is_signaled( HANDLE obj ) { @@ -140,6 +153,231 @@ static void WINAPI apc( void *arg, IO_STATUS_BLOCK *iosb, ULONG reserved ) ok( !reserved, "reserved is not 0: %x\n", reserved ); } +static void create_file_test(void) +{ + static const WCHAR systemrootW[] = {'\\','S','y','s','t','e','m','R','o','o','t', + '\\','f','a','i','l','i','n','g',0}; + NTSTATUS status; + HANDLE dir; + WCHAR path[MAX_PATH]; + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK io; + UNICODE_STRING nameW; + UINT len; + + len = GetCurrentDirectoryW( MAX_PATH, path ); + pRtlDosPathNameToNtPathName_U( path, &nameW, NULL, NULL ); + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = &nameW; + attr.Attributes = OBJ_CASE_INSENSITIVE; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + /* try various open modes and options on directories */ + status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN, FILE_DIRECTORY_FILE, NULL, 0 ); + ok( !status, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + CloseHandle( dir ); + + status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_CREATE, FILE_DIRECTORY_FILE, NULL, 0 ); + ok( status == STATUS_OBJECT_NAME_COLLISION || status == STATUS_ACCESS_DENIED, + "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + + status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN_IF, FILE_DIRECTORY_FILE, NULL, 0 ); + ok( !status, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + CloseHandle( dir ); + + status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_SUPERSEDE, FILE_DIRECTORY_FILE, NULL, 0 ); + ok( status == STATUS_INVALID_PARAMETER, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + + status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OVERWRITE, FILE_DIRECTORY_FILE, NULL, 0 ); + ok( status == STATUS_INVALID_PARAMETER, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + + status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OVERWRITE_IF, FILE_DIRECTORY_FILE, NULL, 0 ); + ok( status == STATUS_INVALID_PARAMETER, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + + status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN, 0, NULL, 0 ); + ok( !status, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + CloseHandle( dir ); + + status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_CREATE, 0, NULL, 0 ); + ok( status == STATUS_OBJECT_NAME_COLLISION || status == STATUS_ACCESS_DENIED, + "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + + status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN_IF, 0, NULL, 0 ); + ok( !status, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + CloseHandle( dir ); + + status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_SUPERSEDE, 0, NULL, 0 ); + ok( status == STATUS_OBJECT_NAME_COLLISION || status == STATUS_ACCESS_DENIED, + "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + + status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OVERWRITE, 0, NULL, 0 ); + ok( status == STATUS_OBJECT_NAME_COLLISION || status == STATUS_ACCESS_DENIED, + "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + + status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OVERWRITE_IF, 0, NULL, 0 ); + ok( status == STATUS_OBJECT_NAME_COLLISION || status == STATUS_ACCESS_DENIED, + "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + + pRtlFreeUnicodeString( &nameW ); + + pRtlInitUnicodeString( &nameW, systemrootW ); + attr.Length = sizeof(attr); + attr.RootDirectory = NULL; + attr.ObjectName = &nameW; + attr.Attributes = OBJ_CASE_INSENSITIVE; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + dir = NULL; + status = pNtCreateFile( &dir, FILE_APPEND_DATA, &attr, &io, NULL, FILE_ATTRIBUTE_NORMAL, 0, + FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 ); + todo_wine + ok( status == STATUS_INVALID_PARAMETER, + "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + pRtlFreeUnicodeString( &nameW ); +} + +static void open_file_test(void) +{ + NTSTATUS status; + HANDLE dir, root, handle; + WCHAR path[MAX_PATH]; + BYTE data[8192]; + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK io; + UNICODE_STRING nameW; + UINT i, len; + BOOL restart = TRUE; + + len = GetWindowsDirectoryW( path, MAX_PATH ); + pRtlDosPathNameToNtPathName_U( path, &nameW, NULL, NULL ); + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = &nameW; + attr.Attributes = OBJ_CASE_INSENSITIVE; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + status = pNtOpenFile( &dir, GENERIC_READ, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_DIRECTORY_FILE ); + ok( !status, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + pRtlFreeUnicodeString( &nameW ); + + path[3] = 0; /* root of the drive */ + pRtlDosPathNameToNtPathName_U( path, &nameW, NULL, NULL ); + status = pNtOpenFile( &root, GENERIC_READ, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_DIRECTORY_FILE ); + ok( !status, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + pRtlFreeUnicodeString( &nameW ); + + /* test opening system dir with RootDirectory set to windows dir */ + GetSystemDirectoryW( path, MAX_PATH ); + while (path[len] == '\\') len++; + nameW.Buffer = path + len; + nameW.Length = lstrlenW(path + len) * sizeof(WCHAR); + attr.RootDirectory = dir; + status = pNtOpenFile( &handle, GENERIC_READ, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_DIRECTORY_FILE ); + ok( !status, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + CloseHandle( handle ); + + /* try uppercase name */ + for (i = len; path[i]; i++) if (path[i] >= 'a' && path[i] <= 'z') path[i] -= 'a' - 'A'; + status = pNtOpenFile( &handle, GENERIC_READ, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_DIRECTORY_FILE ); + ok( !status, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + CloseHandle( handle ); + + /* try with leading backslash */ + nameW.Buffer--; + nameW.Length += sizeof(WCHAR); + status = pNtOpenFile( &handle, GENERIC_READ, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_DIRECTORY_FILE ); + ok( status == STATUS_INVALID_PARAMETER || + status == STATUS_OBJECT_NAME_INVALID || + status == STATUS_OBJECT_PATH_SYNTAX_BAD, + "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + if (!status) CloseHandle( handle ); + + /* try with empty name */ + nameW.Length = 0; + status = pNtOpenFile( &handle, GENERIC_READ, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_DIRECTORY_FILE ); + ok( !status, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + CloseHandle( handle ); + + /* try open by file id */ + + while (!pNtQueryDirectoryFile( dir, NULL, NULL, NULL, &io, data, sizeof(data), + FileIdBothDirectoryInformation, FALSE, NULL, restart )) + { + FILE_ID_BOTH_DIRECTORY_INFORMATION *info = (FILE_ID_BOTH_DIRECTORY_INFORMATION *)data; + + restart = FALSE; + for (;;) + { + if (!info->FileId.QuadPart) goto next; + nameW.Buffer = (WCHAR *)&info->FileId; + nameW.Length = sizeof(info->FileId); + info->FileName[info->FileNameLength/sizeof(WCHAR)] = 0; + attr.RootDirectory = dir; + status = pNtOpenFile( &handle, GENERIC_READ, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN_BY_FILE_ID | + ((info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? FILE_DIRECTORY_FILE : 0) ); + ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED || status == STATUS_NOT_IMPLEMENTED, + "open %s failed %x\n", wine_dbgstr_w(info->FileName), status ); + if (status == STATUS_NOT_IMPLEMENTED) + { + win_skip( "FILE_OPEN_BY_FILE_ID not supported\n" ); + break; + } + if (!status) + { + FILE_ALL_INFORMATION all_info; + + if (!pNtQueryInformationFile( handle, &io, &all_info, sizeof(all_info), FileAllInformation )) + { + /* check that it's the same file */ + ok( info->EndOfFile.QuadPart == all_info.StandardInformation.EndOfFile.QuadPart, + "mismatched file size for %s\n", wine_dbgstr_w(info->FileName)); + ok( info->LastWriteTime.QuadPart == all_info.BasicInformation.LastWriteTime.QuadPart, + "mismatched write time for %s\n", wine_dbgstr_w(info->FileName)); + } + CloseHandle( handle ); + + /* try same thing from drive root */ + attr.RootDirectory = root; + status = pNtOpenFile( &handle, GENERIC_READ, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN_BY_FILE_ID | + ((info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? FILE_DIRECTORY_FILE : 0) ); + ok( status == STATUS_SUCCESS || status == STATUS_NOT_IMPLEMENTED, + "open %s failed %x\n", wine_dbgstr_w(info->FileName), status ); + if (!status) CloseHandle( handle ); + } + next: + if (!info->NextEntryOffset) break; + info = (FILE_ID_BOTH_DIRECTORY_INFORMATION *)((char *)info + info->NextEntryOffset); + } + } + + CloseHandle( dir ); + CloseHandle( root ); +} + static void delete_file_test(void) { NTSTATUS ret; @@ -207,7 +445,7 @@ static void read_file_test(void) const char text[] = "foobar"; HANDLE handle, read, write; NTSTATUS status; - IO_STATUS_BLOCK iosb; + IO_STATUS_BLOCK iosb, iosb2; DWORD written; int apc_count = 0; char buffer[128]; @@ -355,6 +593,112 @@ static void read_file_test(void) ok( apc_count == 1, "apc was not called\n" ); CloseHandle( read ); + if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return; + ok(DuplicateHandle(GetCurrentProcess(), read, GetCurrentProcess(), &handle, 0, TRUE, DUPLICATE_SAME_ACCESS), + "Failed to duplicate handle: %d\n", GetLastError()); + + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); + ok( status == STATUS_PENDING, "wrong status %x\n", status ); + ok( !is_signaled( event ), "event is signaled\n" ); + ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); + ok( !apc_count, "apc was called\n" ); + /* Cancel by other handle */ + status = pNtCancelIoFile( read, &iosb2 ); + ok(status == STATUS_SUCCESS, "failed to cancel by different handle: %x\n", status); + Sleep(1); /* FIXME: needed for wine to run the i/o apc */ + ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information ); + ok( is_signaled( event ), "event is signaled\n" ); + todo_wine ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( apc_count == 1, "apc was not called\n" ); + + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); + ok( status == STATUS_PENDING, "wrong status %x\n", status ); + ok( !is_signaled( event ), "event is signaled\n" ); + ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); + ok( !apc_count, "apc was called\n" ); + /* Close queued handle */ + CloseHandle( read ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); + status = pNtCancelIoFile( read, &iosb2 ); + ok(status == STATUS_INVALID_HANDLE, "cancelled by closed handle?\n"); + status = pNtCancelIoFile( handle, &iosb2 ); + ok(status == STATUS_SUCCESS, "failed to cancel: %x\n", status); + Sleep(1); /* FIXME: needed for wine to run the i/o apc */ + ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information ); + ok( is_signaled( event ), "event is signaled\n" ); + todo_wine ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( apc_count == 1, "apc was not called\n" ); + CloseHandle( handle ); + CloseHandle( write ); + + if (pNtCancelIoFileEx) + { + /* Basic Cancel Ex */ + if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return; + + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); + ok( status == STATUS_PENDING, "wrong status %x\n", status ); + ok( !is_signaled( event ), "event is signaled\n" ); + ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); + ok( !apc_count, "apc was called\n" ); + status = pNtCancelIoFileEx( read, &iosb, &iosb2 ); + ok(status == STATUS_SUCCESS, "Failed to cancel I/O\n"); + Sleep(1); /* FIXME: needed for wine to run the i/o apc */ + ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information ); + ok( is_signaled( event ), "event is signaled\n" ); + todo_wine ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( apc_count == 1, "apc was not called\n" ); + + /* Duplicate iosb */ + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); + ok( status == STATUS_PENDING, "wrong status %x\n", status ); + ok( !is_signaled( event ), "event is signaled\n" ); + ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); + ok( !apc_count, "apc was called\n" ); + status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); + ok( status == STATUS_PENDING, "wrong status %x\n", status ); + ok( !is_signaled( event ), "event is signaled\n" ); + ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); + ok( !apc_count, "apc was called\n" ); + status = pNtCancelIoFileEx( read, &iosb, &iosb2 ); + ok(status == STATUS_SUCCESS, "Failed to cancel I/O\n"); + Sleep(1); /* FIXME: needed for wine to run the i/o apc */ + ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information ); + ok( is_signaled( event ), "event is signaled\n" ); + todo_wine ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( apc_count == 2, "apc was not called\n" ); + + CloseHandle( read ); + CloseHandle( write ); + } + /* now try a real file */ if (!(handle = create_temp_file( FILE_FLAG_OVERLAPPED ))) return; apc_count = 0; @@ -362,8 +706,8 @@ static void read_file_test(void) iosb.Information = 0xdeadbeef; offset.QuadPart = 0; ResetEvent( event ); - pNtWriteFile( handle, event, apc, &apc_count, &iosb, text, strlen(text), &offset, NULL ); - ok( status == STATUS_PENDING, "wrong status %x\n", status ); + status = pNtWriteFile( handle, event, apc, &apc_count, &iosb, text, strlen(text), &offset, NULL ); + ok( status == STATUS_SUCCESS || status == STATUS_PENDING, "wrong status %x\n", status ); ok( U(iosb).Status == STATUS_SUCCESS, "wrong status %x\n", U(iosb).Status ); ok( iosb.Information == strlen(text), "wrong info %lu\n", iosb.Information ); ok( is_signaled( event ), "event is signaled\n" ); @@ -420,8 +764,9 @@ static void read_file_test(void) U(iosb).Status = 0xdeadbabe; iosb.Information = 0xdeadbeef; offset.QuadPart = 0; - pNtWriteFile( handle, event, apc, &apc_count, &iosb, text, strlen(text), &offset, NULL ); + status = pNtWriteFile( handle, event, apc, &apc_count, &iosb, text, strlen(text), &offset, NULL ); ok( status == STATUS_END_OF_FILE || + status == STATUS_SUCCESS || status == STATUS_PENDING, /* vista */ "wrong status %x\n", status ); ok( U(iosb).Status == STATUS_SUCCESS, "wrong status %x\n", U(iosb).Status ); @@ -678,6 +1023,138 @@ static void test_iocp_fileio(HANDLE h) CloseHandle( hPipeClt ); } +static void test_file_basic_information(void) +{ + IO_STATUS_BLOCK io; + FILE_BASIC_INFORMATION fbi; + HANDLE h; + int res; + int attrib_mask = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NORMAL; + + if (!(h = create_temp_file(0))) return; + + /* Check default first */ + memset(&fbi, 0, sizeof(fbi)); + res = pNtQueryInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation); + ok ( res == STATUS_SUCCESS, "can't get attributes, res %x\n", res); + ok ( (fbi.FileAttributes & FILE_ATTRIBUTE_ARCHIVE) == FILE_ATTRIBUTE_ARCHIVE, + "attribute %x not expected\n", fbi.FileAttributes ); + + /* Then SYSTEM */ + /* Clear fbi to avoid setting times */ + memset(&fbi, 0, sizeof(fbi)); + fbi.FileAttributes = FILE_ATTRIBUTE_SYSTEM; + res = pNtSetInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation); + ok ( res == STATUS_SUCCESS, "can't set system attribute\n"); + + memset(&fbi, 0, sizeof(fbi)); + res = pNtQueryInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation); + ok ( res == STATUS_SUCCESS, "can't get attributes\n"); + todo_wine ok ( (fbi.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_SYSTEM, "attribute %x not FILE_ATTRIBUTE_SYSTEM\n", fbi.FileAttributes ); + + /* Then HIDDEN */ + memset(&fbi, 0, sizeof(fbi)); + fbi.FileAttributes = FILE_ATTRIBUTE_HIDDEN; + res = pNtSetInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation); + ok ( res == STATUS_SUCCESS, "can't set system attribute\n"); + + memset(&fbi, 0, sizeof(fbi)); + res = pNtQueryInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation); + ok ( res == STATUS_SUCCESS, "can't get attributes\n"); + todo_wine ok ( (fbi.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_HIDDEN, "attribute %x not FILE_ATTRIBUTE_HIDDEN\n", fbi.FileAttributes ); + + /* Check NORMAL last of all (to make sure we can clear attributes) */ + memset(&fbi, 0, sizeof(fbi)); + fbi.FileAttributes = FILE_ATTRIBUTE_NORMAL; + res = pNtSetInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation); + ok ( res == STATUS_SUCCESS, "can't set normal attribute\n"); + + memset(&fbi, 0, sizeof(fbi)); + res = pNtQueryInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation); + ok ( res == STATUS_SUCCESS, "can't get attributes\n"); + todo_wine ok ( (fbi.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_NORMAL, "attribute %x not 0\n", fbi.FileAttributes ); + + CloseHandle( h ); +} + +static void test_file_all_information(void) +{ + IO_STATUS_BLOCK io; + /* FileAllInformation, like FileNameInformation, has a variable-length pathname + * buffer at the end. Vista objects with STATUS_BUFFER_OVERFLOW if you + * don't leave enough room there. + */ + struct { + FILE_ALL_INFORMATION fai; + WCHAR buf[256]; + } fai_buf; + HANDLE h; + int res; + int attrib_mask = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NORMAL; + + if (!(h = create_temp_file(0))) return; + + /* Check default first */ + res = pNtQueryInformationFile(h, &io, &fai_buf.fai, sizeof fai_buf, FileAllInformation); + ok ( res == STATUS_SUCCESS, "can't get attributes, res %x\n", res); + ok ( (fai_buf.fai.BasicInformation.FileAttributes & FILE_ATTRIBUTE_ARCHIVE) == FILE_ATTRIBUTE_ARCHIVE, + "attribute %x not expected\n", fai_buf.fai.BasicInformation.FileAttributes ); + + /* Then SYSTEM */ + /* Clear fbi to avoid setting times */ + memset(&fai_buf.fai.BasicInformation, 0, sizeof(fai_buf.fai.BasicInformation)); + fai_buf.fai.BasicInformation.FileAttributes = FILE_ATTRIBUTE_SYSTEM; + res = pNtSetInformationFile(h, &io, &fai_buf.fai, sizeof fai_buf, FileAllInformation); + ok ( res == STATUS_INVALID_INFO_CLASS || res == STATUS_NOT_IMPLEMENTED, "shouldn't be able to set FileAllInformation, res %x\n", res); + res = pNtSetInformationFile(h, &io, &fai_buf.fai.BasicInformation, sizeof fai_buf.fai.BasicInformation, FileBasicInformation); + ok ( res == STATUS_SUCCESS, "can't set system attribute\n"); + + memset(&fai_buf.fai, 0, sizeof(fai_buf.fai)); + res = pNtQueryInformationFile(h, &io, &fai_buf.fai, sizeof fai_buf, FileAllInformation); + ok ( res == STATUS_SUCCESS, "can't get attributes, res %x\n", res); + todo_wine ok ( (fai_buf.fai.BasicInformation.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_SYSTEM, "attribute %x not FILE_ATTRIBUTE_SYSTEM\n", fai_buf.fai.BasicInformation.FileAttributes ); + + /* Then HIDDEN */ + memset(&fai_buf.fai.BasicInformation, 0, sizeof(fai_buf.fai.BasicInformation)); + fai_buf.fai.BasicInformation.FileAttributes = FILE_ATTRIBUTE_HIDDEN; + res = pNtSetInformationFile(h, &io, &fai_buf.fai.BasicInformation, sizeof fai_buf.fai.BasicInformation, FileBasicInformation); + ok ( res == STATUS_SUCCESS, "can't set system attribute\n"); + + memset(&fai_buf.fai, 0, sizeof(fai_buf.fai)); + res = pNtQueryInformationFile(h, &io, &fai_buf.fai, sizeof fai_buf, FileAllInformation); + ok ( res == STATUS_SUCCESS, "can't get attributes\n"); + todo_wine ok ( (fai_buf.fai.BasicInformation.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_HIDDEN, "attribute %x not FILE_ATTRIBUTE_HIDDEN\n", fai_buf.fai.BasicInformation.FileAttributes ); + + /* Check NORMAL last of all (to make sure we can clear attributes) */ + memset(&fai_buf.fai.BasicInformation, 0, sizeof(fai_buf.fai.BasicInformation)); + fai_buf.fai.BasicInformation.FileAttributes = FILE_ATTRIBUTE_NORMAL; + res = pNtSetInformationFile(h, &io, &fai_buf.fai.BasicInformation, sizeof fai_buf.fai.BasicInformation, FileBasicInformation); + ok ( res == STATUS_SUCCESS, "can't set normal attribute\n"); + + memset(&fai_buf.fai, 0, sizeof(fai_buf.fai)); + res = pNtQueryInformationFile(h, &io, &fai_buf.fai, sizeof fai_buf, FileAllInformation); + ok ( res == STATUS_SUCCESS, "can't get attributes\n"); + todo_wine ok ( (fai_buf.fai.BasicInformation.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_NORMAL, "attribute %x not FILE_ATTRIBUTE_NORMAL\n", fai_buf.fai.BasicInformation.FileAttributes ); + + CloseHandle( h ); +} + +static void test_file_both_information(void) +{ + IO_STATUS_BLOCK io; + FILE_BOTH_DIR_INFORMATION fbi; + HANDLE h; + int res; + + if (!(h = create_temp_file(0))) return; + + memset(&fbi, 0, sizeof(fbi)); + res = pNtQueryInformationFile(h, &io, &fbi, sizeof fbi, FileBothDirectoryInformation); + ok ( res == STATUS_INVALID_INFO_CLASS || res == STATUS_NOT_IMPLEMENTED, "shouldn't be able to query FileBothDirectoryInformation, res %x\n", res); + + CloseHandle( h ); +} + static void test_iocompletion(void) { HANDLE h = INVALID_HANDLE_VALUE; @@ -696,8 +1173,273 @@ static void test_iocompletion(void) } } +static void test_file_name_information(void) +{ + WCHAR *file_name, *volume_prefix, *expected; + FILE_NAME_INFORMATION *info; + ULONG old_redir = 1, tmp; + UINT file_name_size; + IO_STATUS_BLOCK io; + UINT info_size; + HRESULT hr; + HANDLE h; + UINT len; + + /* GetVolumePathName is not present before w2k */ + if (!pGetVolumePathNameW) { + win_skip("GetVolumePathNameW not found\n"); + return; + } + + file_name_size = GetSystemDirectoryW( NULL, 0 ); + file_name = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*file_name) ); + volume_prefix = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*volume_prefix) ); + expected = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*volume_prefix) ); + + len = GetSystemDirectoryW( file_name, file_name_size ); + ok(len == file_name_size - 1, + "GetSystemDirectoryW returned %u, expected %u.\n", + len, file_name_size - 1); + + len = pGetVolumePathNameW( file_name, volume_prefix, file_name_size ); + ok(len, "GetVolumePathNameW failed.\n"); + + len = lstrlenW( volume_prefix ); + if (len && volume_prefix[len - 1] == '\\') --len; + memcpy( expected, file_name + len, (file_name_size - len - 1) * sizeof(WCHAR) ); + expected[file_name_size - len - 1] = '\0'; + + /* A bit more than we actually need, but it keeps the calculation simple. */ + info_size = sizeof(*info) + (file_name_size * sizeof(WCHAR)); + info = HeapAlloc( GetProcessHeap(), 0, info_size ); + + if (pRtlWow64EnableFsRedirectionEx) pRtlWow64EnableFsRedirectionEx( TRUE, &old_redir ); + h = CreateFileW( file_name, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + if (pRtlWow64EnableFsRedirectionEx) pRtlWow64EnableFsRedirectionEx( old_redir, &tmp ); + ok(h != INVALID_HANDLE_VALUE, "Failed to open file.\n"); + + hr = pNtQueryInformationFile( h, &io, info, sizeof(*info) - 1, FileNameInformation ); + ok(hr == STATUS_INFO_LENGTH_MISMATCH, "NtQueryInformationFile returned %#x.\n", hr); + + memset( info, 0xcc, info_size ); + hr = pNtQueryInformationFile( h, &io, info, sizeof(*info), FileNameInformation ); + ok(hr == STATUS_BUFFER_OVERFLOW, "NtQueryInformationFile returned %#x, expected %#x.\n", + hr, STATUS_BUFFER_OVERFLOW); + ok(U(io).Status == STATUS_BUFFER_OVERFLOW, "io.Status is %#x, expected %#x.\n", + U(io).Status, STATUS_BUFFER_OVERFLOW); + ok(info->FileNameLength == lstrlenW( expected ) * sizeof(WCHAR), "info->FileNameLength is %u\n", info->FileNameLength); + ok(info->FileName[2] == 0xcccc, "info->FileName[2] is %#x, expected 0xcccc.\n", info->FileName[2]); + ok(CharLowerW((LPWSTR)(UINT_PTR)info->FileName[1]) == CharLowerW((LPWSTR)(UINT_PTR)expected[1]), + "info->FileName[1] is %p, expected %p.\n", + CharLowerW((LPWSTR)(UINT_PTR)info->FileName[1]), CharLowerW((LPWSTR)(UINT_PTR)expected[1])); + ok(io.Information == sizeof(*info), "io.Information is %lu\n", io.Information); + + memset( info, 0xcc, info_size ); + hr = pNtQueryInformationFile( h, &io, info, info_size, FileNameInformation ); + ok(hr == STATUS_SUCCESS, "NtQueryInformationFile returned %#x, expected %#x.\n", hr, STATUS_SUCCESS); + ok(U(io).Status == STATUS_SUCCESS, "io.Status is %#x, expected %#x.\n", U(io).Status, STATUS_SUCCESS); + ok(info->FileNameLength == lstrlenW( expected ) * sizeof(WCHAR), "info->FileNameLength is %u\n", info->FileNameLength); + ok(info->FileName[info->FileNameLength / sizeof(WCHAR)] == 0xcccc, "info->FileName[len] is %#x, expected 0xcccc.\n", + info->FileName[info->FileNameLength / sizeof(WCHAR)]); + info->FileName[info->FileNameLength / sizeof(WCHAR)] = '\0'; + ok(!lstrcmpiW( info->FileName, expected ), "info->FileName is %s, expected %s.\n", + wine_dbgstr_w( info->FileName ), wine_dbgstr_w( expected )); + ok(io.Information == FIELD_OFFSET(FILE_NAME_INFORMATION, FileName) + info->FileNameLength, + "io.Information is %lu, expected %u.\n", + io.Information, FIELD_OFFSET(FILE_NAME_INFORMATION, FileName) + info->FileNameLength); + + CloseHandle( h ); + HeapFree( GetProcessHeap(), 0, info ); + HeapFree( GetProcessHeap(), 0, expected ); + HeapFree( GetProcessHeap(), 0, volume_prefix ); + + if (old_redir || !pGetSystemWow64DirectoryW || !(file_name_size = pGetSystemWow64DirectoryW( NULL, 0 ))) + { + skip("Not running on WoW64, skipping test.\n"); + HeapFree( GetProcessHeap(), 0, file_name ); + return; + } + + h = CreateFileW( file_name, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok(h != INVALID_HANDLE_VALUE, "Failed to open file.\n"); + HeapFree( GetProcessHeap(), 0, file_name ); + + file_name = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*file_name) ); + volume_prefix = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*volume_prefix) ); + expected = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*expected) ); + + len = pGetSystemWow64DirectoryW( file_name, file_name_size ); + ok(len == file_name_size - 1, + "GetSystemWow64DirectoryW returned %u, expected %u.\n", + len, file_name_size - 1); + + len = pGetVolumePathNameW( file_name, volume_prefix, file_name_size ); + ok(len, "GetVolumePathNameW failed.\n"); + + len = lstrlenW( volume_prefix ); + if (len && volume_prefix[len - 1] == '\\') --len; + memcpy( expected, file_name + len, (file_name_size - len - 1) * sizeof(WCHAR) ); + expected[file_name_size - len - 1] = '\0'; + + info_size = sizeof(*info) + (file_name_size * sizeof(WCHAR)); + info = HeapAlloc( GetProcessHeap(), 0, info_size ); + + memset( info, 0xcc, info_size ); + hr = pNtQueryInformationFile( h, &io, info, info_size, FileNameInformation ); + ok(hr == STATUS_SUCCESS, "NtQueryInformationFile returned %#x, expected %#x.\n", hr, STATUS_SUCCESS); + info->FileName[info->FileNameLength / sizeof(WCHAR)] = '\0'; + ok(!lstrcmpiW( info->FileName, expected ), "info->FileName is %s, expected %s.\n", + wine_dbgstr_w( info->FileName ), wine_dbgstr_w( expected )); + + CloseHandle( h ); + HeapFree( GetProcessHeap(), 0, info ); + HeapFree( GetProcessHeap(), 0, expected ); + HeapFree( GetProcessHeap(), 0, volume_prefix ); + HeapFree( GetProcessHeap(), 0, file_name ); +} + +static void test_file_all_name_information(void) +{ + WCHAR *file_name, *volume_prefix, *expected; + FILE_ALL_INFORMATION *info; + ULONG old_redir = 1, tmp; + UINT file_name_size; + IO_STATUS_BLOCK io; + UINT info_size; + HRESULT hr; + HANDLE h; + UINT len; + + /* GetVolumePathName is not present before w2k */ + if (!pGetVolumePathNameW) { + win_skip("GetVolumePathNameW not found\n"); + return; + } + + file_name_size = GetSystemDirectoryW( NULL, 0 ); + file_name = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*file_name) ); + volume_prefix = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*volume_prefix) ); + expected = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*volume_prefix) ); + + len = GetSystemDirectoryW( file_name, file_name_size ); + ok(len == file_name_size - 1, + "GetSystemDirectoryW returned %u, expected %u.\n", + len, file_name_size - 1); + + len = pGetVolumePathNameW( file_name, volume_prefix, file_name_size ); + ok(len, "GetVolumePathNameW failed.\n"); + + len = lstrlenW( volume_prefix ); + if (len && volume_prefix[len - 1] == '\\') --len; + memcpy( expected, file_name + len, (file_name_size - len - 1) * sizeof(WCHAR) ); + expected[file_name_size - len - 1] = '\0'; + + /* A bit more than we actually need, but it keeps the calculation simple. */ + info_size = sizeof(*info) + (file_name_size * sizeof(WCHAR)); + info = HeapAlloc( GetProcessHeap(), 0, info_size ); + + if (pRtlWow64EnableFsRedirectionEx) pRtlWow64EnableFsRedirectionEx( TRUE, &old_redir ); + h = CreateFileW( file_name, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + if (pRtlWow64EnableFsRedirectionEx) pRtlWow64EnableFsRedirectionEx( old_redir, &tmp ); + ok(h != INVALID_HANDLE_VALUE, "Failed to open file.\n"); + + hr = pNtQueryInformationFile( h, &io, info, sizeof(*info) - 1, FileAllInformation ); + ok(hr == STATUS_INFO_LENGTH_MISMATCH, "NtQueryInformationFile returned %#x, expected %#x.\n", + hr, STATUS_INFO_LENGTH_MISMATCH); + + memset( info, 0xcc, info_size ); + hr = pNtQueryInformationFile( h, &io, info, sizeof(*info), FileAllInformation ); + ok(hr == STATUS_BUFFER_OVERFLOW, "NtQueryInformationFile returned %#x, expected %#x.\n", + hr, STATUS_BUFFER_OVERFLOW); + ok(U(io).Status == STATUS_BUFFER_OVERFLOW, "io.Status is %#x, expected %#x.\n", + U(io).Status, STATUS_BUFFER_OVERFLOW); + ok(info->NameInformation.FileNameLength == lstrlenW( expected ) * sizeof(WCHAR), + "info->NameInformation.FileNameLength is %u\n", info->NameInformation.FileNameLength ); + ok(info->NameInformation.FileName[2] == 0xcccc, + "info->NameInformation.FileName[2] is %#x, expected 0xcccc.\n", info->NameInformation.FileName[2]); + ok(CharLowerW((LPWSTR)(UINT_PTR)info->NameInformation.FileName[1]) == CharLowerW((LPWSTR)(UINT_PTR)expected[1]), + "info->NameInformation.FileName[1] is %p, expected %p.\n", + CharLowerW((LPWSTR)(UINT_PTR)info->NameInformation.FileName[1]), CharLowerW((LPWSTR)(UINT_PTR)expected[1])); + ok(io.Information == sizeof(*info), "io.Information is %lu\n", io.Information); + + memset( info, 0xcc, info_size ); + hr = pNtQueryInformationFile( h, &io, info, info_size, FileAllInformation ); + ok(hr == STATUS_SUCCESS, "NtQueryInformationFile returned %#x, expected %#x.\n", hr, STATUS_SUCCESS); + ok(U(io).Status == STATUS_SUCCESS, "io.Status is %#x, expected %#x.\n", U(io).Status, STATUS_SUCCESS); + ok(info->NameInformation.FileNameLength == lstrlenW( expected ) * sizeof(WCHAR), + "info->NameInformation.FileNameLength is %u\n", info->NameInformation.FileNameLength ); + ok(info->NameInformation.FileName[info->NameInformation.FileNameLength / sizeof(WCHAR)] == 0xcccc, + "info->NameInformation.FileName[len] is %#x, expected 0xcccc.\n", + info->NameInformation.FileName[info->NameInformation.FileNameLength / sizeof(WCHAR)]); + info->NameInformation.FileName[info->NameInformation.FileNameLength / sizeof(WCHAR)] = '\0'; + ok(!lstrcmpiW( info->NameInformation.FileName, expected ), + "info->NameInformation.FileName is %s, expected %s.\n", + wine_dbgstr_w( info->NameInformation.FileName ), wine_dbgstr_w( expected )); + ok(io.Information == FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + + info->NameInformation.FileNameLength, + "io.Information is %lu\n", io.Information ); + + CloseHandle( h ); + HeapFree( GetProcessHeap(), 0, info ); + HeapFree( GetProcessHeap(), 0, expected ); + HeapFree( GetProcessHeap(), 0, volume_prefix ); + + if (old_redir || !pGetSystemWow64DirectoryW || !(file_name_size = pGetSystemWow64DirectoryW( NULL, 0 ))) + { + skip("Not running on WoW64, skipping test.\n"); + HeapFree( GetProcessHeap(), 0, file_name ); + return; + } + + h = CreateFileW( file_name, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok(h != INVALID_HANDLE_VALUE, "Failed to open file.\n"); + HeapFree( GetProcessHeap(), 0, file_name ); + + file_name = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*file_name) ); + volume_prefix = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*volume_prefix) ); + expected = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*expected) ); + + len = pGetSystemWow64DirectoryW( file_name, file_name_size ); + ok(len == file_name_size - 1, + "GetSystemWow64DirectoryW returned %u, expected %u.\n", + len, file_name_size - 1); + + len = pGetVolumePathNameW( file_name, volume_prefix, file_name_size ); + ok(len, "GetVolumePathNameW failed.\n"); + + len = lstrlenW( volume_prefix ); + if (len && volume_prefix[len - 1] == '\\') --len; + memcpy( expected, file_name + len, (file_name_size - len - 1) * sizeof(WCHAR) ); + expected[file_name_size - len - 1] = '\0'; + + info_size = sizeof(*info) + (file_name_size * sizeof(WCHAR)); + info = HeapAlloc( GetProcessHeap(), 0, info_size ); + + memset( info, 0xcc, info_size ); + hr = pNtQueryInformationFile( h, &io, info, info_size, FileAllInformation ); + ok(hr == STATUS_SUCCESS, "NtQueryInformationFile returned %#x, expected %#x.\n", hr, STATUS_SUCCESS); + info->NameInformation.FileName[info->NameInformation.FileNameLength / sizeof(WCHAR)] = '\0'; + ok(!lstrcmpiW( info->NameInformation.FileName, expected ), "info->NameInformation.FileName is %s, expected %s.\n", + wine_dbgstr_w( info->NameInformation.FileName ), wine_dbgstr_w( expected )); + + CloseHandle( h ); + HeapFree( GetProcessHeap(), 0, info ); + HeapFree( GetProcessHeap(), 0, expected ); + HeapFree( GetProcessHeap(), 0, volume_prefix ); + HeapFree( GetProcessHeap(), 0, file_name ); +} + START_TEST(file) { + HMODULE hkernel32 = GetModuleHandleA("kernel32.dll"); HMODULE hntdll = GetModuleHandleA("ntdll.dll"); if (!hntdll) { @@ -705,13 +1447,21 @@ START_TEST(file) return; } + pGetVolumePathNameW = (void *)GetProcAddress(hkernel32, "GetVolumePathNameW"); + pGetSystemWow64DirectoryW = (void *)GetProcAddress(hkernel32, "GetSystemWow64DirectoryW"); + pRtlFreeUnicodeString = (void *)GetProcAddress(hntdll, "RtlFreeUnicodeString"); pRtlInitUnicodeString = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString"); pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(hntdll, "RtlDosPathNameToNtPathName_U"); + pRtlWow64EnableFsRedirectionEx = (void *)GetProcAddress(hntdll, "RtlWow64EnableFsRedirectionEx"); pNtCreateMailslotFile = (void *)GetProcAddress(hntdll, "NtCreateMailslotFile"); + pNtCreateFile = (void *)GetProcAddress(hntdll, "NtCreateFile"); + pNtOpenFile = (void *)GetProcAddress(hntdll, "NtOpenFile"); pNtDeleteFile = (void *)GetProcAddress(hntdll, "NtDeleteFile"); pNtReadFile = (void *)GetProcAddress(hntdll, "NtReadFile"); pNtWriteFile = (void *)GetProcAddress(hntdll, "NtWriteFile"); + pNtCancelIoFile = (void *)GetProcAddress(hntdll, "NtCancelIoFile"); + pNtCancelIoFileEx = (void *)GetProcAddress(hntdll, "NtCancelIoFileEx"); pNtClose = (void *)GetProcAddress(hntdll, "NtClose"); pNtCreateIoCompletion = (void *)GetProcAddress(hntdll, "NtCreateIoCompletion"); pNtOpenIoCompletion = (void *)GetProcAddress(hntdll, "NtOpenIoCompletion"); @@ -719,9 +1469,18 @@ START_TEST(file) pNtRemoveIoCompletion = (void *)GetProcAddress(hntdll, "NtRemoveIoCompletion"); pNtSetIoCompletion = (void *)GetProcAddress(hntdll, "NtSetIoCompletion"); pNtSetInformationFile = (void *)GetProcAddress(hntdll, "NtSetInformationFile"); + pNtQueryInformationFile = (void *)GetProcAddress(hntdll, "NtQueryInformationFile"); + pNtQueryDirectoryFile = (void *)GetProcAddress(hntdll, "NtQueryDirectoryFile"); + create_file_test(); + open_file_test(); delete_file_test(); read_file_test(); nt_mailslot_test(); test_iocompletion(); + test_file_basic_information(); + test_file_all_information(); + test_file_both_information(); + test_file_name_information(); + test_file_all_name_information(); } diff --git a/rostests/winetests/ntdll/ntdll.rbuild b/rostests/winetests/ntdll/ntdll.rbuild index 448d93c0c0c..aba50d21ebe 100644 --- a/rostests/winetests/ntdll/ntdll.rbuild +++ b/rostests/winetests/ntdll/ntdll.rbuild @@ -4,8 +4,10 @@ . ntdll + user32 atom.c change.c + directory.c env.c error.c exception.c diff --git a/rostests/winetests/ntdll/om.c b/rostests/winetests/ntdll/om.c index d5cf158a80b..d052c359463 100644 --- a/rostests/winetests/ntdll/om.c +++ b/rostests/winetests/ntdll/om.c @@ -44,6 +44,7 @@ static NTSTATUS (WINAPI *pNtOpenDirectoryObject)(PHANDLE, ACCESS_MASK, POBJECT_A static NTSTATUS (WINAPI *pNtCreateDirectoryObject)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); static NTSTATUS (WINAPI *pNtOpenSymbolicLinkObject)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); static NTSTATUS (WINAPI *pNtCreateSymbolicLinkObject)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PUNICODE_STRING); +static NTSTATUS (WINAPI *pNtQueryObject)(HANDLE,OBJECT_INFORMATION_CLASS,PVOID,ULONG,PULONG); static void test_case_sensitive (void) @@ -617,6 +618,72 @@ static void test_symboliclink(void) pNtClose(dir); } +static void test_query_object(void) +{ + static const WCHAR name[] = {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s', + '\\','t','e','s','t','_','e','v','e','n','t'}; + HANDLE handle; + char buffer[1024]; + NTSTATUS status; + ULONG len; + UNICODE_STRING *str; + char dir[MAX_PATH]; + + handle = CreateEventA( NULL, FALSE, FALSE, "test_event" ); + + len = 0; + status = pNtQueryObject( handle, ObjectNameInformation, buffer, 0, &len ); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "NtQueryObject failed %x\n", status ); + ok( len >= sizeof(UNICODE_STRING) + sizeof(name) + sizeof(WCHAR), "unexpected len %u\n", len ); + + len = 0; + status = pNtQueryObject( handle, ObjectNameInformation, buffer, sizeof(UNICODE_STRING), &len ); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "NtQueryObject failed %x\n", status ); + ok( len >= sizeof(UNICODE_STRING) + sizeof(name) + sizeof(WCHAR), "unexpected len %u\n", len ); + + len = 0; + status = pNtQueryObject( handle, ObjectNameInformation, buffer, sizeof(buffer), &len ); + ok( status == STATUS_SUCCESS, "NtQueryObject failed %x\n", status ); + ok( len > sizeof(UNICODE_STRING), "unexpected len %u\n", len ); + str = (UNICODE_STRING *)buffer; + ok( sizeof(UNICODE_STRING) + str->Length + sizeof(WCHAR) == len, "unexpected len %u\n", len ); + ok( str->Length >= sizeof(name), "unexpected len %u\n", str->Length ); + /* there can be a \\Sessions prefix in the name */ + ok( !memcmp( str->Buffer + (str->Length - sizeof(name)) / sizeof(WCHAR), name, sizeof(name) ), + "wrong name %s\n", wine_dbgstr_w(str->Buffer) ); + + len -= sizeof(WCHAR); + status = pNtQueryObject( handle, ObjectNameInformation, buffer, len, &len ); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "NtQueryObject failed %x\n", status ); + ok( len >= sizeof(UNICODE_STRING) + sizeof(name) + sizeof(WCHAR), "unexpected len %u\n", len ); + + pNtClose( handle ); + + handle = CreateEventA( NULL, FALSE, FALSE, NULL ); + len = 0; + status = pNtQueryObject( handle, ObjectNameInformation, buffer, sizeof(buffer), &len ); + ok( status == STATUS_SUCCESS, "NtQueryObject failed %x\n", status ); + ok( len == sizeof(UNICODE_STRING), "unexpected len %u\n", len ); + str = (UNICODE_STRING *)buffer; + ok( str->Length == 0, "unexpected len %u\n", len ); + ok( str->Buffer == NULL, "unexpected ptr %p\n", str->Buffer ); + pNtClose( handle ); + + GetWindowsDirectoryA( dir, MAX_PATH ); + handle = CreateFileA( dir, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, 0 ); + len = 0; + status = pNtQueryObject( handle, ObjectNameInformation, buffer, sizeof(buffer), &len ); + ok( status == STATUS_SUCCESS, "NtQueryObject failed %x\n", status ); + ok( len > sizeof(UNICODE_STRING), "unexpected len %u\n", len ); + str = (UNICODE_STRING *)buffer; + ok( sizeof(UNICODE_STRING) + str->Length + sizeof(WCHAR) == len || + broken(sizeof(UNICODE_STRING) + str->Length == len), /* NT4 */ + "unexpected len %u\n", len ); + trace( "got %s len %u\n", wine_dbgstr_w(str->Buffer), len ); + pNtClose( handle ); +} + START_TEST(om) { HMODULE hntdll = GetModuleHandleA("ntdll.dll"); @@ -646,10 +713,12 @@ START_TEST(om) pNtCreateSemaphore = (void *)GetProcAddress(hntdll, "NtCreateSemaphore"); pNtCreateTimer = (void *)GetProcAddress(hntdll, "NtCreateTimer"); pNtCreateSection = (void *)GetProcAddress(hntdll, "NtCreateSection"); + pNtQueryObject = (void *)GetProcAddress(hntdll, "NtQueryObject"); test_case_sensitive(); test_namespace_pipe(); test_name_collisions(); test_directory(); test_symboliclink(); + test_query_object(); } diff --git a/rostests/winetests/ntdll/reg.c b/rostests/winetests/ntdll/reg.c index 730f818e88d..1cad29e9829 100755 --- a/rostests/winetests/ntdll/reg.c +++ b/rostests/winetests/ntdll/reg.c @@ -116,22 +116,24 @@ typedef enum _KEY_VALUE_INFORMATION_CLASS { #endif static NTSTATUS (WINAPI * pRtlCreateUnicodeStringFromAsciiz)(PUNICODE_STRING, LPCSTR); +static void (WINAPI * pRtlInitUnicodeString)(PUNICODE_STRING,PCWSTR); static NTSTATUS (WINAPI * pRtlFreeUnicodeString)(PUNICODE_STRING); static NTSTATUS (WINAPI * pNtDeleteValueKey)(IN HANDLE, IN PUNICODE_STRING); static NTSTATUS (WINAPI * pRtlQueryRegistryValues)(IN ULONG, IN PCWSTR,IN PRTL_QUERY_REGISTRY_TABLE, IN PVOID,IN PVOID); static NTSTATUS (WINAPI * pRtlCheckRegistryKey)(IN ULONG,IN PWSTR); -static NTSTATUS (WINAPI * pRtlOpenCurrentUser)(IN ACCESS_MASK, OUT PHKEY); +static NTSTATUS (WINAPI * pRtlOpenCurrentUser)(IN ACCESS_MASK, PHANDLE); static NTSTATUS (WINAPI * pNtOpenKey)(PHANDLE, IN ACCESS_MASK, IN POBJECT_ATTRIBUTES); static NTSTATUS (WINAPI * pNtClose)(IN HANDLE); static NTSTATUS (WINAPI * pNtDeleteValueKey)(IN HANDLE, IN PUNICODE_STRING); -static NTSTATUS (WINAPI * pNtFlushKey)(HKEY); -static NTSTATUS (WINAPI * pNtDeleteKey)(HKEY); -static NTSTATUS (WINAPI * pNtCreateKey)( PHKEY retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, +static NTSTATUS (WINAPI * pNtFlushKey)(HANDLE); +static NTSTATUS (WINAPI * pNtDeleteKey)(HANDLE); +static NTSTATUS (WINAPI * pNtCreateKey)( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, ULONG TitleIndex, const UNICODE_STRING *class, ULONG options, PULONG dispos ); static NTSTATUS (WINAPI * pNtQueryValueKey)(HANDLE,const UNICODE_STRING *,KEY_VALUE_INFORMATION_CLASS,void *,DWORD,DWORD *); -static NTSTATUS (WINAPI * pNtSetValueKey)( PHKEY, const PUNICODE_STRING, ULONG, - ULONG, const PVOID, ULONG ); +static NTSTATUS (WINAPI * pNtSetValueKey)(HANDLE, const PUNICODE_STRING, ULONG, + ULONG, const void*, ULONG ); +static NTSTATUS (WINAPI * pNtQueryInformationProcess)(HANDLE,PROCESSINFOCLASS,PVOID,ULONG,PULONG); static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(PUNICODE_STRING); static NTSTATUS (WINAPI * pRtlCreateUnicodeString)( PUNICODE_STRING, LPCWSTR); static LPVOID (WINAPI * pRtlReAllocateHeap)(IN PVOID, IN ULONG, IN PVOID, IN ULONG); @@ -140,7 +142,8 @@ static NTSTATUS (WINAPI * pRtlUnicodeStringToAnsiString)(PSTRING, PUNICODE_STRIN static NTSTATUS (WINAPI * pRtlFreeHeap)(PVOID, ULONG, PVOID); static LPVOID (WINAPI * pRtlAllocateHeap)(PVOID,ULONG,ULONG); static NTSTATUS (WINAPI * pRtlZeroMemory)(PVOID, ULONG); -static NTSTATUS (WINAPI * pRtlpNtQueryValueKey)(HANDLE,ULONG*,PBYTE,DWORD*); +static NTSTATUS (WINAPI * pRtlpNtQueryValueKey)(HANDLE,ULONG*,PBYTE,DWORD*,void *); +static NTSTATUS (WINAPI * pRtlOpenCurrentUser)(ACCESS_MASK,HANDLE*); static HMODULE hntdll = 0; static int CurrentTest = 0; @@ -161,6 +164,7 @@ static BOOL InitFunctionPtrs(void) trace("Could not load ntdll.dll\n"); return FALSE; } + NTDLL_GET_PROC(RtlInitUnicodeString) NTDLL_GET_PROC(RtlCreateUnicodeStringFromAsciiz) NTDLL_GET_PROC(RtlCreateUnicodeString) NTDLL_GET_PROC(RtlFreeUnicodeString) @@ -174,6 +178,7 @@ static BOOL InitFunctionPtrs(void) NTDLL_GET_PROC(NtFlushKey) NTDLL_GET_PROC(NtDeleteKey) NTDLL_GET_PROC(NtQueryValueKey) + NTDLL_GET_PROC(NtQueryInformationProcess) NTDLL_GET_PROC(NtSetValueKey) NTDLL_GET_PROC(NtOpenKey) NTDLL_GET_PROC(RtlFormatCurrentUserKeyPath) @@ -184,6 +189,7 @@ static BOOL InitFunctionPtrs(void) NTDLL_GET_PROC(RtlAllocateHeap) NTDLL_GET_PROC(RtlZeroMemory) NTDLL_GET_PROC(RtlpNtQueryValueKey) + NTDLL_GET_PROC(RtlOpenCurrentUser) return TRUE; } #undef NTDLL_GET_PROC @@ -336,9 +342,6 @@ static void test_NtOpenKey(void) OBJECT_ATTRIBUTES attr; ACCESS_MASK am = KEY_READ; - if (0) - { - /* Crashes Wine */ /* All NULL */ status = pNtOpenKey(NULL, 0, NULL); ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status); @@ -347,29 +350,27 @@ static void test_NtOpenKey(void) status = pNtOpenKey(&key, 0, NULL); ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */, "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status); - } InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); /* NULL key */ - status = pNtOpenKey(NULL, 0, &attr); - todo_wine - ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status); + status = pNtOpenKey(NULL, am, &attr); + ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status); /* Length > sizeof(OBJECT_ATTRIBUTES) */ attr.Length *= 2; status = pNtOpenKey(&key, am, &attr); - todo_wine - ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status); + ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status); } static void test_NtCreateKey(void) { /*Create WineTest*/ OBJECT_ATTRIBUTES attr; - HKEY key; + HANDLE key, subkey; ACCESS_MASK am = GENERIC_ALL; NTSTATUS status; + UNICODE_STRING str; /* All NULL */ status = pNtCreateKey(NULL, 0, NULL, 0, 0, 0, 0); @@ -397,14 +398,51 @@ static void test_NtCreateKey(void) status = pNtCreateKey(NULL, 0, &attr, 0, 0, 0, 0); ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status); - status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0); - ok(status == STATUS_SUCCESS, "NtCreateKey Failed: 0x%08x\n", status); - /* Length > sizeof(OBJECT_ATTRIBUTES) */ attr.Length *= 2; status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0); ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status); + attr.Length = sizeof(attr); + status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0); + ok(status == STATUS_SUCCESS, "NtCreateKey Failed: 0x%08x\n", status); + + attr.RootDirectory = key; + attr.ObjectName = &str; + + pRtlCreateUnicodeStringFromAsciiz( &str, "test\\sub\\key" ); + status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status ); + pRtlFreeUnicodeString( &str ); + + pRtlCreateUnicodeStringFromAsciiz( &str, "test\\subkey" ); + status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status ); + pRtlFreeUnicodeString( &str ); + + pRtlCreateUnicodeStringFromAsciiz( &str, "test\\subkey\\" ); + status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status ); + pRtlFreeUnicodeString( &str ); + + pRtlCreateUnicodeStringFromAsciiz( &str, "test_subkey\\" ); + status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS || broken(status == STATUS_OBJECT_NAME_NOT_FOUND), /* nt4 */ + "NtCreateKey failed: 0x%08x\n", status ); + if (status == STATUS_SUCCESS) + { + pNtDeleteKey( subkey ); + pNtClose( subkey ); + } + pRtlFreeUnicodeString( &str ); + + pRtlCreateUnicodeStringFromAsciiz( &str, "test_subkey" ); + status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + pRtlFreeUnicodeString( &str ); + pNtDeleteKey( subkey ); + pNtClose( subkey ); + pNtClose(key); } @@ -437,7 +475,7 @@ static void test_NtSetValueKey(void) static void test_RtlOpenCurrentUser(void) { NTSTATUS status; - HKEY handle; + HANDLE handle; status=pRtlOpenCurrentUser(KEY_READ, &handle); ok(status == STATUS_SUCCESS, "RtlOpenCurrentUser Failed: 0x%08x\n", status); pNtClose(handle); @@ -482,7 +520,7 @@ static void test_NtQueryValueKey(void) KEY_VALUE_BASIC_INFORMATION *basic_info; KEY_VALUE_PARTIAL_INFORMATION *partial_info; KEY_VALUE_FULL_INFORMATION *full_info; - DWORD len; + DWORD len, expected; pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest"); @@ -556,7 +594,7 @@ static void test_NtQueryValueKey(void) pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest"); status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, NULL, 0, &len); - todo_wine ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey should have returned STATUS_BUFFER_TOO_SMALL instead of 0x%08x\n", status); + ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey should have returned STATUS_BUFFER_TOO_SMALL instead of 0x%08x\n", status); partial_info = HeapAlloc(GetProcessHeap(), 0, len+1); memset(partial_info, 0xbd, len+1); status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len); @@ -566,6 +604,21 @@ static void test_NtQueryValueKey(void) ok(partial_info->DataLength == STR_TRUNC_SIZE, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength); ok(!memcmp(partial_info->Data, stringW, STR_TRUNC_SIZE), "incorrect Data returned\n"); ok(*(partial_info->Data+STR_TRUNC_SIZE) == 0xbd, "string overflowed %02x\n", *(partial_info->Data+STR_TRUNC_SIZE)); + + expected = len; + status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 0, &len); + ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status); + ok(len == expected, "NtQueryValueKey wrong len %u\n", len); + status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 1, &len); + ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status); + ok(len == expected, "NtQueryValueKey wrong len %u\n", len); + status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) - 1, &len); + ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status); + ok(len == expected, "NtQueryValueKey wrong len %u\n", len); + status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data), &len); + ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey wrong status 0x%08x\n", status); + ok(len == expected, "NtQueryValueKey wrong len %u\n", len); + HeapFree(GetProcessHeap(), 0, partial_info); pRtlFreeUnicodeString(&ValName); @@ -593,10 +646,597 @@ static void test_RtlpNtQueryValueKey(void) { NTSTATUS status; - status = pRtlpNtQueryValueKey(NULL, NULL, NULL, NULL); + status = pRtlpNtQueryValueKey(NULL, NULL, NULL, NULL, NULL); ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status); } +static void test_symlinks(void) +{ + static const WCHAR linkW[] = {'l','i','n','k',0}; + static const WCHAR valueW[] = {'v','a','l','u','e',0}; + static const WCHAR symlinkW[] = {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0}; + static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0}; + static UNICODE_STRING null_str; + char buffer[1024]; + KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; + WCHAR *target; + UNICODE_STRING symlink_str, link_str, target_str, value_str; + HANDLE root, key, link; + OBJECT_ATTRIBUTES attr; + NTSTATUS status; + DWORD target_len, len, dw; + + pRtlInitUnicodeString( &link_str, linkW ); + pRtlInitUnicodeString( &symlink_str, symlinkW ); + pRtlInitUnicodeString( &target_str, targetW + 1 ); + pRtlInitUnicodeString( &value_str, valueW ); + + target_len = winetestpath.Length + sizeof(targetW); + target = pRtlAllocateHeap( GetProcessHeap(), 0, target_len + sizeof(targetW) /*for loop test*/ ); + memcpy( target, winetestpath.Buffer, winetestpath.Length ); + memcpy( target + winetestpath.Length/sizeof(WCHAR), targetW, sizeof(targetW) ); + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.Attributes = 0; + attr.ObjectName = &winetestpath; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + status = pNtCreateKey( &root, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + + attr.RootDirectory = root; + attr.ObjectName = &link_str; + status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + + /* REG_SZ is not allowed */ + status = pNtSetValueKey( link, &symlink_str, 0, REG_SZ, target, target_len ); + ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status ); + status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) ); + ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status ); + /* other values are not allowed */ + status = pNtSetValueKey( link, &link_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) ); + ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status ); + + /* try opening the target through the link */ + + attr.ObjectName = &link_str; + status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr ); + ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status ); + + attr.ObjectName = &target_str; + status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + + dw = 0xbeef; + status = pNtSetValueKey( key, &value_str, 0, REG_DWORD, &dw, sizeof(dw) ); + ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status ); + pNtClose( key ); + + attr.ObjectName = &link_str; + status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr ); + ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status ); + + len = sizeof(buffer); + status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len ); + ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status ); + ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len ); + + status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len ); + ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status ); + + /* REG_LINK can be created in non-link keys */ + status = pNtSetValueKey( key, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) ); + ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status ); + len = sizeof(buffer); + status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len ); + ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status ); + ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR), + "wrong len %u\n", len ); + status = pNtDeleteValueKey( key, &symlink_str ); + ok( status == STATUS_SUCCESS, "NtDeleteValueKey failed: 0x%08x\n", status ); + + pNtClose( key ); + + attr.Attributes = 0; + status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + + len = sizeof(buffer); + status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len ); + ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status ); + ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len ); + + status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len ); + ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status ); + pNtClose( key ); + + /* now open the symlink itself */ + + attr.RootDirectory = root; + attr.Attributes = OBJ_OPENLINK; + attr.ObjectName = &link_str; + status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr ); + ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status ); + + len = sizeof(buffer); + status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len ); + ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status ); + ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR), + "wrong len %u\n", len ); + pNtClose( key ); + + status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + len = sizeof(buffer); + status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len ); + ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status ); + ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR), + "wrong len %u\n", len ); + pNtClose( key ); + + if (0) /* crashes the Windows kernel on some Vista systems */ + { + /* reopen the link from itself */ + + attr.RootDirectory = link; + attr.Attributes = OBJ_OPENLINK; + attr.ObjectName = &null_str; + status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr ); + ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status ); + len = sizeof(buffer); + status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len ); + ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status ); + ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR), + "wrong len %u\n", len ); + pNtClose( key ); + + status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + len = sizeof(buffer); + status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len ); + ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status ); + ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR), + "wrong len %u\n", len ); + pNtClose( key ); + } + + if (0) /* crashes the Windows kernel in most versions */ + { + attr.RootDirectory = link; + attr.Attributes = 0; + attr.ObjectName = &null_str; + status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr ); + ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status ); + len = sizeof(buffer); + status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len ); + ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status ); + pNtClose( key ); + + status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + len = sizeof(buffer); + status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len ); + ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status ); + pNtClose( key ); + } + + /* target with terminating null doesn't work */ + status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len ); + ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status ); + attr.RootDirectory = root; + attr.Attributes = 0; + attr.ObjectName = &link_str; + status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr ); + ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status ); + + /* relative symlink, works only on win2k */ + status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, targetW+1, sizeof(targetW)-2*sizeof(WCHAR) ); + ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status ); + attr.ObjectName = &link_str; + status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr ); + ok( status == STATUS_SUCCESS || status == STATUS_OBJECT_NAME_NOT_FOUND, + "NtOpenKey wrong status 0x%08x\n", status ); + + status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 ); + ok( status == STATUS_OBJECT_NAME_COLLISION, "NtCreateKey failed: 0x%08x\n", status ); + + status = pNtDeleteKey( link ); + ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status ); + pNtClose( link ); + + attr.ObjectName = &target_str; + status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr ); + ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status ); + status = pNtDeleteKey( key ); + ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status ); + pNtClose( key ); + + /* symlink loop */ + + status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + memcpy( target + target_len/sizeof(WCHAR) - 1, targetW, sizeof(targetW) ); + status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, + target, target_len + sizeof(targetW) - sizeof(WCHAR) ); + ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status ); + + status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr ); + ok( status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_NAME_TOO_LONG, + "NtOpenKey failed: 0x%08x\n", status ); + + attr.Attributes = OBJ_OPENLINK; + status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr ); + ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status ); + pNtClose( key ); + + status = pNtDeleteKey( link ); + ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status ); + pNtClose( link ); + + status = pNtDeleteKey( root ); + ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status ); + pNtClose( root ); + + pRtlFreeHeap(GetProcessHeap(), 0, target); +} + +static WCHAR valueW[] = {'v','a','l','u','e'}; +static UNICODE_STRING value_str = { sizeof(valueW), sizeof(valueW), valueW }; +static const DWORD ptr_size = 8 * sizeof(void*); + +static DWORD get_key_value( HANDLE root, const char *name, DWORD flags ) +{ + char tmp[32]; + NTSTATUS status; + OBJECT_ATTRIBUTES attr; + UNICODE_STRING str; + HANDLE key; + KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp; + DWORD dw, len = sizeof(tmp); + + attr.Length = sizeof(attr); + attr.RootDirectory = root; + attr.Attributes = OBJ_CASE_INSENSITIVE; + attr.ObjectName = &str; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + pRtlCreateUnicodeStringFromAsciiz( &str, name ); + + status = pNtCreateKey( &key, flags | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + if (status == STATUS_OBJECT_NAME_NOT_FOUND) return 0; + ok( status == STATUS_SUCCESS, "%08x: NtCreateKey failed: 0x%08x\n", flags, status ); + + status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len ); + if (status == STATUS_OBJECT_NAME_NOT_FOUND) + dw = 0; + else + { + ok( status == STATUS_SUCCESS, "%08x: NtQueryValueKey failed: 0x%08x\n", flags, status ); + dw = *(DWORD *)info->Data; + } + pNtClose( key ); + pRtlFreeUnicodeString( &str ); + return dw; +} + +static void _check_key_value( int line, HANDLE root, const char *name, DWORD flags, DWORD expect ) +{ + DWORD dw = get_key_value( root, name, flags ); + ok_(__FILE__,line)( dw == expect, "%08x: wrong value %u/%u\n", flags, dw, expect ); +} +#define check_key_value(root,name,flags,expect) _check_key_value( __LINE__, root, name, flags, expect ) + +static void test_redirection(void) +{ + static const WCHAR softwareW[] = {'\\','R','e','g','i','s','t','r','y','\\', + 'M','a','c','h','i','n','e','\\', + 'S','o','f','t','w','a','r','e',0}; + static const WCHAR wownodeW[] = {'\\','R','e','g','i','s','t','r','y','\\', + 'M','a','c','h','i','n','e','\\', + 'S','o','f','t','w','a','r','e','\\', + 'W','o','w','6','4','3','2','N','o','d','e',0}; + static const WCHAR wine64W[] = {'\\','R','e','g','i','s','t','r','y','\\', + 'M','a','c','h','i','n','e','\\', + 'S','o','f','t','w','a','r','e','\\', + 'W','i','n','e',0}; + static const WCHAR wine32W[] = {'\\','R','e','g','i','s','t','r','y','\\', + 'M','a','c','h','i','n','e','\\', + 'S','o','f','t','w','a','r','e','\\', + 'W','o','w','6','4','3','2','N','o','d','e','\\', + 'W','i','n','e',0}; + static const WCHAR key64W[] = {'\\','R','e','g','i','s','t','r','y','\\', + 'M','a','c','h','i','n','e','\\', + 'S','o','f','t','w','a','r','e','\\', + 'W','i','n','e','\\','W','i','n','e','t','e','s','t',0}; + static const WCHAR key32W[] = {'\\','R','e','g','i','s','t','r','y','\\', + 'M','a','c','h','i','n','e','\\', + 'S','o','f','t','w','a','r','e','\\', + 'W','o','w','6','4','3','2','N','o','d','e','\\', + 'W','i','n','e','\\', 'W','i','n','e','t','e','s','t',0}; + static const WCHAR classes64W[] = {'\\','R','e','g','i','s','t','r','y','\\', + 'M','a','c','h','i','n','e','\\', + 'S','o','f','t','w','a','r','e','\\', + 'C','l','a','s','s','e','s','\\', + 'W','i','n','e',0}; + static const WCHAR classes32W[] = {'\\','R','e','g','i','s','t','r','y','\\', + 'M','a','c','h','i','n','e','\\', + 'S','o','f','t','w','a','r','e','\\', + 'C','l','a','s','s','e','s','\\', + 'W','o','w','6','4','3','2','N','o','d','e','\\', + 'W','i','n','e',0}; + NTSTATUS status; + OBJECT_ATTRIBUTES attr; + UNICODE_STRING str; + char buffer[1024]; + KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; + DWORD dw, len; + HANDLE key, root32, root64, key32, key64; + BOOL is_vista = FALSE; + + if (ptr_size != 64) + { + ULONG is_wow64, len; + if (pNtQueryInformationProcess( GetCurrentProcess(), ProcessWow64Information, + &is_wow64, sizeof(is_wow64), &len ) || + !is_wow64) + { + trace( "Not on Wow64, no redirection\n" ); + return; + } + } + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.Attributes = OBJ_CASE_INSENSITIVE; + attr.ObjectName = &str; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + pRtlInitUnicodeString( &str, wine64W ); + status = pNtCreateKey( &root64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + + pRtlInitUnicodeString( &str, wine32W ); + status = pNtCreateKey( &root32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + + pRtlInitUnicodeString( &str, key64W ); + status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + + pRtlInitUnicodeString( &str, key32W ); + status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + + dw = 64; + status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) ); + ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status ); + + dw = 32; + status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) ); + ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status ); + + len = sizeof(buffer); + status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len ); + ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status ); + dw = *(DWORD *)info->Data; + ok( dw == 32, "wrong value %u\n", dw ); + + len = sizeof(buffer); + status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len ); + ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status ); + dw = *(DWORD *)info->Data; + ok( dw == 64, "wrong value %u\n", dw ); + + pRtlInitUnicodeString( &str, softwareW ); + status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + + if (ptr_size == 32) + { + /* the Vista mechanism allows opening Wow6432Node from a 32-bit key too */ + /* the new (and simpler) Win7 mechanism doesn't */ + if (get_key_value( key, "Wow6432Node\\Wine\\Winetest", 0 ) == 32) + { + trace( "using Vista-style Wow6432Node handling\n" ); + is_vista = TRUE; + } + check_key_value( key, "Wine\\Winetest", 0, 32 ); + check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 ); + check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 ); + check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 ); + check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 ); + check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 ); + } + else + { + check_key_value( key, "Wine\\Winetest", 0, 64 ); + check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 ); + } + pNtClose( key ); + + if (ptr_size == 32) + { + status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + dw = get_key_value( key, "Wine\\Winetest", 0 ); + ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw ); + check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, 64 ); + check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 ); + check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 ); + dw = get_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY ); + ok( dw == 32 || broken(dw == 64) /* xp64 */, "wrong value %u\n", dw ); + check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 ); + pNtClose( key ); + + status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + check_key_value( key, "Wine\\Winetest", 0, 32 ); + check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 ); + check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 ); + check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 ); + check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 ); + check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 ); + pNtClose( key ); + } + + check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", 0, ptr_size ); + check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", 0, 32 ); + if (ptr_size == 64) + { + /* KEY_WOW64 flags have no effect on 64-bit */ + check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 ); + check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY, 64 ); + check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, 32 ); + check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 ); + } + else + { + check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 ); + check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY, 32 ); + check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 ); + check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 ); + } + + pRtlInitUnicodeString( &str, wownodeW ); + status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + check_key_value( key, "Wine\\Winetest", 0, 32 ); + check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, (ptr_size == 64) ? 32 : (is_vista ? 64 : 32) ); + check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 ); + pNtClose( key ); + + if (ptr_size == 32) + { + status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + dw = get_key_value( key, "Wine\\Winetest", 0 ); + ok( dw == (is_vista ? 64 : 32) || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw ); + check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 ); + check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 ); + pNtClose( key ); + + status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + check_key_value( key, "Wine\\Winetest", 0, 32 ); + check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 ); + check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 ); + pNtClose( key ); + } + + pRtlInitUnicodeString( &str, wine32W ); + status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + check_key_value( key, "Winetest", 0, 32 ); + check_key_value( key, "Winetest", KEY_WOW64_64KEY, (ptr_size == 32 && is_vista) ? 64 : 32 ); + check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 ); + pNtClose( key ); + + if (ptr_size == 32) + { + status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + dw = get_key_value( key, "Winetest", 0 ); + ok( dw == 32 || (is_vista && dw == 64), "wrong value %u\n", dw ); + check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 ); + check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 ); + pNtClose( key ); + + status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + check_key_value( key, "Winetest", 0, 32 ); + check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 ); + check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 ); + pNtClose( key ); + } + + pRtlInitUnicodeString( &str, wine64W ); + status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + check_key_value( key, "Winetest", 0, ptr_size ); + check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : ptr_size ); + check_key_value( key, "Winetest", KEY_WOW64_32KEY, ptr_size ); + pNtClose( key ); + + if (ptr_size == 32) + { + status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + dw = get_key_value( key, "Winetest", 0 ); + ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw ); + check_key_value( key, "Winetest", KEY_WOW64_64KEY, 64 ); + dw = get_key_value( key, "Winetest", KEY_WOW64_32KEY ); + todo_wine ok( dw == 32, "wrong value %u\n", dw ); + pNtClose( key ); + + status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + check_key_value( key, "Winetest", 0, 32 ); + check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 ); + check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 ); + pNtClose( key ); + } + + status = pNtDeleteKey( key32 ); + ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status ); + pNtClose( key32 ); + + status = pNtDeleteKey( key64 ); + ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status ); + pNtClose( key64 ); + + pNtDeleteKey( root32 ); + pNtClose( root32 ); + pNtDeleteKey( root64 ); + pNtClose( root64 ); + + /* Software\Classes is shared/reflected so behavior is different */ + + pRtlInitUnicodeString( &str, classes64W ); + status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + + pRtlInitUnicodeString( &str, classes32W ); + status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + + dw = 64; + status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) ); + ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status ); + pNtClose( key64 ); + + dw = 32; + status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) ); + ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status ); + pNtClose( key32 ); + + pRtlInitUnicodeString( &str, classes64W ); + status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + len = sizeof(buffer); + status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len ); + ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status ); + dw = *(DWORD *)info->Data; + ok( dw == ptr_size, "wrong value %u\n", dw ); + + pRtlInitUnicodeString( &str, classes32W ); + status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); + len = sizeof(buffer); + status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len ); + ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status ); + dw = *(DWORD *)info->Data; + ok( dw == 32, "wrong value %u\n", dw ); + + pNtDeleteKey( key32 ); + pNtClose( key32 ); + pNtDeleteKey( key64 ); + pNtClose( key64 ); +} + START_TEST(reg) { static const WCHAR winetest[] = {'\\','W','i','n','e','T','e','s','t',0}; @@ -609,8 +1249,8 @@ START_TEST(reg) pRtlAppendUnicodeToString(&winetestpath, winetest); - test_NtOpenKey(); test_NtCreateKey(); + test_NtOpenKey(); test_NtSetValueKey(); test_RtlCheckRegistryKey(); test_RtlOpenCurrentUser(); @@ -619,6 +1259,8 @@ START_TEST(reg) test_NtFlushKey(); test_NtQueryValueKey(); test_NtDeleteKey(); + test_symlinks(); + test_redirection(); pRtlFreeUnicodeString(&winetestpath); diff --git a/rostests/winetests/ntdll/rtl.c b/rostests/winetests/ntdll/rtl.c index 7beef6d9865..6e76a3cc58d 100755 --- a/rostests/winetests/ntdll/rtl.c +++ b/rostests/winetests/ntdll/rtl.c @@ -67,6 +67,11 @@ static RTL_HANDLE * (WINAPI * pRtlAllocateHandle)(RTL_HANDLE_TABLE *, ULONG *); static BOOLEAN (WINAPI * pRtlFreeHandle)(RTL_HANDLE_TABLE *, RTL_HANDLE *); static NTSTATUS (WINAPI *pRtlAllocateAndInitializeSid)(PSID_IDENTIFIER_AUTHORITY,BYTE,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,PSID*); static NTSTATUS (WINAPI *pRtlFreeSid)(PSID); +static struct _TEB * (WINAPI *pNtCurrentTeb)(void); +static DWORD (WINAPI *pRtlGetThreadErrorMode)(void); +static NTSTATUS (WINAPI *pRtlSetThreadErrorMode)(DWORD, LPDWORD); +static HMODULE hkernel32 = 0; +static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL); #define LEN 16 static const char* src_src = "This is a test!"; /* 16 bytes long, incl NUL */ static ULONG src_aligned_block[4]; @@ -99,6 +104,14 @@ static void InitFunctionPtrs(void) pRtlFreeHandle = (void *)GetProcAddress(hntdll, "RtlFreeHandle"); pRtlAllocateAndInitializeSid = (void *)GetProcAddress(hntdll, "RtlAllocateAndInitializeSid"); pRtlFreeSid = (void *)GetProcAddress(hntdll, "RtlFreeSid"); + pNtCurrentTeb = (void *)GetProcAddress(hntdll, "NtCurrentTeb"); + pRtlGetThreadErrorMode = (void *)GetProcAddress(hntdll, "RtlGetThreadErrorMode"); + pRtlSetThreadErrorMode = (void *)GetProcAddress(hntdll, "RtlSetThreadErrorMode"); + } + hkernel32 = LoadLibraryA("kernel32.dll"); + ok(hkernel32 != 0, "LoadLibrary failed\n"); + if (hkernel32) { + pIsWow64Process = (void *)GetProcAddress(hkernel32, "IsWow64Process"); } strcpy((char*)src_aligned_block, src_src); ok(strlen(src) == 15, "Source must be 16 bytes long!\n"); @@ -112,7 +125,10 @@ static void test_RtlCompareMemory(void) SIZE_T size; if (!pRtlCompareMemory) + { + win_skip("RtlCompareMemory is not available\n"); return; + } strcpy(dest, src); @@ -127,6 +143,12 @@ static void test_RtlCompareMemoryUlong(void) ULONG a[10]; ULONG result; + if (!pRtlCompareMemoryUlong) + { + win_skip("RtlCompareMemoryUlong is not available\n"); + return; + } + a[0]= 0x0123; a[1]= 0x4567; a[2]= 0x89ab; @@ -173,7 +195,10 @@ static void test_RtlCompareMemoryUlong(void) static void test_RtlMoveMemory(void) { if (!pRtlMoveMemory) + { + win_skip("RtlMoveMemory is not available\n"); return; + } /* Length should be in bytes and not rounded. Use strcmp to ensure we * didn't write past the end (it checks for the final NUL left by memset) @@ -201,7 +226,10 @@ static void test_RtlMoveMemory(void) static void test_RtlFillMemory(void) { if (!pRtlFillMemory) + { + win_skip("RtlFillMemory is not available\n"); return; + } /* Length should be in bytes and not rounded. Use strcmp to ensure we * didn't write past the end (the remainder of the string should match) @@ -224,7 +252,10 @@ static void test_RtlFillMemoryUlong(void) { ULONG val = ('x' << 24) | ('x' << 16) | ('x' << 8) | 'x'; if (!pRtlFillMemoryUlong) + { + win_skip("RtlFillMemoryUlong is not available\n"); return; + } /* Length should be in bytes and not rounded. Use strcmp to ensure we * didn't write past the end (the remainder of the string should match) @@ -247,7 +278,10 @@ static void test_RtlFillMemoryUlong(void) static void test_RtlZeroMemory(void) { if (!pRtlZeroMemory) + { + win_skip("RtlZeroMemory is not available\n"); return; + } /* Length should be in bytes and not rounded. */ ZERO(0); MCMP("This is a test!"); @@ -266,6 +300,12 @@ static void test_RtlUlonglongByteSwap(void) { ULONGLONG result; + if ( !pRtlUlonglongByteSwap ) + { + win_skip("RtlUlonglongByteSwap is not available\n"); + return; + } + if ( pRtlUlonglongByteSwap( 0 ) != 0 ) { win_skip("Broken RtlUlonglongByteSwap in win2k\n"); @@ -287,6 +327,12 @@ static void test_RtlUniform(void) ULONG expected; ULONG result; + if (!pRtlUniform) + { + win_skip("RtlUniform is not available\n"); + return; + } + /* * According to the documentation RtlUniform is using D.H. Lehmer's 1948 * algorithm. This algorithm is: @@ -612,6 +658,12 @@ static void test_RtlRandom(void) ULONG result; ULONG result_expected; + if (!pRtlRandom) + { + win_skip("RtlRandom is not available\n"); + return; + } + /* * Unlike RtlUniform, RtlRandom is not documented. We guess that for * RtlRandom D.H. Lehmer's 1948 algorithm is used like stated in @@ -820,6 +872,12 @@ static void test_RtlAreAllAccessesGranted(void) unsigned int test_num; BOOLEAN result; + if (!pRtlAreAllAccessesGranted) + { + win_skip("RtlAreAllAccessesGranted is not available\n"); + return; + } + for (test_num = 0; test_num < NB_ALL_ACCESSES; test_num++) { result = pRtlAreAllAccessesGranted(all_accesses[test_num].GrantedAccess, all_accesses[test_num].DesiredAccess); @@ -857,6 +915,12 @@ static void test_RtlAreAnyAccessesGranted(void) unsigned int test_num; BOOLEAN result; + if (!pRtlAreAnyAccessesGranted) + { + win_skip("RtlAreAnyAccessesGranted is not available\n"); + return; + } + for (test_num = 0; test_num < NB_ANY_ACCESSES; test_num++) { result = pRtlAreAnyAccessesGranted(any_accesses[test_num].GrantedAccess, any_accesses[test_num].DesiredAccess); @@ -873,7 +937,10 @@ static void test_RtlComputeCrc32(void) DWORD crc = 0; if (!pRtlComputeCrc32) + { + win_skip("RtlComputeCrc32 is not available\n"); return; + } crc = pRtlComputeCrc32(crc, (const BYTE *)src, LEN); ok(crc == 0x40861dc2,"Expected 0x40861dc2, got %8x\n", crc); @@ -900,6 +967,12 @@ static void test_HandleTables(void) MY_HANDLE * MyHandle; RTL_HANDLE_TABLE HandleTable; + if (!pRtlInitializeHandleTable) + { + win_skip("RtlInitializeHandleTable is not available\n"); + return; + } + pRtlInitializeHandleTable(0x3FFF, sizeof(MY_HANDLE), &HandleTable); MyHandle = (MY_HANDLE *)pRtlAllocateHandle(&HandleTable, &Index); ok(MyHandle != NULL, "RtlAllocateHandle failed\n"); @@ -919,14 +992,23 @@ static void test_RtlAllocateAndInitializeSid(void) SID_IDENTIFIER_AUTHORITY sia = {{ 1, 2, 3, 4, 5, 6 }}; PSID psid; + if (!pRtlAllocateAndInitializeSid) + { + win_skip("RtlAllocateAndInitializeSid is not available\n"); + return; + } + ret = pRtlAllocateAndInitializeSid(&sia, 0, 1, 2, 3, 4, 5, 6, 7, 8, &psid); ok(!ret, "RtlAllocateAndInitializeSid error %08x\n", ret); ret = pRtlFreeSid(psid); ok(!ret, "RtlFreeSid error %08x\n", ret); - /* these tests crash on XP - ret = pRtlAllocateAndInitializeSid(NULL, 0, 1, 2, 3, 4, 5, 6, 7, 8, &psid); - ret = pRtlAllocateAndInitializeSid(&sia, 0, 1, 2, 3, 4, 5, 6, 7, 8, NULL);*/ + /* these tests crash on XP */ + if (0) + { + ret = pRtlAllocateAndInitializeSid(NULL, 0, 1, 2, 3, 4, 5, 6, 7, 8, &psid); + ret = pRtlAllocateAndInitializeSid(&sia, 0, 1, 2, 3, 4, 5, 6, 7, 8, NULL); + } ret = pRtlAllocateAndInitializeSid(&sia, 9, 1, 2, 3, 4, 5, 6, 7, 8, &psid); ok(ret == STATUS_INVALID_SID, "wrong error %08x\n", ret); @@ -935,44 +1017,101 @@ static void test_RtlAllocateAndInitializeSid(void) static void test_RtlDeleteTimer(void) { NTSTATUS ret; + + if (!pRtlDeleteTimer) + { + win_skip("RtlDeleteTimer is not available\n"); + return; + } + ret = pRtlDeleteTimer(NULL, NULL, NULL); ok(ret == STATUS_INVALID_PARAMETER_1 || ret == STATUS_INVALID_PARAMETER, /* W2K */ "expected STATUS_INVALID_PARAMETER_1 or STATUS_INVALID_PARAMETER, got %x\n", ret); } +static void test_RtlThreadErrorMode(void) +{ + DWORD oldmode; + BOOL is_wow64; + DWORD mode; + NTSTATUS status; + + if (!pRtlGetThreadErrorMode || !pRtlSetThreadErrorMode) + { + win_skip("RtlGetThreadErrorMode and/or RtlSetThreadErrorMode not available\n"); + return; + } + + if (!pIsWow64Process || !pIsWow64Process(GetCurrentProcess(), &is_wow64)) + is_wow64 = FALSE; + + oldmode = pRtlGetThreadErrorMode(); + + status = pRtlSetThreadErrorMode(0x70, &mode); + ok(status == STATUS_SUCCESS || + status == STATUS_WAIT_1, /* Vista */ + "RtlSetThreadErrorMode failed with error 0x%08x\n", status); + ok(mode == oldmode, + "RtlSetThreadErrorMode returned mode 0x%x, expected 0x%x\n", + mode, oldmode); + ok(pRtlGetThreadErrorMode() == 0x70, + "RtlGetThreadErrorMode returned 0x%x, expected 0x%x\n", mode, 0x70); + if (!is_wow64 && pNtCurrentTeb) + ok(pNtCurrentTeb()->HardErrorDisabled == 0x70, + "The TEB contains 0x%x, expected 0x%x\n", + pNtCurrentTeb()->HardErrorDisabled, 0x70); + + status = pRtlSetThreadErrorMode(0, &mode); + ok(status == STATUS_SUCCESS || + status == STATUS_WAIT_1, /* Vista */ + "RtlSetThreadErrorMode failed with error 0x%08x\n", status); + ok(mode == 0x70, + "RtlSetThreadErrorMode returned mode 0x%x, expected 0x%x\n", + mode, 0x70); + ok(pRtlGetThreadErrorMode() == 0, + "RtlGetThreadErrorMode returned 0x%x, expected 0x%x\n", mode, 0); + if (!is_wow64 && pNtCurrentTeb) + ok(pNtCurrentTeb()->HardErrorDisabled == 0, + "The TEB contains 0x%x, expected 0x%x\n", + pNtCurrentTeb()->HardErrorDisabled, 0); + + for (mode = 1; mode; mode <<= 1) + { + status = pRtlSetThreadErrorMode(mode, NULL); + if (mode & 0x70) + ok(status == STATUS_SUCCESS || + status == STATUS_WAIT_1, /* Vista */ + "RtlSetThreadErrorMode(%x,NULL) failed with error 0x%08x\n", + mode, status); + else + ok(status == STATUS_INVALID_PARAMETER_1, + "RtlSetThreadErrorMode(%x,NULL) returns 0x%08x, " + "expected STATUS_INVALID_PARAMETER_1\n", + mode, status); + } + + pRtlSetThreadErrorMode(oldmode, NULL); +} + START_TEST(rtl) { InitFunctionPtrs(); - if (pRtlCompareMemory) - test_RtlCompareMemory(); - if (pRtlCompareMemoryUlong) - test_RtlCompareMemoryUlong(); - if (pRtlMoveMemory) - test_RtlMoveMemory(); - if (pRtlFillMemory) - test_RtlFillMemory(); - if (pRtlFillMemoryUlong) - test_RtlFillMemoryUlong(); - if (pRtlZeroMemory) - test_RtlZeroMemory(); - if (pRtlUlonglongByteSwap) - test_RtlUlonglongByteSwap(); - if (pRtlUniform) - test_RtlUniform(); - if (pRtlRandom) - test_RtlRandom(); - if (pRtlAreAllAccessesGranted) - test_RtlAreAllAccessesGranted(); - if (pRtlAreAnyAccessesGranted) - test_RtlAreAnyAccessesGranted(); - if (pRtlComputeCrc32) - test_RtlComputeCrc32(); - if (pRtlInitializeHandleTable) - test_HandleTables(); - if (pRtlAllocateAndInitializeSid) - test_RtlAllocateAndInitializeSid(); - if (pRtlDeleteTimer) - test_RtlDeleteTimer(); + test_RtlCompareMemory(); + test_RtlCompareMemoryUlong(); + test_RtlMoveMemory(); + test_RtlFillMemory(); + test_RtlFillMemoryUlong(); + test_RtlZeroMemory(); + test_RtlUlonglongByteSwap(); + test_RtlUniform(); + test_RtlRandom(); + test_RtlAreAllAccessesGranted(); + test_RtlAreAnyAccessesGranted(); + test_RtlComputeCrc32(); + test_HandleTables(); + test_RtlAllocateAndInitializeSid(); + test_RtlDeleteTimer(); + test_RtlThreadErrorMode(); } diff --git a/rostests/winetests/ntdll/string.c b/rostests/winetests/ntdll/string.c index 16c11926016..cd3ae37cf4c 100755 --- a/rostests/winetests/ntdll/string.c +++ b/rostests/winetests/ntdll/string.c @@ -1113,11 +1113,28 @@ static void test_wtoi64(void) } } -static void test_wcsfuncs(void) -{ - static const WCHAR testing[] = {'T','e','s','t','i','n','g',0}; - ok (p_wcschr(testing,0)!=NULL, "wcschr Not finding terminating character\n"); - ok (p_wcsrchr(testing,0)!=NULL, "wcsrchr Not finding terminating character\n"); +static void test_wcschr(void) +{ + static const WCHAR teststringW[] = {'a','b','r','a','c','a','d','a','b','r','a',0}; + + ok(p_wcschr(teststringW, 'a') == teststringW + 0, + "wcschr should have returned a pointer to the first 'a' character\n"); + ok(p_wcschr(teststringW, 0) == teststringW + 11, + "wcschr should have returned a pointer to the null terminator\n"); + ok(p_wcschr(teststringW, 'x') == NULL, + "wcschr should have returned NULL\n"); +} + +static void test_wcsrchr(void) +{ + static const WCHAR teststringW[] = {'a','b','r','a','c','a','d','a','b','r','a',0}; + + ok(p_wcsrchr(teststringW, 'a') == teststringW + 10, + "wcsrchr should have returned a pointer to the last 'a' character\n"); + ok(p_wcsrchr(teststringW, 0) == teststringW + 11, + "wcsrchr should have returned a pointer to the null terminator\n"); + ok(p_wcsrchr(teststringW, 'x') == NULL, + "wcsrchr should have returned NULL\n"); } START_TEST(string) @@ -1140,8 +1157,10 @@ START_TEST(string) test_wtol(); if (p_wtoi64) test_wtoi64(); - if (p_wcschr && p_wcsrchr) - test_wcsfuncs(); + if (p_wcschr) + test_wcschr(); + if (p_wcsrchr) + test_wcsrchr(); if (patoi) test_atoi(); if (patol) diff --git a/rostests/winetests/ntdll/testlist.c b/rostests/winetests/ntdll/testlist.c index 0162d0f8937..b5b1674cdd1 100644 --- a/rostests/winetests/ntdll/testlist.c +++ b/rostests/winetests/ntdll/testlist.c @@ -8,6 +8,7 @@ extern void func_atom(void); extern void func_change(void); +extern void func_directory(void); extern void func_env(void); extern void func_error(void); extern void func_exception(void); @@ -29,6 +30,7 @@ const struct test winetest_testlist[] = { { "atom", func_atom }, { "change", func_change }, + { "directory", func_directory }, { "env", func_env }, { "error", func_error }, { "exception", func_exception }, diff --git a/rostests/winetests/ntdll/time.c b/rostests/winetests/ntdll/time.c index 2e9adbc11a5..16530c4d651 100755 --- a/rostests/winetests/ntdll/time.c +++ b/rostests/winetests/ntdll/time.c @@ -20,8 +20,6 @@ #include "ntdll_test.h" -#ifdef __WINE_WINTERNL_H - #define TICKSPERSEC 10000000 #define TICKSPERMSEC 10000 #define SECSPERDAY 86400 @@ -95,15 +93,14 @@ static void test_pRtlTimeToTimeFields(void) litime.QuadPart += (LONGLONG) tftest.Day * TICKSPERSEC * SECSPERDAY; } } -#endif START_TEST(time) { -#ifdef __WINE_WINTERNL_H HMODULE mod = GetModuleHandleA("ntdll.dll"); pRtlTimeToTimeFields = (void *)GetProcAddress(mod,"RtlTimeToTimeFields"); pRtlTimeFieldsToTime = (void *)GetProcAddress(mod,"RtlTimeFieldsToTime"); if (pRtlTimeToTimeFields && pRtlTimeFieldsToTime) test_pRtlTimeToTimeFields(); -#endif + else + win_skip("Required time conversion functions are not available\n"); } From f64f8479d978d3bd7a0cd4bb6b8aefaf34693459 Mon Sep 17 00:00:00 2001 From: Christoph von Wittich Date: Mon, 15 Mar 2010 22:21:34 +0000 Subject: [PATCH 35/61] [PSDK] fix callback definition svn path=/trunk/; revision=46216 --- reactos/include/psdk/winternl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reactos/include/psdk/winternl.h b/reactos/include/psdk/winternl.h index 1496b0f7f1f..7f1a739b53d 100644 --- a/reactos/include/psdk/winternl.h +++ b/reactos/include/psdk/winternl.h @@ -1554,7 +1554,7 @@ typedef struct _KEY_MULTIPLE_VALUE_INFORMATION ULONG Type; } KEY_MULTIPLE_VALUE_INFORMATION, *PKEY_MULTIPLE_VALUE_INFORMATION; -typedef VOID (*PTIMER_APC_ROUTINE) ( PVOID, ULONG, LONG ); +typedef VOID (CALLBACK *PTIMER_APC_ROUTINE) ( PVOID, ULONG, LONG ); typedef enum _EVENT_TYPE { NotificationEvent, From 96ae173fead7d3329b064cbab756f82006b63cf1 Mon Sep 17 00:00:00 2001 From: Dmitry Gorbachev Date: Mon, 15 Mar 2010 22:54:09 +0000 Subject: [PATCH 36/61] Link buslogic.sys against libcntpr. This should fix "undefined reference" errors reported on the forum. svn path=/trunk/; revision=46217 --- .../storage/port/buslogic/BusLogic958.c | 34 ------------------- .../storage/port/buslogic/buslogic.rbuild | 2 +- 2 files changed, 1 insertion(+), 35 deletions(-) diff --git a/reactos/drivers/storage/port/buslogic/BusLogic958.c b/reactos/drivers/storage/port/buslogic/BusLogic958.c index 22c5838b99b..0bf439e06b9 100644 --- a/reactos/drivers/storage/port/buslogic/BusLogic958.c +++ b/reactos/drivers/storage/port/buslogic/BusLogic958.c @@ -79,40 +79,6 @@ v1.2.0.2 // Fix PR 40284 correctly, disable interrupts in the initialization ro #include "BusLogic958.h" -int strcmp(const char* s1, const char* s2) -{ - while(*s1 == *s2) - { - if(*s1 == 0) return 0; - - s1 ++; - s2 ++; - } - - return *s1 - *s2; -} - -char * strcat(char * s, const char * append) -{ - char * save = s; - - for(; *s; ++s); - - while((*s++ = *append++)); - - return save; -} - -char * strcpy(char * to, const char * from) -{ - char *save = to; - - for (; (*to = *from); ++from, ++to); - - return save; -} - - ULONG NTAPI DriverEntry(IN PVOID DriverObject, diff --git a/reactos/drivers/storage/port/buslogic/buslogic.rbuild b/reactos/drivers/storage/port/buslogic/buslogic.rbuild index 3a197ce05de..3347f10b98d 100644 --- a/reactos/drivers/storage/port/buslogic/buslogic.rbuild +++ b/reactos/drivers/storage/port/buslogic/buslogic.rbuild @@ -1,6 +1,6 @@ - + . scsiport From c1e3362f03f568154e574a20f8dd0a0eeff13b51 Mon Sep 17 00:00:00 2001 From: Christoph von Wittich Date: Tue, 16 Mar 2010 09:29:28 +0000 Subject: [PATCH 37/61] [ADVAPI32] sync RegpApplyRestrictions to wine 1.1.40 svn path=/trunk/; revision=46219 --- reactos/dll/win32/advapi32/reg/reg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reactos/dll/win32/advapi32/reg/reg.c b/reactos/dll/win32/advapi32/reg/reg.c index 4a2ce7e96d6..686101e7f1b 100644 --- a/reactos/dll/win32/advapi32/reg/reg.c +++ b/reactos/dll/win32/advapi32/reg/reg.c @@ -1916,9 +1916,9 @@ RegpApplyRestrictions(DWORD dwFlags, { DWORD cbExpect = 0; - if ((dwFlags & RRF_RT_DWORD) == RRF_RT_DWORD) + if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD) cbExpect = 4; - else if ((dwFlags & RRF_RT_QWORD) == RRF_RT_QWORD) + else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD) cbExpect = 8; if (cbExpect && cbData != cbExpect) From fcec48b05bd23b91c7e33a28399298e09a01b096 Mon Sep 17 00:00:00 2001 From: Christoph von Wittich Date: Tue, 16 Mar 2010 10:47:04 +0000 Subject: [PATCH 38/61] [DXDIAG] get next button to work svn path=/trunk/; revision=46220 --- reactos/base/applications/dxdiag/dxdiag.c | 22 +++++++++++++++++++--- reactos/base/applications/dxdiag/system.c | 5 ++--- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/reactos/base/applications/dxdiag/dxdiag.c b/reactos/base/applications/dxdiag/dxdiag.c index 3985fae208d..2c9bc701baf 100644 --- a/reactos/base/applications/dxdiag/dxdiag.c +++ b/reactos/base/applications/dxdiag/dxdiag.c @@ -126,7 +126,6 @@ InitializeTabCtrl(HWND hwndDlg, PDXDIAG_CONTEXT pContext) pContext->hDialogs[4] = CreateDialogParamW(hInst, MAKEINTRESOURCEW(IDD_HELP_DIALOG), hTabCtrlWnd, HelpPageWndProc, (LPARAM)pContext); /* insert tab ctrl items */ - InsertTabCtrlItem(hTabCtrlWnd, 0, MAKEINTRESOURCEW(IDS_SYSTEM_DIALOG)); InitializeDisplayAdapters(pContext); InitializeDirectSoundPage(pContext); @@ -188,8 +187,19 @@ DxDiagWndProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) if (LOWORD(wParam) == IDC_BUTTON_NEXT) { - //TODO - /* handle next button */ + INT CurSel; + + /* retrieve current page */ + CurSel = TabCtrl_GetCurSel(hTabCtrlWnd); + CurSel++; + + /* enable/disable next button */ + EnableWindow(GetDlgItem(hwndDlg, IDC_BUTTON_NEXT), + (CurSel != TabCtrl_GetItemCount(hTabCtrlWnd) - 1)); + + /* switch to next page */ + SendMessageW(hTabCtrlWnd, TCM_SETCURSEL, CurSel, 0L); + return TRUE; } @@ -210,6 +220,12 @@ DxDiagWndProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) pnmh = (LPNMHDR)lParam; if ((pnmh->hwndFrom == hTabCtrlWnd) && (pnmh->idFrom == IDC_TAB_CONTROL) && (pnmh->code == TCN_SELCHANGE)) { + INT CurSel = TabCtrl_GetCurSel(hTabCtrlWnd); + + /* enable/disable next button */ + EnableWindow(GetDlgItem(hwndDlg, IDC_BUTTON_NEXT), + (CurSel != TabCtrl_GetItemCount(hTabCtrlWnd) - 1)); + TabCtrl_OnSelChange(pContext); } break; diff --git a/reactos/base/applications/dxdiag/system.c b/reactos/base/applications/dxdiag/system.c index 33c1f9d5bde..311fc03cdf7 100644 --- a/reactos/base/applications/dxdiag/system.c +++ b/reactos/base/applications/dxdiag/system.c @@ -17,7 +17,6 @@ GetRegValue(HKEY hBaseKey, LPWSTR SubKey, LPWSTR ValueName, DWORD Type, LPWSTR R DWORD dwType; DWORD dwSize; - if (RegOpenKeyExW(hBaseKey, SubKey, 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS) return FALSE; @@ -25,10 +24,10 @@ GetRegValue(HKEY hBaseKey, LPWSTR SubKey, LPWSTR ValueName, DWORD Type, LPWSTR R res = RegQueryValueExW(hKey, ValueName, NULL, &dwType, (LPBYTE)Result, &dwSize); RegCloseKey(hKey); - if (dwType != Type) + if (res != ERROR_SUCCESS) return FALSE; - if (res != ERROR_SUCCESS) + if (dwType != Type) return FALSE; if (Size == sizeof(DWORD)) From 76e59af8978a38530182d6468c0ed3ffd1b3bab2 Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Tue, 16 Mar 2010 11:09:19 +0000 Subject: [PATCH 39/61] [DXSDK] - Add IAMBufferNegotiation interface svn path=/trunk/; revision=46221 --- reactos/include/dxsdk/axextend.idl | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/reactos/include/dxsdk/axextend.idl b/reactos/include/dxsdk/axextend.idl index 66e43f151ca..72e37ce47c7 100644 --- a/reactos/include/dxsdk/axextend.idl +++ b/reactos/include/dxsdk/axextend.idl @@ -1070,6 +1070,22 @@ interface IAMFilterMiscFlags : IUnknown ULONG GetMiscFlags(); }; +[ + local, + object, + uuid(56ED71A0-AF5F-11D0-B3F0-00AA003761C5), + pointer_default(unique) +] +interface IAMBufferNegotiation : IUnknown +{ + HRESULT SuggestAllocatorProperties ( + [in] const ALLOCATOR_PROPERTIES *pprop); + + HRESULT GetAllocatorProperties ( + [out] ALLOCATOR_PROPERTIES *pprop); + +} + #include [ From 8012adb8031f87a092490812b7c02e28f32db1f5 Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Tue, 16 Mar 2010 11:12:19 +0000 Subject: [PATCH 40/61] [KSPROXY] - Implement IKsPinPipe for CInputPin & COutputPin - Implement IKsPinFactory, IStreamBuilder for CInputPin - Implement IKsAggregateControl, IQualityControl stub for CInputPin & COutputPin svn path=/trunk/; revision=46222 --- reactos/dll/directx/ksproxy/input_pin.cpp | 340 +++++++++- reactos/dll/directx/ksproxy/output_pin.cpp | 743 ++++++++++++++++++++- reactos/dll/directx/ksproxy/precomp.h | 3 + 3 files changed, 1057 insertions(+), 29 deletions(-) diff --git a/reactos/dll/directx/ksproxy/input_pin.cpp b/reactos/dll/directx/ksproxy/input_pin.cpp index 40d339ef894..7fec31eb92a 100644 --- a/reactos/dll/directx/ksproxy/input_pin.cpp +++ b/reactos/dll/directx/ksproxy/input_pin.cpp @@ -8,13 +8,14 @@ */ #include "precomp.h" -const GUID IID_IKsPinEx = {0x7bb38260L, 0xd19c, 0x11d2, {0xb3, 0x8a, 0x00, 0xa0, 0xc9, 0x5e, 0xc2, 0x2e}}; +const GUID IID_IKsPinPipe = {0xe539cd90, 0xa8b4, 0x11d1, {0x81, 0x89, 0x00, 0xa0, 0xc9, 0x06, 0x28, 0x02}}; +const GUID IID_IKsPinEx = {0x7bb38260L, 0xd19c, 0x11d2, {0xb3, 0x8a, 0x00, 0xa0, 0xc9, 0x5e, 0xc2, 0x2e}}; + #ifndef _MSC_VER + const GUID KSPROPSETID_Connection = {0x1D58C920L, 0xAC9B, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}}; -#endif -#ifndef _MSC_VER KSPIN_INTERFACE StandardPinInterface = { {STATIC_KSINTERFACESETID_Standard}, @@ -53,14 +54,12 @@ class CInputPin : public IPin, public IKsObject, public IKsPinEx, public IMemInputPin, - public ISpecifyPropertyPages -/* - public IQualityControl, public IKsPinPipe, - public IStreamBuilder, public IKsPinFactory, - public IKsAggregateControl -*/ + public IStreamBuilder, + public IKsAggregateControl, + public IQualityControl, + public ISpecifyPropertyPages { public: STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface); @@ -81,6 +80,19 @@ public: return m_Ref; } + //IKsPinPipe + HRESULT STDMETHODCALLTYPE KsGetPinFramingCache(PKSALLOCATOR_FRAMING_EX *FramingEx, PFRAMING_PROP FramingProp, FRAMING_CACHE_OPS Option); + HRESULT STDMETHODCALLTYPE KsSetPinFramingCache(PKSALLOCATOR_FRAMING_EX FramingEx, PFRAMING_PROP FramingProp, FRAMING_CACHE_OPS Option); + IPin* STDMETHODCALLTYPE KsGetConnectedPin(); + IKsAllocatorEx* STDMETHODCALLTYPE KsGetPipe(KSPEEKOPERATION Operation); + HRESULT STDMETHODCALLTYPE KsSetPipe(IKsAllocatorEx *KsAllocator); + ULONG STDMETHODCALLTYPE KsGetPipeAllocatorFlag(); + HRESULT STDMETHODCALLTYPE KsSetPipeAllocatorFlag(ULONG Flag); + GUID STDMETHODCALLTYPE KsGetPinBusCache(); + HRESULT STDMETHODCALLTYPE KsSetPinBusCache(GUID Bus); + PWCHAR STDMETHODCALLTYPE KsGetPinName(); + PWCHAR STDMETHODCALLTYPE KsGetFilterName(); + //IPin methods HRESULT STDMETHODCALLTYPE Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt); HRESULT STDMETHODCALLTYPE ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt); @@ -139,11 +151,26 @@ public: HRESULT STDMETHODCALLTYPE ReceiveMultiple(IMediaSample **pSamples, long nSamples, long *nSamplesProcessed); HRESULT STDMETHODCALLTYPE ReceiveCanBlock( void); + //IKsPinFactory + HRESULT STDMETHODCALLTYPE KsPinFactory(ULONG* PinFactory); + + //IStreamBuilder + HRESULT STDMETHODCALLTYPE Render(IPin *ppinOut, IGraphBuilder *pGraph); + HRESULT STDMETHODCALLTYPE Backout(IPin *ppinOut, IGraphBuilder *pGraph); + + //IKsAggregateControl + HRESULT STDMETHODCALLTYPE KsAddAggregate(IN REFGUID AggregateClass); + HRESULT STDMETHODCALLTYPE KsRemoveAggregate(REFGUID AggregateClass); + + //IQualityControl + HRESULT STDMETHODCALLTYPE Notify(IBaseFilter *pSelf, Quality q); + HRESULT STDMETHODCALLTYPE SetSink(IQualityControl *piqc); + //--------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CheckFormat(const AM_MEDIA_TYPE *pmt); HRESULT STDMETHODCALLTYPE CreatePin(const AM_MEDIA_TYPE *pmt); HRESULT STDMETHODCALLTYPE CreatePinHandle(PKSPIN_MEDIUM Medium, PKSPIN_INTERFACE Interface, const AM_MEDIA_TYPE *pmt); - CInputPin(IBaseFilter * ParentFilter, LPCWSTR PinName, HANDLE hFilter, ULONG PinId, KSPIN_COMMUNICATION Communication) : m_Ref(0), m_ParentFilter(ParentFilter), m_PinName(PinName), m_hFilter(hFilter), m_hPin(INVALID_HANDLE_VALUE), m_PinId(PinId), m_MemAllocator(0), m_IoCount(0), m_Communication(Communication), m_Pin(0), m_ReadOnly(0), m_InterfaceHandler(0){}; + CInputPin(IBaseFilter * ParentFilter, LPCWSTR PinName, HANDLE hFilter, ULONG PinId, KSPIN_COMMUNICATION Communication); virtual ~CInputPin(){}; protected: @@ -161,8 +188,41 @@ protected: IPin * m_Pin; BOOL m_ReadOnly; IKsInterfaceHandler * m_InterfaceHandler; + IKsAllocatorEx * m_KsAllocatorEx; + ULONG m_PipeAllocatorFlag; + BOOL m_bPinBusCacheInitialized; + GUID m_PinBusCache; + LPWSTR m_FilterName; + FRAMING_PROP m_FramingProp[4]; + PKSALLOCATOR_FRAMING_EX m_FramingEx[4]; }; +CInputPin::CInputPin( + IBaseFilter * ParentFilter, + LPCWSTR PinName, + HANDLE hFilter, + ULONG PinId, + KSPIN_COMMUNICATION Communication) : m_Ref(0), + m_ParentFilter(ParentFilter), + m_PinName(PinName), + m_hFilter(hFilter), + m_hPin(INVALID_HANDLE_VALUE), + m_PinId(PinId), + m_MemAllocator(0), + m_IoCount(0), + m_Communication(Communication), + m_Pin(0), + m_ReadOnly(0), + m_InterfaceHandler(0), + m_KsAllocatorEx(0), + m_PipeAllocatorFlag(0), + m_bPinBusCacheInitialized(0), + m_FilterName(0) +{ + ZeroMemory(m_FramingProp, sizeof(m_FramingProp)); + ZeroMemory(m_FramingEx, sizeof(m_FramingEx)); +} + HRESULT STDMETHODCALLTYPE CInputPin::QueryInterface( @@ -209,6 +269,38 @@ CInputPin::QueryInterface( reinterpret_cast(*Output)->AddRef(); return NOERROR; } + else if (IsEqualGUID(refiid, IID_IKsPinPipe)) + { + *Output = (IKsPinPipe*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } + else if (IsEqualGUID(refiid, IID_IKsPinFactory)) + { + *Output = (IKsPinFactory*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } +#if 0 + else if (IsEqualGUID(refiid, IID_IStreamBuilder)) + { + *Output = (IStreamBuilder*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } +#endif + else if (IsEqualGUID(refiid, IID_IKsAggregateControl)) + { + *Output = (IKsAggregateControl*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } + else if (IsEqualGUID(refiid, IID_IQualityControl)) + { + *Output = (IQualityControl*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } else if (IsEqualGUID(refiid, IID_ISpecifyPropertyPages)) { *Output = (ISpecifyPropertyPages*)(this); @@ -225,6 +317,232 @@ CInputPin::QueryInterface( return E_NOINTERFACE; } +//------------------------------------------------------------------- +// IQualityControl interface +// +HRESULT +STDMETHODCALLTYPE +CInputPin::Notify( + IBaseFilter *pSelf, + Quality q) +{ + OutputDebugStringW(L"CInputPin::Notify NotImplemented\n"); + return E_NOTIMPL; +} + +HRESULT +STDMETHODCALLTYPE +CInputPin::SetSink( + IQualityControl *piqc) +{ + OutputDebugStringW(L"CInputPin::SetSink NotImplemented\n"); + return E_NOTIMPL; +} + + +//------------------------------------------------------------------- +// IKsAggregateControl interface +// +HRESULT +STDMETHODCALLTYPE +CInputPin::KsAddAggregate( + IN REFGUID AggregateClass) +{ + OutputDebugStringW(L"CInputPin::KsAddAggregate NotImplemented\n"); + return E_NOTIMPL; +} + +HRESULT +STDMETHODCALLTYPE +CInputPin::KsRemoveAggregate( + REFGUID AggregateClass) +{ + OutputDebugStringW(L"CInputPin::KsRemoveAggregate NotImplemented\n"); + return E_NOTIMPL; +} + +//------------------------------------------------------------------- +// IStreamBuilder +// + +HRESULT +STDMETHODCALLTYPE +CInputPin::Render( + IPin *ppinOut, + IGraphBuilder *pGraph) +{ + OutputDebugStringW(L"CInputPin::Render\n"); + return S_OK; +} + +HRESULT +STDMETHODCALLTYPE +CInputPin::Backout( + IPin *ppinOut, + IGraphBuilder *pGraph) +{ + OutputDebugStringW(L"CInputPin::Backout\n"); + return S_OK; +} + +//------------------------------------------------------------------- +// IKsPinFactory +// + +HRESULT +STDMETHODCALLTYPE +CInputPin::KsPinFactory( + ULONG* PinFactory) +{ + OutputDebugStringW(L"CInputPin::KsPinFactory\n"); + *PinFactory = m_PinId; + return S_OK; +} + +//------------------------------------------------------------------- +// IKsPinPipe +// + +HRESULT +STDMETHODCALLTYPE +CInputPin::KsGetPinFramingCache( + PKSALLOCATOR_FRAMING_EX *FramingEx, + PFRAMING_PROP FramingProp, + FRAMING_CACHE_OPS Option) +{ + if (Option > Framing_Cache_Write || Option < Framing_Cache_ReadLast) + { + // invalid argument + return E_INVALIDARG; + } + + // get framing properties + *FramingProp = m_FramingProp[Option]; + *FramingEx = m_FramingEx[Option]; + + return NOERROR; +} + +HRESULT +STDMETHODCALLTYPE +CInputPin::KsSetPinFramingCache( + PKSALLOCATOR_FRAMING_EX FramingEx, + PFRAMING_PROP FramingProp, + FRAMING_CACHE_OPS Option) +{ + ULONG Index; + ULONG RefCount = 0; + + if (m_FramingEx[Option]) + { + for(Index = 1; Index < 4; Index++) + { + if (m_FramingEx[Index] == m_FramingEx[Option]) + RefCount++; + } + + if (RefCount == 1) + { + // existing framing is only used once + CoTaskMemFree(m_FramingEx[Option]); + } + } + + // store framing + m_FramingEx[Option] = FramingEx; + m_FramingProp[Option] = *FramingProp; + + return S_OK; +} + +IPin* +STDMETHODCALLTYPE +CInputPin::KsGetConnectedPin() +{ + return m_Pin; +} + +IKsAllocatorEx* +STDMETHODCALLTYPE +CInputPin::KsGetPipe( + KSPEEKOPERATION Operation) +{ + if (Operation == KsPeekOperation_AddRef) + { + if (m_KsAllocatorEx) + m_KsAllocatorEx->AddRef(); + } + return m_KsAllocatorEx; +} + +HRESULT +STDMETHODCALLTYPE +CInputPin::KsSetPipe( + IKsAllocatorEx *KsAllocator) +{ + if (KsAllocator) + KsAllocator->AddRef(); + + if (m_KsAllocatorEx) + m_KsAllocatorEx->Release(); + + m_KsAllocatorEx = KsAllocator; + return NOERROR; +} + +ULONG +STDMETHODCALLTYPE +CInputPin::KsGetPipeAllocatorFlag() +{ + return m_PipeAllocatorFlag; +} + + +HRESULT +STDMETHODCALLTYPE +CInputPin::KsSetPipeAllocatorFlag( + ULONG Flag) +{ + m_PipeAllocatorFlag = Flag; + return NOERROR; +} + +GUID +STDMETHODCALLTYPE +CInputPin::KsGetPinBusCache() +{ + if (!m_bPinBusCacheInitialized) + { + CopyMemory(&m_PinBusCache, &m_Medium.Set, sizeof(GUID)); + m_bPinBusCacheInitialized = TRUE; + } + + return m_PinBusCache; +} + +HRESULT +STDMETHODCALLTYPE +CInputPin::KsSetPinBusCache( + GUID Bus) +{ + CopyMemory(&m_PinBusCache, &Bus, sizeof(GUID)); + return NOERROR; +} + +PWCHAR +STDMETHODCALLTYPE +CInputPin::KsGetPinName() +{ + return (PWCHAR)m_PinName; +} + + +PWCHAR +STDMETHODCALLTYPE +CInputPin::KsGetFilterName() +{ + return m_FilterName; +} //------------------------------------------------------------------- // ISpecifyPropertyPages @@ -325,7 +643,6 @@ CInputPin::ReceiveCanBlock( void) return S_FALSE; } - //------------------------------------------------------------------- // IKsPin // @@ -854,6 +1171,7 @@ CInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) return E_NOTIMPL; } + //------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE diff --git a/reactos/dll/directx/ksproxy/output_pin.cpp b/reactos/dll/directx/ksproxy/output_pin.cpp index b17fffa84bd..0224bd62541 100644 --- a/reactos/dll/directx/ksproxy/output_pin.cpp +++ b/reactos/dll/directx/ksproxy/output_pin.cpp @@ -1,34 +1,29 @@ /* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS WDM Streaming ActiveMovie Proxy - * FILE: dll/directx/ksproxy/input_cpp.cpp - * PURPOSE: InputPin of Proxy Filter + * FILE: dll/directx/ksproxy/Output_cpp.cpp + * PURPOSE: OutputPin of Proxy Filter * * PROGRAMMERS: Johannes Anderwald (janderwald@reactos.org) */ #include "precomp.h" -#ifndef _MSC_VER -const GUID IID_IKsPinFactory = {0xCD5EBE6BL, 0x8B6E, 0x11D1, {0x8A, 0xE0, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}}; -#endif - class COutputPin : public IPin, public IKsObject, public IKsPropertySet, public IStreamBuilder, public IKsPinFactory, public ISpecifyPropertyPages, -// public IKsPinPipe, - public IKsControl -/* - public IAMBufferNegotiation, - public IQualityControl, - public IKsPinEx, - public IKsAggregateControl - public IMediaSeeking, - public IAMStreamConfig, - public IMemAllocatorNotifyCallbackTemp -*/ + public IKsPinEx, + public IKsPinPipe, + public IKsControl, + public IKsAggregateControl, + public IQualityControl, + public IMediaSeeking, + public IAMBufferNegotiation, + public IAMStreamConfig, + public IMemAllocatorNotifyCallbackTemp + { public: STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface); @@ -49,6 +44,23 @@ public: return m_Ref; } + //IKsPin + HRESULT STDMETHODCALLTYPE KsQueryMediums(PKSMULTIPLE_ITEM* MediumList); + HRESULT STDMETHODCALLTYPE KsQueryInterfaces(PKSMULTIPLE_ITEM* InterfaceList); + HRESULT STDMETHODCALLTYPE KsCreateSinkPinHandle(KSPIN_INTERFACE& Interface, KSPIN_MEDIUM& Medium); + HRESULT STDMETHODCALLTYPE KsGetCurrentCommunication(KSPIN_COMMUNICATION *Communication, KSPIN_INTERFACE *Interface, KSPIN_MEDIUM *Medium); + HRESULT STDMETHODCALLTYPE KsPropagateAcquire(); + HRESULT STDMETHODCALLTYPE KsDeliver(IMediaSample* Sample, ULONG Flags); + HRESULT STDMETHODCALLTYPE KsMediaSamplesCompleted(PKSSTREAM_SEGMENT StreamSegment); + IMemAllocator * STDMETHODCALLTYPE KsPeekAllocator(KSPEEKOPERATION Operation); + HRESULT STDMETHODCALLTYPE KsReceiveAllocator(IMemAllocator *MemAllocator); + HRESULT STDMETHODCALLTYPE KsRenegotiateAllocator(); + LONG STDMETHODCALLTYPE KsIncrementPendingIoCount(); + LONG STDMETHODCALLTYPE KsDecrementPendingIoCount(); + HRESULT STDMETHODCALLTYPE KsQualityNotify(ULONG Proportion, REFERENCE_TIME TimeDelta); + // IKsPinEx + VOID STDMETHODCALLTYPE KsNotifyError(IMediaSample* Sample, HRESULT hr); + //IKsPinPipe HRESULT STDMETHODCALLTYPE KsGetPinFramingCache(PKSALLOCATOR_FRAMING_EX *FramingEx, PFRAMING_PROP FramingProp, FRAMING_CACHE_OPS Option); HRESULT STDMETHODCALLTYPE KsSetPinFramingCache(PKSALLOCATOR_FRAMING_EX FramingEx, PFRAMING_PROP FramingProp, FRAMING_CACHE_OPS Option); @@ -102,6 +114,46 @@ public: //IKsPinFactory HRESULT STDMETHODCALLTYPE KsPinFactory(ULONG* PinFactory); + //IKsAggregateControl + HRESULT STDMETHODCALLTYPE KsAddAggregate(IN REFGUID AggregateClass); + HRESULT STDMETHODCALLTYPE KsRemoveAggregate(REFGUID AggregateClass); + + //IQualityControl + HRESULT STDMETHODCALLTYPE Notify(IBaseFilter *pSelf, Quality q); + HRESULT STDMETHODCALLTYPE SetSink(IQualityControl *piqc); + + //IMediaSeeking + HRESULT STDMETHODCALLTYPE GetCapabilities(DWORD *pCapabilities); + HRESULT STDMETHODCALLTYPE CheckCapabilities(DWORD *pCapabilities); + HRESULT STDMETHODCALLTYPE IsFormatSupported(const GUID *pFormat); + HRESULT STDMETHODCALLTYPE QueryPreferredFormat(GUID *pFormat); + HRESULT STDMETHODCALLTYPE GetTimeFormat(GUID *pFormat); + HRESULT STDMETHODCALLTYPE IsUsingTimeFormat(const GUID *pFormat); + HRESULT STDMETHODCALLTYPE SetTimeFormat(const GUID *pFormat); + HRESULT STDMETHODCALLTYPE GetDuration(LONGLONG *pDuration); + HRESULT STDMETHODCALLTYPE GetStopPosition(LONGLONG *pStop); + HRESULT STDMETHODCALLTYPE GetCurrentPosition(LONGLONG *pCurrent); + HRESULT STDMETHODCALLTYPE ConvertTimeFormat(LONGLONG *pTarget, const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat); + HRESULT STDMETHODCALLTYPE SetPositions(LONGLONG *pCurrent, DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags); + HRESULT STDMETHODCALLTYPE GetPositions(LONGLONG *pCurrent, LONGLONG *pStop); + HRESULT STDMETHODCALLTYPE GetAvailable(LONGLONG *pEarliest, LONGLONG *pLatest); + HRESULT STDMETHODCALLTYPE SetRate(double dRate); + HRESULT STDMETHODCALLTYPE GetRate(double *pdRate); + HRESULT STDMETHODCALLTYPE GetPreroll(LONGLONG *pllPreroll); + + //IAMBufferNegotiation + HRESULT STDMETHODCALLTYPE SuggestAllocatorProperties(const ALLOCATOR_PROPERTIES *pprop); + HRESULT STDMETHODCALLTYPE GetAllocatorProperties(ALLOCATOR_PROPERTIES *pprop); + + //IAMStreamConfig + HRESULT STDMETHODCALLTYPE SetFormat(AM_MEDIA_TYPE *pmt); + HRESULT STDMETHODCALLTYPE GetFormat(AM_MEDIA_TYPE **ppmt); + HRESULT STDMETHODCALLTYPE GetNumberOfCapabilities(int *piCount, int *piSize); + HRESULT STDMETHODCALLTYPE GetStreamCaps(int iIndex, AM_MEDIA_TYPE **ppmt, BYTE *pSCC); + + //IMemAllocatorNotifyCallbackTemp + HRESULT STDMETHODCALLTYPE NotifyRelease(); + COutputPin(IBaseFilter * ParentFilter, LPCWSTR PinName, ULONG PinId); virtual ~COutputPin(); @@ -113,6 +165,20 @@ protected: ULONG m_PinId; IKsObject * m_KsObjectParent; IPin * m_Pin; + IKsAllocatorEx * m_KsAllocatorEx; + ULONG m_PipeAllocatorFlag; + BOOL m_bPinBusCacheInitialized; + GUID m_PinBusCache; + LPWSTR m_FilterName; + FRAMING_PROP m_FramingProp[4]; + PKSALLOCATOR_FRAMING_EX m_FramingEx[4]; + + IMemAllocator * m_MemAllocator; + LONG m_IoCount; + KSPIN_COMMUNICATION m_Communication; + KSPIN_INTERFACE m_Interface; + KSPIN_MEDIUM m_Medium; + IMediaSeeking * m_FilterMediaSeeking; }; COutputPin::~COutputPin() @@ -124,13 +190,32 @@ COutputPin::~COutputPin() COutputPin::COutputPin( IBaseFilter * ParentFilter, LPCWSTR PinName, - ULONG PinId) : m_Ref(0), m_ParentFilter(ParentFilter), m_PinName(PinName), m_hPin(INVALID_HANDLE_VALUE), m_PinId(PinId), m_KsObjectParent(0), m_Pin(0) + ULONG PinId) : m_Ref(0), + m_ParentFilter(ParentFilter), + m_PinName(PinName), + m_hPin(INVALID_HANDLE_VALUE), + m_PinId(PinId), + m_KsObjectParent(0), + m_Pin(0), + m_KsAllocatorEx(0), + m_PipeAllocatorFlag(0), + m_bPinBusCacheInitialized(0), + m_FilterName(0), + m_MemAllocator(0), + m_IoCount(0), + m_Communication(KSPIN_COMMUNICATION_NONE), + m_FilterMediaSeeking(0) { HRESULT hr; hr = m_ParentFilter->QueryInterface(IID_IKsObject, (LPVOID*)&m_KsObjectParent); assert(hr == S_OK); + hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&m_FilterMediaSeeking); + assert(hr == S_OK); + + ZeroMemory(m_FramingProp, sizeof(m_FramingProp)); + ZeroMemory(m_FramingEx, sizeof(m_FramingEx)); }; HRESULT @@ -155,6 +240,30 @@ COutputPin::QueryInterface( reinterpret_cast(*Output)->AddRef(); return NOERROR; } + else if (IsEqualGUID(refiid, IID_IKsPin) || IsEqualGUID(refiid, IID_IKsPinEx)) + { + *Output = (IKsPinEx*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } + else if (IsEqualGUID(refiid, IID_IKsPinPipe)) + { + *Output = (IKsPinPipe*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } + else if (IsEqualGUID(refiid, IID_IKsAggregateControl)) + { + *Output = (IKsAggregateControl*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } + else if (IsEqualGUID(refiid, IID_IQualityControl)) + { + *Output = (IQualityControl*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } else if (IsEqualGUID(refiid, IID_IKsPropertySet)) { OutputDebugStringW(L"COutputPin::QueryInterface IID_IKsPropertySet\n"); @@ -192,6 +301,30 @@ COutputPin::QueryInterface( reinterpret_cast(*Output)->AddRef(); return NOERROR; } + else if (IsEqualGUID(refiid, IID_IMediaSeeking)) + { + *Output = (IMediaSeeking*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } + else if (IsEqualGUID(refiid, IID_IAMBufferNegotiation)) + { + *Output = (IAMBufferNegotiation*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } + else if (IsEqualGUID(refiid, IID_IAMStreamConfig)) + { + *Output = (IAMStreamConfig*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } + else if (IsEqualGUID(refiid, IID_IMemAllocatorNotifyCallbackTemp)) + { + *Output = (IMemAllocatorNotifyCallbackTemp*)(this); + reinterpret_cast(*Output)->AddRef(); + return NOERROR; + } WCHAR Buffer[MAX_PATH]; LPOLESTR lpstr; @@ -203,6 +336,580 @@ COutputPin::QueryInterface( return E_NOINTERFACE; } +//------------------------------------------------------------------- +// IAMBufferNegotiation interface +// +HRESULT +STDMETHODCALLTYPE +COutputPin::SuggestAllocatorProperties( + const ALLOCATOR_PROPERTIES *pprop) +{ + OutputDebugStringW(L"COutputPin::SuggestAllocatorProperties NotImplemented\n"); + return E_NOTIMPL; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::GetAllocatorProperties( + ALLOCATOR_PROPERTIES *pprop) +{ + OutputDebugStringW(L"COutputPin::GetAllocatorProperties NotImplemented\n"); + return E_NOTIMPL; +} + +//------------------------------------------------------------------- +// IAMStreamConfig interface +// +HRESULT +STDMETHODCALLTYPE +COutputPin::SetFormat( + AM_MEDIA_TYPE *pmt) +{ + OutputDebugStringW(L"COutputPin::SetFormat NotImplemented\n"); + return E_NOTIMPL; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::GetFormat(AM_MEDIA_TYPE **ppmt) +{ + OutputDebugStringW(L"COutputPin::GetFormat NotImplemented\n"); + return E_NOTIMPL; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::GetNumberOfCapabilities( + int *piCount, + int *piSize) +{ + OutputDebugStringW(L"COutputPin::GetNumberOfCapabilities NotImplemented\n"); + return E_NOTIMPL; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::GetStreamCaps( + int iIndex, + AM_MEDIA_TYPE **ppmt, + BYTE *pSCC) +{ + OutputDebugStringW(L"COutputPin::GetStreamCaps NotImplemented\n"); + return E_NOTIMPL; +} + +//------------------------------------------------------------------- +// IMemAllocatorNotifyCallbackTemp interface +// +HRESULT +STDMETHODCALLTYPE +COutputPin::NotifyRelease() +{ + OutputDebugStringW(L"COutputPin::NotifyRelease NotImplemented\n"); + return E_NOTIMPL; +} + +//------------------------------------------------------------------- +// IMediaSeeking interface +// +HRESULT +STDMETHODCALLTYPE +COutputPin::GetCapabilities( + DWORD *pCapabilities) +{ + return m_FilterMediaSeeking->GetCapabilities(pCapabilities); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::CheckCapabilities( + DWORD *pCapabilities) +{ + return m_FilterMediaSeeking->CheckCapabilities(pCapabilities); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::IsFormatSupported( + const GUID *pFormat) +{ + return m_FilterMediaSeeking->IsFormatSupported(pFormat); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::QueryPreferredFormat( + GUID *pFormat) +{ + return m_FilterMediaSeeking->QueryPreferredFormat(pFormat); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::GetTimeFormat( + GUID *pFormat) +{ + return m_FilterMediaSeeking->GetTimeFormat(pFormat); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::IsUsingTimeFormat( + const GUID *pFormat) +{ + return m_FilterMediaSeeking->IsUsingTimeFormat(pFormat); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::SetTimeFormat( + const GUID *pFormat) +{ + return m_FilterMediaSeeking->SetTimeFormat(pFormat); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::GetDuration( + LONGLONG *pDuration) +{ + return m_FilterMediaSeeking->GetDuration(pDuration); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::GetStopPosition( + LONGLONG *pStop) +{ + return m_FilterMediaSeeking->GetStopPosition(pStop); +} + + +HRESULT +STDMETHODCALLTYPE +COutputPin::GetCurrentPosition( + LONGLONG *pCurrent) +{ + return m_FilterMediaSeeking->GetCurrentPosition(pCurrent); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::ConvertTimeFormat( + LONGLONG *pTarget, + const GUID *pTargetFormat, + LONGLONG Source, + const GUID *pSourceFormat) +{ + return m_FilterMediaSeeking->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::SetPositions( + LONGLONG *pCurrent, + DWORD dwCurrentFlags, + LONGLONG *pStop, + DWORD dwStopFlags) +{ + return m_FilterMediaSeeking->SetPositions(pCurrent, dwCurrentFlags, pStop, dwStopFlags); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::GetPositions( + LONGLONG *pCurrent, + LONGLONG *pStop) +{ + return m_FilterMediaSeeking->GetPositions(pCurrent, pStop); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::GetAvailable( + LONGLONG *pEarliest, + LONGLONG *pLatest) +{ + return m_FilterMediaSeeking->GetAvailable(pEarliest, pLatest); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::SetRate( + double dRate) +{ + return m_FilterMediaSeeking->SetRate(dRate); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::GetRate( + double *pdRate) +{ + return m_FilterMediaSeeking->GetRate(pdRate); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::GetPreroll( + LONGLONG *pllPreroll) +{ + return m_FilterMediaSeeking->GetPreroll(pllPreroll); +} + +//------------------------------------------------------------------- +// IQualityControl interface +// +HRESULT +STDMETHODCALLTYPE +COutputPin::Notify( + IBaseFilter *pSelf, + Quality q) +{ + OutputDebugStringW(L"COutputPin::Notify NotImplemented\n"); + return E_NOTIMPL; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::SetSink( + IQualityControl *piqc) +{ + OutputDebugStringW(L"COutputPin::SetSink NotImplemented\n"); + return E_NOTIMPL; +} + + +//------------------------------------------------------------------- +// IKsAggregateControl interface +// +HRESULT +STDMETHODCALLTYPE +COutputPin::KsAddAggregate( + IN REFGUID AggregateClass) +{ + OutputDebugStringW(L"COutputPin::KsAddAggregate NotImplemented\n"); + return E_NOTIMPL; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsRemoveAggregate( + REFGUID AggregateClass) +{ + OutputDebugStringW(L"COutputPin::KsRemoveAggregate NotImplemented\n"); + return E_NOTIMPL; +} + + +//------------------------------------------------------------------- +// IKsPin +// + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsQueryMediums( + PKSMULTIPLE_ITEM* MediumList) +{ + HANDLE hFilter = m_KsObjectParent->KsGetObjectHandle(); + return KsGetMultiplePinFactoryItems(hFilter, m_PinId, KSPROPERTY_PIN_MEDIUMS, (PVOID*)MediumList); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsQueryInterfaces( + PKSMULTIPLE_ITEM* InterfaceList) +{ + HANDLE hFilter = m_KsObjectParent->KsGetObjectHandle(); + + return KsGetMultiplePinFactoryItems(hFilter, m_PinId, KSPROPERTY_PIN_INTERFACES, (PVOID*)InterfaceList); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsCreateSinkPinHandle( + KSPIN_INTERFACE& Interface, + KSPIN_MEDIUM& Medium) +{ + OutputDebugStringW(L"COutputPin::KsCreateSinkPinHandle NotImplemented\n"); + return E_NOTIMPL; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsGetCurrentCommunication( + KSPIN_COMMUNICATION *Communication, + KSPIN_INTERFACE *Interface, + KSPIN_MEDIUM *Medium) +{ + if (Communication) + { + *Communication = m_Communication; + } + + if (Interface) + { + if (!m_hPin) + return VFW_E_NOT_CONNECTED; + + CopyMemory(Interface, &m_Interface, sizeof(KSPIN_INTERFACE)); + } + + if (Medium) + { + if (!m_hPin) + return VFW_E_NOT_CONNECTED; + + CopyMemory(Medium, &m_Medium, sizeof(KSPIN_MEDIUM)); + } + return NOERROR; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsPropagateAcquire() +{ + OutputDebugStringW(L"COutputPin::KsPropagateAcquire NotImplemented\n"); + return E_NOTIMPL; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsDeliver( + IMediaSample* Sample, + ULONG Flags) +{ + return E_FAIL; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsMediaSamplesCompleted(PKSSTREAM_SEGMENT StreamSegment) +{ + return NOERROR; +} + +IMemAllocator * +STDMETHODCALLTYPE +COutputPin::KsPeekAllocator(KSPEEKOPERATION Operation) +{ + if (Operation == KsPeekOperation_AddRef) + { + // add reference on allocator + m_MemAllocator->AddRef(); + } + + return m_MemAllocator; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsReceiveAllocator(IMemAllocator *MemAllocator) +{ + if (MemAllocator) + { + MemAllocator->AddRef(); + } + + if (m_MemAllocator) + { + m_MemAllocator->Release(); + } + + m_MemAllocator = MemAllocator; + return NOERROR; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsRenegotiateAllocator() +{ + return E_FAIL; +} + +LONG +STDMETHODCALLTYPE +COutputPin::KsIncrementPendingIoCount() +{ + return InterlockedIncrement((volatile LONG*)&m_IoCount); +} + +LONG +STDMETHODCALLTYPE +COutputPin::KsDecrementPendingIoCount() +{ + return InterlockedDecrement((volatile LONG*)&m_IoCount); +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsQualityNotify( + ULONG Proportion, + REFERENCE_TIME TimeDelta) +{ + OutputDebugStringW(L"COutputPin::KsQualityNotify NotImplemented\n"); + return E_NOTIMPL; +} + +//------------------------------------------------------------------- +// IKsPinEx +// + +VOID +STDMETHODCALLTYPE +COutputPin::KsNotifyError( + IMediaSample* Sample, + HRESULT hr) +{ + OutputDebugStringW(L"COutputPin::KsNotifyError NotImplemented\n"); +} + + +//------------------------------------------------------------------- +// IKsPinPipe +// + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsGetPinFramingCache( + PKSALLOCATOR_FRAMING_EX *FramingEx, + PFRAMING_PROP FramingProp, + FRAMING_CACHE_OPS Option) +{ + if (Option > Framing_Cache_Write || Option < Framing_Cache_ReadLast) + { + // invalid argument + return E_INVALIDARG; + } + + // get framing properties + *FramingProp = m_FramingProp[Option]; + *FramingEx = m_FramingEx[Option]; + + return NOERROR; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsSetPinFramingCache( + PKSALLOCATOR_FRAMING_EX FramingEx, + PFRAMING_PROP FramingProp, + FRAMING_CACHE_OPS Option) +{ + ULONG Index; + ULONG RefCount = 0; + + if (m_FramingEx[Option]) + { + for(Index = 1; Index < 4; Index++) + { + if (m_FramingEx[Index] == m_FramingEx[Option]) + RefCount++; + } + + if (RefCount == 1) + { + // existing framing is only used once + CoTaskMemFree(m_FramingEx[Option]); + } + } + + // store framing + m_FramingEx[Option] = FramingEx; + m_FramingProp[Option] = *FramingProp; + + return S_OK; +} + +IPin* +STDMETHODCALLTYPE +COutputPin::KsGetConnectedPin() +{ + return m_Pin; +} + +IKsAllocatorEx* +STDMETHODCALLTYPE +COutputPin::KsGetPipe( + KSPEEKOPERATION Operation) +{ + if (Operation == KsPeekOperation_AddRef) + { + if (m_KsAllocatorEx) + m_KsAllocatorEx->AddRef(); + } + return m_KsAllocatorEx; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsSetPipe( + IKsAllocatorEx *KsAllocator) +{ + if (KsAllocator) + KsAllocator->AddRef(); + + if (m_KsAllocatorEx) + m_KsAllocatorEx->Release(); + + m_KsAllocatorEx = KsAllocator; + return NOERROR; +} + +ULONG +STDMETHODCALLTYPE +COutputPin::KsGetPipeAllocatorFlag() +{ + return m_PipeAllocatorFlag; +} + + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsSetPipeAllocatorFlag( + ULONG Flag) +{ + m_PipeAllocatorFlag = Flag; + return NOERROR; +} + +GUID +STDMETHODCALLTYPE +COutputPin::KsGetPinBusCache() +{ + if (!m_bPinBusCacheInitialized) + { + CopyMemory(&m_PinBusCache, &m_Medium.Set, sizeof(GUID)); + m_bPinBusCacheInitialized = TRUE; + } + + return m_PinBusCache; +} + +HRESULT +STDMETHODCALLTYPE +COutputPin::KsSetPinBusCache( + GUID Bus) +{ + CopyMemory(&m_PinBusCache, &Bus, sizeof(GUID)); + return NOERROR; +} + +PWCHAR +STDMETHODCALLTYPE +COutputPin::KsGetPinName() +{ + return (PWCHAR)m_PinName; +} + + +PWCHAR +STDMETHODCALLTYPE +COutputPin::KsGetFilterName() +{ + return m_FilterName; +} + //------------------------------------------------------------------- // ISpecifyPropertyPages // diff --git a/reactos/dll/directx/ksproxy/precomp.h b/reactos/dll/directx/ksproxy/precomp.h index 21cd4eb2e27..2ea89aa0887 100644 --- a/reactos/dll/directx/ksproxy/precomp.h +++ b/reactos/dll/directx/ksproxy/precomp.h @@ -167,3 +167,6 @@ CKsNode_Constructor( extern const GUID IID_IKsObject; extern const GUID IID_IKsPinEx; +extern const GUID IID_IKsAggregateControl; +extern const GUID IID_IKsPinPipe; +extern const GUID IID_IKsPinFactory; From 8d09720a18bf6795a94eb933260ce97956a7edf7 Mon Sep 17 00:00:00 2001 From: Christoph von Wittich Date: Tue, 16 Mar 2010 12:02:45 +0000 Subject: [PATCH 41/61] [SHELL32] sync SHNotifyCopyFileW to wine 1.1.40 svn path=/trunk/; revision=46223 --- reactos/dll/win32/shell32/shlfileop.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/reactos/dll/win32/shell32/shlfileop.c b/reactos/dll/win32/shell32/shlfileop.c index e3bdf6eac31..6992d187ee4 100644 --- a/reactos/dll/win32/shell32/shlfileop.c +++ b/reactos/dll/win32/shell32/shlfileop.c @@ -531,9 +531,15 @@ static DWORD SHNotifyMoveFileW(LPCWSTR src, LPCWSTR dest) static DWORD SHNotifyCopyFileW(LPCWSTR src, LPCWSTR dest, BOOL bFailIfExists) { BOOL ret; + DWORD attribs; TRACE("(%s %s %s)\n", debugstr_w(src), debugstr_w(dest), bFailIfExists ? "failIfExists" : ""); + /* Destination file may already exist with read only attribute */ + attribs = GetFileAttributesW(dest); + if (IsAttrib(attribs, FILE_ATTRIBUTE_READONLY)) + SetFileAttributesW(dest, attribs & ~FILE_ATTRIBUTE_READONLY); + ret = CopyFileW(src, dest, bFailIfExists); if (ret) { @@ -1479,7 +1485,7 @@ int WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp) /************************************************************************* * SHFreeNameMappings [shell32.246] * - * Free the mapping handle returned by SHFileoperation if FOF_WANTSMAPPINGHANDLE + * Free the mapping handle returned by SHFileOperation if FOF_WANTSMAPPINGHANDLE * was specified. * * PARAMS @@ -1496,12 +1502,12 @@ void WINAPI SHFreeNameMappings(HANDLE hNameMapping) for (; i>= 0; i--) { - LPSHNAMEMAPPINGW lp = DSA_GetItemPtr((HDSA)hNameMapping, i); + LPSHNAMEMAPPINGW lp = DSA_GetItemPtr(hNameMapping, i); SHFree(lp->pszOldPath); SHFree(lp->pszNewPath); } - DSA_Destroy((HDSA)hNameMapping); + DSA_Destroy(hNameMapping); } } From 65a79a863e45bc0ad41fe64f6a7d6c1b8a88c436 Mon Sep 17 00:00:00 2001 From: Christoph von Wittich Date: Tue, 16 Mar 2010 12:11:39 +0000 Subject: [PATCH 42/61] [KSPROXY] fix file headers svn path=/trunk/; revision=46224 --- reactos/dll/directx/ksproxy/input_pin.cpp | 2 +- reactos/dll/directx/ksproxy/output_pin.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/reactos/dll/directx/ksproxy/input_pin.cpp b/reactos/dll/directx/ksproxy/input_pin.cpp index 7fec31eb92a..e95894f4efa 100644 --- a/reactos/dll/directx/ksproxy/input_pin.cpp +++ b/reactos/dll/directx/ksproxy/input_pin.cpp @@ -1,7 +1,7 @@ /* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS WDM Streaming ActiveMovie Proxy - * FILE: dll/directx/ksproxy/input_cpp.cpp + * FILE: dll/directx/ksproxy/input_pin.cpp * PURPOSE: InputPin of Proxy Filter * * PROGRAMMERS: Johannes Anderwald (janderwald@reactos.org) diff --git a/reactos/dll/directx/ksproxy/output_pin.cpp b/reactos/dll/directx/ksproxy/output_pin.cpp index 0224bd62541..52f9cc94f7a 100644 --- a/reactos/dll/directx/ksproxy/output_pin.cpp +++ b/reactos/dll/directx/ksproxy/output_pin.cpp @@ -1,7 +1,7 @@ /* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS WDM Streaming ActiveMovie Proxy - * FILE: dll/directx/ksproxy/Output_cpp.cpp + * FILE: dll/directx/ksproxy/output_pin.cpp * PURPOSE: OutputPin of Proxy Filter * * PROGRAMMERS: Johannes Anderwald (janderwald@reactos.org) From bdbfaa6b19d47cd88e084d46a08e9437d687ef3f Mon Sep 17 00:00:00 2001 From: Christoph von Wittich Date: Tue, 16 Mar 2010 12:26:49 +0000 Subject: [PATCH 43/61] [SHELL32] reduce diffs to wine svn path=/trunk/; revision=46225 --- reactos/dll/win32/shell32/shell32_main.c | 2 +- reactos/dll/win32/shell32/shellord.c | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/reactos/dll/win32/shell32/shell32_main.c b/reactos/dll/win32/shell32/shell32_main.c index f4ae815ade4..2bf6502443f 100644 --- a/reactos/dll/win32/shell32/shell32_main.c +++ b/reactos/dll/win32/shell32/shell32_main.c @@ -495,7 +495,7 @@ DWORD_PTR WINAPI SHGetFileInfoW(LPCWSTR path,DWORD dwFileAttributes, static const WCHAR p1W[] = {'%','1',0}; WCHAR sTemp [MAX_PATH]; - szExt = (LPWSTR) PathFindExtensionW(szFullPath); + szExt = PathFindExtensionW(szFullPath); TRACE("szExt=%s\n", debugstr_w(szExt)); if ( szExt && HCR_MapTypeToValueW(szExt, sTemp, MAX_PATH, TRUE) && diff --git a/reactos/dll/win32/shell32/shellord.c b/reactos/dll/win32/shell32/shellord.c index ff9025c4e0e..c25ddff3803 100644 --- a/reactos/dll/win32/shell32/shellord.c +++ b/reactos/dll/win32/shell32/shellord.c @@ -1673,6 +1673,14 @@ UINT WINAPI SHAddFromPropSheetExtArray(HPSXA hpsxa, LPFNADDPROPSHEETPAGE lpfnAdd return 0; } +/************************************************************************* + * SHCreatePropSheetExtArray [SHELL32.168] + */ +HPSXA WINAPI SHCreatePropSheetExtArray(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface) +{ + return SHCreatePropSheetExtArrayEx(hKey, pszSubKey, max_iface, NULL); +} + /************************************************************************* * SHCreatePropSheetExtArrayEx [SHELL32.194] */ @@ -1780,15 +1788,6 @@ HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_ return (HPSXA)psxa; } -/************************************************************************* - * SHCreatePropSheetExtArray [SHELL32.168] - */ -HPSXA WINAPI SHCreatePropSheetExtArray(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface) -{ - return SHCreatePropSheetExtArrayEx(hKey, pszSubKey, max_iface, NULL); -} - - /************************************************************************* * SHReplaceFromPropSheetExtArray [SHELL32.170] */ From 251f0e96d81eb8713ab693282e62874df56d44e7 Mon Sep 17 00:00:00 2001 From: Christoph von Wittich Date: Tue, 16 Mar 2010 17:50:04 +0000 Subject: [PATCH 44/61] [KERNEL32] reduce diff to wine svn path=/trunk/; revision=46229 --- reactos/dll/win32/kernel32/misc/profile.c | 68 ++++++++++------------- reactos/dll/win32/kernel32/misc/stubs.c | 8 --- 2 files changed, 28 insertions(+), 48 deletions(-) diff --git a/reactos/dll/win32/kernel32/misc/profile.c b/reactos/dll/win32/kernel32/misc/profile.c index 09b7c76806a..e327029f378 100644 --- a/reactos/dll/win32/kernel32/misc/profile.c +++ b/reactos/dll/win32/kernel32/misc/profile.c @@ -993,7 +993,7 @@ static INT PROFILE_GetSectionNames( LPWSTR buffer, UINT len ) * */ static INT PROFILE_GetString( LPCWSTR section, LPCWSTR key_name, - LPCWSTR def_val, LPWSTR buffer, UINT len, BOOL win32 ) + LPCWSTR def_val, LPWSTR buffer, UINT len ) { PROFILEKEY *key = NULL; static const WCHAR empty_strW[] = { 0 }; @@ -1114,16 +1114,12 @@ UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val ) return GetPrivateProfileIntW( section, entry, def_val, L"win.ini" ); } -/* - * if win32, copy: - * - Section names if 'section' is NULL - * - Keys in a Section if 'entry' is NULL - * (see MSDN doc for GetPrivateProfileString) +/*********************************************************************** + * GetPrivateProfileStringW (KERNEL32.@) */ -static int PROFILE_GetPrivateProfileString( LPCWSTR section, LPCWSTR entry, - LPCWSTR def_val, LPWSTR buffer, - UINT len, LPCWSTR filename, - BOOL win32 ) +DWORD WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry, + LPCWSTR def_val, LPWSTR buffer, + DWORD len, LPCWSTR filename ) { int ret; LPWSTR defval_tmp = NULL; @@ -1141,30 +1137,30 @@ static int PROFILE_GetPrivateProfileString( LPCWSTR section, LPCWSTR entry, if (p >= def_val) { - int len = (int)(p - def_val) + 1; + int len = (int)(p - def_val) + 1; - defval_tmp = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); - if (!defval_tmp) return 0; - memcpy(defval_tmp, def_val, len * sizeof(WCHAR)); - defval_tmp[len] = '\0'; - def_val = defval_tmp; + defval_tmp = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); + if (!defval_tmp) return 0; + memcpy(defval_tmp, def_val, len * sizeof(WCHAR)); + defval_tmp[len] = '\0'; + def_val = defval_tmp; } } RtlEnterCriticalSection( &PROFILE_CritSect ); if (PROFILE_Open( filename, FALSE )) { - if (win32 && (section == NULL)) + if (section == NULL) ret = PROFILE_GetSectionNames(buffer, len); else /* PROFILE_GetString can handle the 'entry == NULL' case */ - ret = PROFILE_GetString( section, entry, def_val, buffer, len, win32 ); + ret = PROFILE_GetString( section, entry, def_val, buffer, len ); } else if (buffer && def_val) { lstrcpynW( buffer, def_val, len ); ret = wcslen( buffer ); } - else - ret = 0; + else + ret = 0; RtlLeaveCriticalSection( &PROFILE_CritSect ); @@ -1175,7 +1171,6 @@ static int PROFILE_GetPrivateProfileString( LPCWSTR section, LPCWSTR entry, return ret; } - /*********************************************************************** * GetPrivateProfileStringA (KERNEL32.@) */ @@ -1219,21 +1214,6 @@ DWORD WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry, return ret; } -/*********************************************************************** - * GetPrivateProfileStringW (KERNEL32.@) - */ -DWORD WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry, - LPCWSTR def_val, LPWSTR buffer, - DWORD len, LPCWSTR filename ) -{ - DPRINT("(%S, %S, %S, %p, %d, %S)\n", - section, entry, def_val, buffer, len, filename); - - return PROFILE_GetPrivateProfileString( section, entry, def_val, - buffer, len, filename, TRUE ); -} - - /*********************************************************************** * GetProfileStringA (KERNEL32.@) */ @@ -1244,7 +1224,6 @@ DWORD WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val, buffer, len, "win.ini" ); } - /*********************************************************************** * GetProfileStringW (KERNEL32.@) */ @@ -1853,10 +1832,19 @@ WritePrivateProfileStructA (LPCSTR section, LPCSTR key, /*********************************************************************** - * CloseProfileUserMapping + * OpenProfileUserMapping (KERNEL32.@) */ -BOOL WINAPI -CloseProfileUserMapping(VOID) +BOOL WINAPI OpenProfileUserMapping(VOID) +{ + DPRINT1("(), stub!\n"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +/*********************************************************************** + * CloseProfileUserMapping (KERNEL32.@) + */ +BOOL WINAPI CloseProfileUserMapping(VOID) { DPRINT1("(), stub!\n"); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); diff --git a/reactos/dll/win32/kernel32/misc/stubs.c b/reactos/dll/win32/kernel32/misc/stubs.c index ecc9010d57d..d22e9baed17 100644 --- a/reactos/dll/win32/kernel32/misc/stubs.c +++ b/reactos/dll/win32/kernel32/misc/stubs.c @@ -1156,14 +1156,6 @@ OpenDataFile(HANDLE hFile, DWORD dwUnused) return FALSE; } -BOOL -WINAPI -OpenProfileUserMapping(VOID) -{ - STUB; - return FALSE; -} - BOOL WINAPI PrivMoveFileIdentityW(DWORD Unknown1, DWORD Unknown2, DWORD Unknown3) From a32c56c9bda9fa06115fca327b6b72cdc00069c8 Mon Sep 17 00:00:00 2001 From: Daniel Reimer Date: Tue, 16 Mar 2010 22:08:44 +0000 Subject: [PATCH 45/61] Update openoffice 2.4 Links to a new and working mirror svn path=/trunk/; revision=46230 --- reactos/base/applications/rapps/rapps/openoffice2.4.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/reactos/base/applications/rapps/rapps/openoffice2.4.txt b/reactos/base/applications/rapps/rapps/openoffice2.4.txt index 81cae28edf9..d68f92e3418 100644 --- a/reactos/base/applications/rapps/rapps/openoffice2.4.txt +++ b/reactos/base/applications/rapps/rapps/openoffice2.4.txt @@ -8,23 +8,23 @@ Description = THE Open Source Office Suite. Size = 127MB Category = 6 URLSite = http://www.openoffice.org/ -URLDownload = http://ftp.plusline.de/OpenOffice/stable/2.4.3/OOo_2.4.3_Win32Intel_install_en-US.exe +URLDownload = ftp://archive.services.openoffice.org/pub/openoffice-archive/stable/2.4.3/OOo_2.4.3_Win32Intel_install_en-US.exe CDPath = none [Section.0407] Description = DIE Open Source Office Suite. URLSite = http://de.openoffice.org/ Size = 114.2MB -URLDownload = http://ftp.tu-chemnitz.de/pub/openoffice/localized/de/2.4.3/OOo_2.4.3_Win32Intel_install_de.exe +URLDownload = ftp://archive.services.openoffice.org/pub/openoffice-archive/localized/de/2.4.3/OOo_2.4.3_Win32Intel_install_de.exe [Section.040a] Description = La suite de ofimática de código abierto. URLSite = http://es.openoffice.org/ Size = 113.9MB -URLDownload = http://ftp.tu-chemnitz.de/pub/openoffice/localized/es/2.4.3/OOo_2.4.3_Win32Intel_install_es.exe +URLDownload = ftp://archive.services.openoffice.org/pub/openoffice-archive/localized/es/2.4.3/OOo_2.4.3_Win32Intel_install_es.exe [Section.0415] URLSite = http://pl.openoffice.org/ Description = Otwarty pakiet biurowy. -URLDownload = http://ftp.tu-chemnitz.de/pub/openoffice/localized/pl/2.4.2/OOo_2.4.2_Win32Intel_install_pl.exe +URLDownload = ftp://archive.services.openoffice.org/pub/openoffice-archive/localized/pl/2.4.2/OOo_2.4.2_Win32Intel_install_pl.exe Size = 113.9M From 8e9189e36efe2baa914fc6c57550a4ea45be4dfc Mon Sep 17 00:00:00 2001 From: Christoph von Wittich Date: Tue, 16 Mar 2010 22:21:20 +0000 Subject: [PATCH 46/61] [USER32] reduce diff to wine svn path=/trunk/; revision=46231 --- reactos/dll/win32/user32/windows/menu.c | 2226 +++++++++++------------ 1 file changed, 1048 insertions(+), 1178 deletions(-) diff --git a/reactos/dll/win32/user32/windows/menu.c b/reactos/dll/win32/user32/windows/menu.c index 3f3916c6481..badf2d923c1 100644 --- a/reactos/dll/win32/user32/windows/menu.c +++ b/reactos/dll/win32/user32/windows/menu.c @@ -12,15 +12,25 @@ /* INCLUDES ******************************************************************/ #include - #include -WINE_DEFAULT_DEBUG_CHANNEL(user32); LRESULT DefWndNCPaint(HWND hWnd, HRGN hRgn, BOOL Active); +WINE_DEFAULT_DEBUG_CHANNEL(menu); + /* internal popup menu window messages */ -#define MM_SETMENUHANDLE (WM_USER + 0) -#define MM_GETMENUHANDLE (WM_USER + 1) + +#define MM_SETMENUHANDLE (WM_USER + 0) +#define MM_GETMENUHANDLE (WM_USER + 1) + +/* internal flags for menu tracking */ + +#define TF_ENDMENU 0x10000 +#define TF_SUSPENDPOPUP 0x20000 +#define TF_SKIPREMOVE 0x40000 + +#define ITEM_PREV -1 +#define ITEM_NEXT 1 /* Internal MenuTrackMenu() flags */ #define TPM_INTERNAL 0xF0000000 @@ -28,13 +38,14 @@ LRESULT DefWndNCPaint(HWND hWnd, HRGN hRgn, BOOL Active); #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */ #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */ -/* TYPES *********************************************************************/ #define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR) #define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK) + +/* macro to test that flags do not indicate bitmap, ownerdraw or separator */ #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags)) -#define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags)) +#define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1)) #define IS_SYSTEM_MENU(MenuInfo) \ (0 == ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU)) @@ -42,27 +53,25 @@ LRESULT DefWndNCPaint(HWND hWnd, HRGN hRgn, BOOL Active); #define IS_SYSTEM_POPUP(MenuInfo) \ (0 != ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU)) -#define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1)) +#define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags)) + +/* Use global popup window because there's no way 2 menus can + * be tracked at the same time. */ +static HWND TopPopup; + +/* Flag set by EndMenu() to force an exit from menu tracking */ +static BOOL fEndMenu = FALSE; #define MENU_ITEM_HBMP_SPACE (5) #define MENU_BAR_ITEMS_SPACE (12) #define SEPARATOR_HEIGHT (5) #define MENU_TAB_SPACE (8) -#define ITEM_PREV -1 -#define ITEM_NEXT 1 - #define MAKEINTATOMA(atom) ((LPCSTR)((ULONG_PTR)((WORD)(atom)))) #define MAKEINTATOMW(atom) ((LPCWSTR)((ULONG_PTR)((WORD)(atom)))) #define POPUPMENU_CLASS_ATOMA MAKEINTATOMA(32768) /* PopupMenu */ #define POPUPMENU_CLASS_ATOMW MAKEINTATOMW(32768) /* PopupMenu */ -/* internal flags for menu tracking */ - -#define TF_ENDMENU 0x0001 -#define TF_SUSPENDPOPUP 0x0002 -#define TF_SKIPREMOVE 0x0004 - typedef struct { UINT TrackFlags; @@ -72,8 +81,6 @@ typedef struct POINT Pt; } MTRACKER; -//static LRESULT WINAPI PopupMenuWndProcA(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam); -//static LRESULT WINAPI PopupMenuWndProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); /********************************************************************* * PopupMenu class descriptor @@ -89,14 +96,6 @@ const struct builtin_class_descr POPUPMENU_builtin_class = (HBRUSH)(COLOR_MENU + 1) /* brush */ }; - -/* INTERNAL FUNCTIONS ********************************************************/ - -/* Rip the fun and easy to use and fun WINE unicode string manipulation routines. - * Of course I didnt copy the ASM code because we want this to be portable - * and it needs to go away. - */ - #ifndef GET_WORD #define GET_WORD(ptr) (*(WORD *)(ptr)) #endif @@ -107,13 +106,6 @@ const struct builtin_class_descr POPUPMENU_builtin_class = HFONT hMenuFont = NULL; HFONT hMenuFontBold = NULL; -/* Flag set by EndMenu() to force an exit from menu tracking */ -static BOOL fEndMenu = FALSE; - -/* Use global popup window because there's no way 2 menus can - * be tracked at the same time. */ -static HWND TopPopup; - /* Dimension of the menu bitmaps */ static HBITMAP BmpSysMenu = NULL; @@ -293,71 +285,6 @@ MenuLoadBitmaps(VOID) } } -/*********************************************************************** - * MenuGetBitmapItemSize - * - * Get the size of a bitmap item. - */ -static void FASTCALL -MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem, SIZE *Size, HWND WndOwner) -{ - BITMAP Bm; - HBITMAP Bmp = lpitem->hbmpItem; - - Size->cx = Size->cy = 0; - - /* check if there is a magic menu item associated with this item */ - if (IS_MAGIC_BITMAP(Bmp)) - { - switch((INT_PTR) Bmp) - { - case (INT_PTR)HBMMENU_CALLBACK: - { - MEASUREITEMSTRUCT measItem; - measItem.CtlType = ODT_MENU; - measItem.CtlID = 0; - measItem.itemID = lpitem->wID; - measItem.itemWidth = lpitem->Rect.right - lpitem->Rect.left; - measItem.itemHeight = lpitem->Rect.bottom - lpitem->Rect.top; - measItem.itemData = lpitem->dwItemData; - SendMessageW( WndOwner, WM_MEASUREITEM, lpitem->wID, (LPARAM)&measItem); - Size->cx = measItem.itemWidth; - Size->cy = measItem.itemHeight; - return; - } - break; - - case (INT_PTR) HBMMENU_SYSTEM: - if (0 != lpitem->dwItemData) - { - Bmp = (HBITMAP) lpitem->dwItemData; - break; - } - /* fall through */ - case (INT_PTR) HBMMENU_MBAR_RESTORE: - case (INT_PTR) HBMMENU_MBAR_MINIMIZE: - case (INT_PTR) HBMMENU_MBAR_CLOSE: - case (INT_PTR) HBMMENU_MBAR_MINIMIZE_D: - case (INT_PTR) HBMMENU_MBAR_CLOSE_D: - case (INT_PTR) HBMMENU_POPUP_CLOSE: - case (INT_PTR) HBMMENU_POPUP_RESTORE: - case (INT_PTR) HBMMENU_POPUP_MAXIMIZE: - case (INT_PTR) HBMMENU_POPUP_MINIMIZE: - /* FIXME: Why we need to subtract these magic values? */ - /* to make them smaller than the menu bar? */ - Size->cx = GetSystemMetrics(SM_CXSIZE) - 2; - Size->cy = GetSystemMetrics(SM_CYSIZE) - 4; - return; - } - } - - if (GetObjectW(Bmp, sizeof(BITMAP), &Bm)) - { - Size->cx = Bm.bmWidth; - Size->cy = Bm.bmHeight; - } -} - /*********************************************************************** * MenuDrawPopupGlyph * @@ -422,96 +349,225 @@ MenuDrawPopupGlyph(HDC dc, LPRECT r, INT_PTR popupMagic, BOOL inactive, BOOL hil DeleteObject(hFont); } +/*********************************************************************** + * MenuFindItemByKey + * + * Find the menu item selected by a key press. + * Return item id, -1 if none, -2 if we should close the menu. + */ +static UINT FASTCALL MenuFindItemByKey(HWND WndOwner, PROSMENUINFO MenuInfo, + WCHAR Key, BOOL ForceMenuChar) +{ + ROSMENUINFO SysMenuInfo; + PROSMENUITEMINFO Items, ItemInfo; + LRESULT MenuChar; + UINT i; + + TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key, Key, MenuInfo); + + if (NULL == MenuInfo || ! IsMenu(MenuInfo->Self)) + { + if (MenuGetRosMenuInfo(&SysMenuInfo, GetSystemMenu(WndOwner, FALSE))) + { + MenuInfo = &SysMenuInfo; + } + else + { + MenuInfo = NULL; + } + } + + if (NULL != MenuInfo) + { + if (MenuGetAllRosMenuItemInfo(MenuInfo->Self, &Items) <= 0) + { + return -1; + } + if (! ForceMenuChar) + { + Key = toupperW(Key); + ItemInfo = Items; + for (i = 0; i < MenuInfo->MenuItemCount; i++, ItemInfo++) + { + if ((ItemInfo->Text) && NULL != ItemInfo->dwTypeData) + { + WCHAR *p = (WCHAR *) ItemInfo->dwTypeData - 2; + do + { + p = strchrW(p + 2, '&'); + } + while (NULL != p && L'&' == p[1]); + if (NULL != p && (toupperW(p[1]) == Key)) + { + return i; + } + } + } + } + + MenuChar = SendMessageW(WndOwner, WM_MENUCHAR, + MAKEWPARAM(Key, MenuInfo->Flags), (LPARAM) MenuInfo->Self); + if (2 == HIWORD(MenuChar)) + { + return LOWORD(MenuChar); + } + if (1 == HIWORD(MenuChar)) + { + return (UINT) (-2); + } + } + + return (UINT)(-1); +} + +/*********************************************************************** + * MenuGetBitmapItemSize + * + * Get the size of a bitmap item. + */ +static void FASTCALL MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem, SIZE *size, + HWND WndOwner) +{ + BITMAP bm; + HBITMAP bmp = lpitem->hbmpItem; + + size->cx = size->cy = 0; + + /* check if there is a magic menu item associated with this item */ + if (IS_MAGIC_BITMAP(bmp)) + { + switch((INT_PTR) bmp) + { + case (INT_PTR)HBMMENU_CALLBACK: + { + MEASUREITEMSTRUCT measItem; + measItem.CtlType = ODT_MENU; + measItem.CtlID = 0; + measItem.itemID = lpitem->wID; + measItem.itemWidth = lpitem->Rect.right - lpitem->Rect.left; + measItem.itemHeight = lpitem->Rect.bottom - lpitem->Rect.top; + measItem.itemData = lpitem->dwItemData; + SendMessageW( WndOwner, WM_MEASUREITEM, lpitem->wID, (LPARAM)&measItem); + size->cx = measItem.itemWidth; + size->cy = measItem.itemHeight; + return; + } + break; + + case (INT_PTR) HBMMENU_SYSTEM: + if (0 != lpitem->dwItemData) + { + bmp = (HBITMAP) lpitem->dwItemData; + break; + } + /* fall through */ + case (INT_PTR) HBMMENU_MBAR_RESTORE: + case (INT_PTR) HBMMENU_MBAR_MINIMIZE: + case (INT_PTR) HBMMENU_MBAR_CLOSE: + case (INT_PTR) HBMMENU_MBAR_MINIMIZE_D: + case (INT_PTR) HBMMENU_MBAR_CLOSE_D: + case (INT_PTR) HBMMENU_POPUP_CLOSE: + case (INT_PTR) HBMMENU_POPUP_RESTORE: + case (INT_PTR) HBMMENU_POPUP_MAXIMIZE: + case (INT_PTR) HBMMENU_POPUP_MINIMIZE: + /* FIXME: Why we need to subtract these magic values? */ + /* to make them smaller than the menu bar? */ + size->cx = GetSystemMetrics(SM_CXSIZE) - 2; + size->cy = GetSystemMetrics(SM_CYSIZE) - 4; + return; + } + } + + if (GetObjectW(bmp, sizeof(BITMAP), &bm)) + { + size->cx = bm.bmWidth; + size->cy = bm.bmHeight; + } +} + /*********************************************************************** * MenuDrawBitmapItem * * Draw a bitmap item. */ -static void FASTCALL -MenuDrawBitmapItem(HDC Dc, PROSMENUITEMINFO Item, const RECT *Rect, +static void FASTCALL MenuDrawBitmapItem(HDC hdc, PROSMENUITEMINFO lpitem, const RECT *rect, HMENU hmenu, HWND WndOwner, UINT odaction, BOOL MenuBar) { - BITMAP Bm; - DWORD Rop; - HDC DcMem; - HBITMAP Bmp; - int w = Rect->right - Rect->left; - int h = Rect->bottom - Rect->top; - int BmpXoffset = 0; - int Left, Top; - HBITMAP hbmpToDraw = (HBITMAP) Item->hbmpItem; - Bmp = hbmpToDraw; + BITMAP bm; + DWORD rop; + HDC hdcMem; + HBITMAP bmp; + int w = rect->right - rect->left; + int h = rect->bottom - rect->top; + int bmp_xoffset = 0; + int left, top; + HBITMAP hbmToDraw = lpitem->hbmpItem; + bmp = hbmToDraw; - /* Check if there is a magic menu item associated with this item */ - if (IS_MAGIC_BITMAP(hbmpToDraw)) + /* Check if there is a magic menu item associated with this item */ + if (IS_MAGIC_BITMAP(hbmToDraw)) { - UINT Flags = 0; - RECT r; + UINT flags = 0; + RECT r; - r = *Rect; - switch ((INT_PTR)hbmpToDraw) + r = *rect; + switch ((INT_PTR)hbmToDraw) { - case (INT_PTR) HBMMENU_SYSTEM: - if (NULL != Item->dwTypeData) - { - Bmp = (HBITMAP)Item->dwTypeData; - if (! GetObjectW(Bmp, sizeof(BITMAP), &Bm)) - { - return; - } - } + case (INT_PTR)HBMMENU_SYSTEM: + if (lpitem->dwTypeData) + { + bmp = (HBITMAP)lpitem->dwTypeData; + if (!GetObjectW( bmp, sizeof(bm), &bm )) return; + } else - { + { if (!BmpSysMenu) BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE)); - Bmp = BmpSysMenu; - if (! GetObjectW(Bmp, sizeof(BITMAP), &Bm)) - { - return; - } + bmp = BmpSysMenu; + if (! GetObjectW(bmp, sizeof(bm), &bm)) return; /* only use right half of the bitmap */ - BmpXoffset = Bm.bmWidth / 2; - Bm.bmWidth -= BmpXoffset; - } + bmp_xoffset = bm.bmWidth / 2; + bm.bmWidth -= bmp_xoffset; + } goto got_bitmap; - case (INT_PTR) HBMMENU_MBAR_RESTORE: - Flags = DFCS_CAPTIONRESTORE; + case (INT_PTR)HBMMENU_MBAR_RESTORE: + flags = DFCS_CAPTIONRESTORE; break; - case (INT_PTR) HBMMENU_MBAR_MINIMIZE: + case (INT_PTR)HBMMENU_MBAR_MINIMIZE: r.right += 1; - Flags = DFCS_CAPTIONMIN; + flags = DFCS_CAPTIONMIN; break; - case (INT_PTR) HBMMENU_MBAR_MINIMIZE_D: + case (INT_PTR)HBMMENU_MBAR_MINIMIZE_D: r.right += 1; - Flags = DFCS_CAPTIONMIN | DFCS_INACTIVE; + flags = DFCS_CAPTIONMIN | DFCS_INACTIVE; break; - case (INT_PTR) HBMMENU_MBAR_CLOSE: - Flags = DFCS_CAPTIONCLOSE; + case (INT_PTR)HBMMENU_MBAR_CLOSE: + flags = DFCS_CAPTIONCLOSE; break; - case (INT_PTR) HBMMENU_MBAR_CLOSE_D: - Flags = DFCS_CAPTIONCLOSE | DFCS_INACTIVE; + case (INT_PTR)HBMMENU_MBAR_CLOSE_D: + flags = DFCS_CAPTIONCLOSE | DFCS_INACTIVE; break; - case (INT_PTR) HBMMENU_CALLBACK: + case (INT_PTR)HBMMENU_CALLBACK: { DRAWITEMSTRUCT drawItem; POINT origorg; drawItem.CtlType = ODT_MENU; drawItem.CtlID = 0; - drawItem.itemID = Item->wID; + drawItem.itemID = lpitem->wID; drawItem.itemAction = odaction; - drawItem.itemState = (Item->fState & MF_CHECKED)?ODS_CHECKED:0; - drawItem.itemState |= (Item->fState & MF_DEFAULT)?ODS_DEFAULT:0; - drawItem.itemState |= (Item->fState & MF_DISABLED)?ODS_DISABLED:0; - drawItem.itemState |= (Item->fState & MF_GRAYED)?ODS_GRAYED|ODS_DISABLED:0; - drawItem.itemState |= (Item->fState & MF_HILITE)?ODS_SELECTED:0; + drawItem.itemState = (lpitem->fState & MF_CHECKED)?ODS_CHECKED:0; + drawItem.itemState |= (lpitem->fState & MF_DEFAULT)?ODS_DEFAULT:0; + drawItem.itemState |= (lpitem->fState & MF_DISABLED)?ODS_DISABLED:0; + drawItem.itemState |= (lpitem->fState & MF_GRAYED)?ODS_GRAYED|ODS_DISABLED:0; + drawItem.itemState |= (lpitem->fState & MF_HILITE)?ODS_SELECTED:0; drawItem.hwndItem = (HWND)hmenu; - drawItem.hDC = Dc; - drawItem.rcItem = *Rect; - drawItem.itemData = Item->dwItemData; + drawItem.hDC = hdc; + drawItem.rcItem = *rect; + drawItem.itemData = lpitem->dwItemData; /* some applications make this assumption on the DC's origin */ - SetViewportOrgEx( Dc, Item->Rect.left, Item->Rect.top, &origorg); - OffsetRect( &drawItem.rcItem, - Item->Rect.left, - Item->Rect.top); + SetViewportOrgEx( hdc, lpitem->Rect.left, lpitem->Rect.top, &origorg); + OffsetRect( &drawItem.rcItem, - lpitem->Rect.left, - lpitem->Rect.top); SendMessageW( WndOwner, WM_DRAWITEM, 0, (LPARAM)&drawItem); - SetViewportOrgEx( Dc, origorg.x, origorg.y, NULL); + SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL); return; } break; @@ -520,37 +576,413 @@ MenuDrawBitmapItem(HDC Dc, PROSMENUITEMINFO Item, const RECT *Rect, case (INT_PTR) HBMMENU_POPUP_RESTORE: case (INT_PTR) HBMMENU_POPUP_MAXIMIZE: case (INT_PTR) HBMMENU_POPUP_MINIMIZE: - MenuDrawPopupGlyph(Dc, &r, (INT_PTR)hbmpToDraw, Item->fState & MF_GRAYED, Item->fState & MF_HILITE); + MenuDrawPopupGlyph(hdc, &r, (INT_PTR)hbmToDraw, lpitem->fState & MF_GRAYED, lpitem->fState & MF_HILITE); return; } InflateRect(&r, -1, -1); - if (0 != (Item->fState & MF_HILITE)) - { - Flags |= DFCS_PUSHED; + if (0 != (lpitem->fState & MF_HILITE)) + { + flags |= DFCS_PUSHED; + } + DrawFrameControl(hdc, &r, DFC_CAPTION, flags); + return; + } + + if (!bmp || !GetObjectW( bmp, sizeof(bm), &bm )) return; + + got_bitmap: + hdcMem = CreateCompatibleDC( hdc ); + SelectObject( hdcMem, bmp ); + + /* handle fontsize > bitmap_height */ + top = (h>bm.bmHeight) ? rect->top+(h-bm.bmHeight)/2 : rect->top; + left=rect->left; + rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_BITMAP(hbmToDraw)) ? NOTSRCCOPY : SRCCOPY; + if ((lpitem->fState & MF_HILITE) && lpitem->hbmpItem) + SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT)); + BitBlt( hdc, left, top, w, h, hdcMem, bmp_xoffset, 0, rop ); + DeleteDC( hdcMem ); +} + +/*********************************************************************** + * MenuCalcItemSize + * + * Calculate the size of the menu item and store it in lpitem->rect. + */ +static void FASTCALL MenuCalcItemSize( HDC hdc, PROSMENUITEMINFO lpitem, PROSMENUINFO MenuInfo, HWND hwndOwner, + INT orgX, INT orgY, BOOL menuBar) +{ + WCHAR *p; + UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK ); + INT itemheight = 0; + + TRACE("dc=%x owner=%x (%d,%d)\n", hdc, hwndOwner, orgX, orgY); + + MenuCharSize.cx = GdiGetCharDimensions( hdc, NULL, &MenuCharSize.cy ); + + SetRect( &lpitem->Rect, orgX, orgY, orgX, orgY ); + + if (lpitem->fType & MF_OWNERDRAW) + { + MEASUREITEMSTRUCT mis; + mis.CtlType = ODT_MENU; + mis.CtlID = 0; + mis.itemID = lpitem->wID; + mis.itemData = lpitem->dwItemData; + mis.itemHeight = HIWORD( GetDialogBaseUnits()); + mis.itemWidth = 0; + SendMessageW( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis ); + /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average + * width of a menufont character to the width of an owner-drawn menu. + */ + lpitem->Rect.right += mis.itemWidth + 2 * MenuCharSize.cx; + + if (menuBar) { + /* under at least win95 you seem to be given a standard + height for the menu and the height value is ignored */ + lpitem->Rect.bottom += GetSystemMetrics(SM_CYMENUSIZE); + } else + lpitem->Rect.bottom += mis.itemHeight; + + TRACE("id=%04lx size=%dx%d\n", + lpitem->wID, mis.itemWidth, mis.itemHeight); + return; + } + + if (lpitem->fType & MF_SEPARATOR) + { + lpitem->Rect.bottom += SEPARATOR_HEIGHT; + if( !menuBar) + lpitem->Rect.right += check_bitmap_width + MenuCharSize.cx; + return; + } + + lpitem->XTab = 0; + + if (lpitem->hbmpItem) + { + SIZE size; + + if (!menuBar) { + MenuGetBitmapItemSize(lpitem, &size, hwndOwner ); + /* Keep the size of the bitmap in callback mode to be able + * to draw it correctly */ + lpitem->Rect.right = lpitem->Rect.left + size.cx; + if (MenuInfo->maxBmpSize.cx < abs(size.cx) + MENU_ITEM_HBMP_SPACE || + MenuInfo->maxBmpSize.cy < abs(size.cy)) + { + MenuInfo->maxBmpSize.cx = abs(size.cx) + MENU_ITEM_HBMP_SPACE; + MenuInfo->maxBmpSize.cy = abs(size.cy); + } + MenuSetRosMenuInfo(MenuInfo); + itemheight = size.cy + 2; + + if( !(MenuInfo->dwStyle & MNS_NOCHECK)) + lpitem->Rect.right += 2 * check_bitmap_width; + lpitem->Rect.right += 4 + MenuCharSize.cx; + lpitem->XTab = lpitem->Rect.right; + lpitem->Rect.right += check_bitmap_width; + } else /* hbmpItem & MenuBar */ { + MenuGetBitmapItemSize(lpitem, &size, hwndOwner ); + lpitem->Rect.right += size.cx; + if( lpitem->Text) lpitem->Rect.right += 2; + itemheight = size.cy; + + /* Special case: Minimize button doesn't have a space behind it. */ + if (lpitem->hbmpItem == (HBITMAP)HBMMENU_MBAR_MINIMIZE || + lpitem->hbmpItem == (HBITMAP)HBMMENU_MBAR_MINIMIZE_D) + lpitem->Rect.right -= 1; } - DrawFrameControl(Dc, &r, DFC_CAPTION, Flags); - return; + } + else if (!menuBar) { + if( !(MenuInfo->dwStyle & MNS_NOCHECK)) + lpitem->Rect.right += check_bitmap_width; + lpitem->Rect.right += 4 + MenuCharSize.cx; + lpitem->XTab = lpitem->Rect.right; + lpitem->Rect.right += check_bitmap_width; } - if (NULL == Bmp || ! GetObjectW(Bmp, sizeof(BITMAP), &Bm)) + /* it must be a text item - unless it's the system menu */ + if (!(lpitem->fType & MF_SYSMENU) && lpitem->Text) { + HFONT hfontOld = NULL; + RECT rc = lpitem->Rect; + LONG txtheight, txtwidth; + + if ( lpitem->fState & MFS_DEFAULT ) { + hfontOld = SelectObject( hdc, hMenuFontBold ); + } + if (menuBar) { + txtheight = DrawTextW( hdc, lpitem->dwTypeData, -1, &rc, + DT_SINGLELINE|DT_CALCRECT); + lpitem->Rect.right += rc.right - rc.left; + itemheight = max( max( itemheight, txtheight), + GetSystemMetrics( SM_CYMENU) - 1); + lpitem->Rect.right += 2 * MenuCharSize.cx; + } else { + if ((p = strchrW( lpitem->dwTypeData, '\t' )) != NULL) { + RECT tmprc = rc; + LONG tmpheight; + int n = (int)( p - lpitem->dwTypeData); + /* Item contains a tab (only meaningful in popup menus) */ + /* get text size before the tab */ + txtheight = DrawTextW( hdc, lpitem->dwTypeData, n, &rc, + DT_SINGLELINE|DT_CALCRECT); + txtwidth = rc.right - rc.left; + p += 1; /* advance past the Tab */ + /* get text size after the tab */ + tmpheight = DrawTextW( hdc, p, -1, &tmprc, + DT_SINGLELINE|DT_CALCRECT); + lpitem->XTab += txtwidth; + txtheight = max( txtheight, tmpheight); + txtwidth += MenuCharSize.cx + /* space for the tab */ + tmprc.right - tmprc.left; /* space for the short cut */ + } else { + txtheight = DrawTextW( hdc, lpitem->dwTypeData, -1, &rc, + DT_SINGLELINE|DT_CALCRECT); + txtwidth = rc.right - rc.left; + lpitem->XTab += txtwidth; + } + lpitem->Rect.right += 2 + txtwidth; + itemheight = max( itemheight, + max( txtheight + 2, MenuCharSize.cy + 4)); + } + if (hfontOld) SelectObject (hdc, hfontOld); + } else if( menuBar) { + itemheight = max( itemheight, GetSystemMetrics(SM_CYMENU)-1); + } + lpitem->Rect.bottom += itemheight; + TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem->Rect.left, lpitem->Rect.top, lpitem->Rect.right, lpitem->Rect.bottom); +} + +/*********************************************************************** + * MenuPopupMenuCalcSize + * + * Calculate the size of a popup menu. + */ +static void FASTCALL MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo, HWND WndOwner) +{ + ROSMENUITEMINFO lpitem; + HDC hdc; + int start, i; + int orgX, orgY, maxX, maxTab, maxTabWidth; + + MenuInfo->Width = MenuInfo->Height = 0; + if (MenuInfo->MenuItemCount == 0) { - return; + MenuSetRosMenuInfo(MenuInfo); + return; } -got_bitmap: - DcMem = CreateCompatibleDC(Dc); - SelectObject(DcMem, Bmp); + hdc = GetDC(NULL); + SelectObject( hdc, hMenuFont ); - /* handle fontsize > bitmap_height */ - Top = (Bm.bmHeight < h) ? Rect->top + (h - Bm.bmHeight) / 2 : Rect->top; - Left = Rect->left; - Rop= ((Item->fState & MF_HILITE) && !IS_MAGIC_BITMAP(hbmpToDraw)) ? NOTSRCCOPY : SRCCOPY; - if ((Item->fState & MF_HILITE) && Item->hbmpItem) + start = 0; + maxX = 2 + 1; + + MenuInfo->maxBmpSize.cx = 0; + MenuInfo->maxBmpSize.cy = 0; + + MenuInitRosMenuItemInfo(&lpitem); + while (start < MenuInfo->MenuItemCount) { - SetBkColor(Dc, GetSysColor(COLOR_HIGHLIGHT)); + orgX = maxX; + orgY = 2; + + maxTab = maxTabWidth = 0; + + /* Parse items until column break or end of menu */ + for (i = start; i < MenuInfo->MenuItemCount; i++) + { + if (! MenuGetRosMenuItemInfo(MenuInfo->Self, i, &lpitem)) + { + MenuCleanupRosMenuItemInfo(&lpitem); + MenuSetRosMenuInfo(MenuInfo); + return; + } + if (i != start && + (lpitem.fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break; + + MenuCalcItemSize(hdc, &lpitem, MenuInfo, WndOwner, orgX, orgY, FALSE); + if (! MenuSetRosMenuItemInfo(MenuInfo->Self, i, &lpitem)) + { + MenuCleanupRosMenuItemInfo(&lpitem); + MenuSetRosMenuInfo(MenuInfo); + return; + } +// Not sure here,, The patch from wine removes this. +// if ((lpitem.fType & MF_MENUBARBREAK) != 0) +// { +// OrgX++; +// } + maxX = max(maxX, lpitem.Rect.right); + orgY = lpitem.Rect.bottom; + if ((lpitem.Text) && lpitem.XTab ) + { + maxTab = max( maxTab, lpitem.XTab ); + maxTabWidth = max(maxTabWidth, lpitem.Rect.right - lpitem.XTab); + } + } + + /* Finish the column (set all items to the largest width found) */ + maxX = max( maxX, maxTab + maxTabWidth ); + while (start < i) + { + if (MenuGetRosMenuItemInfo(MenuInfo->Self, start, &lpitem)) + { + lpitem.Rect.right = maxX; + if ((lpitem.Text) && 0 != lpitem.XTab) + { + lpitem.XTab = maxTab; + } + MenuSetRosMenuItemInfo(MenuInfo->Self, start, &lpitem); + } + start++; + } + MenuInfo->Height = max(MenuInfo->Height, orgY); } - BitBlt(Dc, Left, Top, w, h, DcMem, BmpXoffset, 0, Rop); - DeleteDC(DcMem); + + MenuInfo->Width = maxX; + + /* space for 3d border */ + MenuInfo->Height += 2; + MenuInfo->Width += 2; + + MenuCleanupRosMenuItemInfo(&lpitem); + MenuSetRosMenuInfo(MenuInfo); + ReleaseDC( 0, hdc ); +} + +/*********************************************************************** + * MenuMenuBarCalcSize + * + * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap + * height is off by 1 pixel which causes lengthy window relocations when + * active document window is maximized/restored. + * + * Calculate the size of the menu bar. + */ +static void FASTCALL MenuMenuBarCalcSize( HDC hdc, LPRECT lprect, + PROSMENUINFO MenuInfo, HWND hwndOwner ) +{ + ROSMENUITEMINFO ItemInfo; + int start, i, orgX, orgY, maxY, helpPos; + + if ((lprect == NULL) || (MenuInfo == NULL)) return; + if (MenuInfo->MenuItemCount == 0) return; + TRACE("left=%ld top=%ld right=%ld bottom=%ld\n", lprect->left, lprect->top, lprect->right, lprect->bottom); + MenuInfo->Width = lprect->right - lprect->left; + MenuInfo->Height = 0; + maxY = lprect->top + 1; + start = 0; + helpPos = -1; + + MenuInfo->maxBmpSize.cx = 0; + MenuInfo->maxBmpSize.cy = 0; + + MenuInitRosMenuItemInfo(&ItemInfo); + while (start < MenuInfo->MenuItemCount) + { + if (! MenuGetRosMenuItemInfo(MenuInfo->Self, start, &ItemInfo)) + { + MenuCleanupRosMenuItemInfo(&ItemInfo); + return; + } + orgX = lprect->left; + orgY = maxY; + + /* Parse items until line break or end of menu */ + for (i = start; i < MenuInfo->MenuItemCount; i++) + { + if ((helpPos == -1) && (ItemInfo.fType & MF_RIGHTJUSTIFY)) helpPos = i; + if ((i != start) && + (ItemInfo.fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break; + + TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX, orgY); + MenuCalcItemSize(hdc, &ItemInfo, MenuInfo, hwndOwner, orgX, orgY, TRUE); + if (! MenuSetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo)) + { + MenuCleanupRosMenuItemInfo(&ItemInfo); + return; + } + + if (ItemInfo.Rect.right > lprect->right) + { + if (i != start) break; + else ItemInfo.Rect.right = lprect->right; + } + maxY = max( maxY, ItemInfo.Rect.bottom ); + orgX = ItemInfo.Rect.right; + if (i + 1 < MenuInfo->MenuItemCount) + { + if (! MenuGetRosMenuItemInfo(MenuInfo->Self, i + 1, &ItemInfo)) + { + MenuCleanupRosMenuItemInfo(&ItemInfo); + return; + } + } + } + +/* FIXME: Is this really needed? */ /*NO! it is not needed, why make the +HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */ +#if 0 + /* Finish the line (set all items to the largest height found) */ + while (start < i) + { + if (MenuGetRosMenuItemInfo(MenuInfo->Self, start, &ItemInfo)) + { + ItemInfo.Rect.bottom = maxY; + MenuSetRosMenuItemInfo(MenuInfo->Self, start, &ItemInfo); + } + start++; + } +#else + start = i; /* This works! */ +#endif + } + + lprect->bottom = maxY; + MenuInfo->Height = lprect->bottom - lprect->top; + MenuSetRosMenuInfo(MenuInfo); + + if (helpPos != -1) + { + /* Flush right all items between the MF_RIGHTJUSTIFY and */ + /* the last item (if several lines, only move the last line) */ + if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->MenuItemCount - 1, &ItemInfo)) + { + MenuCleanupRosMenuItemInfo(&ItemInfo); + return; + } + orgY = ItemInfo.Rect.top; + orgX = lprect->right; + for (i = MenuInfo->MenuItemCount - 1; helpPos <= i; i--) + { + if (i < helpPos) + { + break; /* done */ + } + if (ItemInfo.Rect.top != orgY) + { + break; /* Other line */ + } + if (orgX <= ItemInfo.Rect.right) + { + break; /* Too far right already */ + } + ItemInfo.Rect.left += orgX - ItemInfo.Rect.right; + ItemInfo.Rect.right = orgX; + orgX = ItemInfo.Rect.left; + MenuSetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo); + if (helpPos + 1 <= i && + ! MenuGetRosMenuItemInfo(MenuInfo->Self, i - 1, &ItemInfo)) + { + MenuCleanupRosMenuItemInfo(&ItemInfo); + return; + } + } + } + + MenuCleanupRosMenuItemInfo(&ItemInfo); } /*********************************************************************** @@ -558,358 +990,322 @@ got_bitmap: * * Draw a single menu item. */ -static void FASTCALL -MenuDrawMenuItem(HWND hWnd, PROSMENUINFO MenuInfo, HWND WndOwner, HDC Dc, - PROSMENUITEMINFO Item, UINT Height, BOOL MenuBar, UINT Action) +static void FASTCALL MenuDrawMenuItem(HWND hWnd, PROSMENUINFO MenuInfo, HWND WndOwner, HDC hdc, + PROSMENUITEMINFO lpitem, UINT Height, BOOL menuBar, UINT odaction) { - RECT Rect; - PWCHAR Text; - BOOL flat_menu = FALSE; - int bkgnd; - PWND Wnd = ValidateHwnd(hWnd); + RECT rect; + PWCHAR Text; + BOOL flat_menu = FALSE; + int bkgnd; + PWND Wnd = ValidateHwnd(hWnd); - if (!Wnd) + if (!Wnd) return; - if (0 != (Item->fType & MF_SYSMENU)) + if (lpitem->fType & MF_SYSMENU) { - if ( (Wnd->style & WS_MINIMIZE)) + if ( (Wnd->style & WS_MINIMIZE)) { - UserGetInsideRectNC(Wnd, &Rect); - UserDrawSysMenuButton(hWnd, Dc, &Rect, - Item->fState & (MF_HILITE | MF_MOUSESELECT)); - } - return; + UserGetInsideRectNC(Wnd, &rect); + UserDrawSysMenuButton(hWnd, hdc, &rect, + lpitem->fState & (MF_HILITE | MF_MOUSESELECT)); + } + return; } SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0); - bkgnd = (MenuBar && flat_menu) ? COLOR_MENUBAR : COLOR_MENU; + bkgnd = (menuBar && flat_menu) ? COLOR_MENUBAR : COLOR_MENU; + + /* Setup colors */ - /* Setup colors */ - - if (0 != (Item->fState & MF_HILITE)) + if (lpitem->fState & MF_HILITE) { - if (MenuBar && !flat_menu) - { - SetTextColor(Dc, GetSysColor(COLOR_MENUTEXT)); - SetBkColor(Dc, GetSysColor(COLOR_MENU)); + if(menuBar && !flat_menu) { + SetTextColor(hdc, GetSysColor(COLOR_MENUTEXT)); + SetBkColor(hdc, GetSysColor(COLOR_MENU)); + } else { + if (lpitem->fState & MF_GRAYED) + SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); + else + SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); + SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT)); } - else - { - if (0 != (Item->fState & MF_GRAYED)) - { - SetTextColor(Dc, GetSysColor(COLOR_GRAYTEXT)); - } - else - { - SetTextColor(Dc, GetSysColor(COLOR_HIGHLIGHTTEXT)); - } - SetBkColor(Dc, GetSysColor(COLOR_HIGHLIGHT)); - } - } - else - { - if (0 != (Item->fState & MF_GRAYED)) - { - SetTextColor(Dc, GetSysColor(COLOR_GRAYTEXT)); - } - else - { - SetTextColor(Dc, GetSysColor(COLOR_MENUTEXT)); - } - SetBkColor(Dc, GetSysColor(bkgnd)); - } - - Rect = Item->Rect; - - if (Item->fType & MF_OWNERDRAW) - { - /* - ** Experimentation under Windows reveals that an owner-drawn - ** menu is given the rectangle which includes the space it requested - ** in its response to WM_MEASUREITEM _plus_ width for a checkmark - ** and a popup-menu arrow. This is the value of lpitem->rect. - ** Windows will leave all drawing to the application except for - ** the popup-menu arrow. Windows always draws that itself, after - ** the menu owner has finished drawing. - */ - DRAWITEMSTRUCT dis; - - dis.CtlType = ODT_MENU; - dis.CtlID = 0; - dis.itemID = Item->wID; - dis.itemData = (DWORD)Item->dwItemData; - dis.itemState = 0; - if (0 != (Item->fState & MF_CHECKED)) - { - dis.itemState |= ODS_CHECKED; - } - if (0 != (Item->fState & MF_GRAYED)) - { - dis.itemState |= ODS_GRAYED | ODS_DISABLED; - } - if (0 != (Item->fState & MF_HILITE)) - { - dis.itemState |= ODS_SELECTED; - } - dis.itemAction = Action; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */ - dis.hwndItem = (HWND) MenuInfo->Self; - dis.hDC = Dc; - dis.rcItem = Rect; - TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, " - "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd, - dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem, - dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right, - dis.rcItem.bottom); - SendMessageW(WndOwner, WM_DRAWITEM, 0, (LPARAM) &dis); - /* Draw the popup-menu arrow */ - if (0 != (Item->fType & MF_POPUP)) - { - RECT rectTemp; - CopyRect(&rectTemp, &Rect); - rectTemp.left = rectTemp.right - GetSystemMetrics(SM_CXMENUCHECK); - DrawFrameControl(Dc, &rectTemp, DFC_MENU, DFCS_MENUARROW); - } - return; - } - - TRACE("rect={%ld,%ld,%ld,%ld}\n", Item->Rect.left, Item->Rect.top, - Item->Rect.right, Item->Rect.bottom); - - if (MenuBar && 0 != (Item->fType & MF_SEPARATOR)) - { - return; - } - - if (Item->fState & MF_HILITE) - { - if (flat_menu) - { - InflateRect (&Rect, -1, -1); - FillRect(Dc, &Rect, GetSysColorBrush(COLOR_MENUHILIGHT)); - InflateRect (&Rect, 1, 1); - FrameRect(Dc, &Rect, GetSysColorBrush(COLOR_HIGHLIGHT)); } else { - if (MenuBar) - { - DrawEdge(Dc, &Rect, BDR_SUNKENOUTER, BF_RECT); - } - else - { - FillRect(Dc, &Rect, GetSysColorBrush(COLOR_HIGHLIGHT)); - } + if (lpitem->fState & MF_GRAYED) + SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) ); + else + SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) ); + SetBkColor( hdc, GetSysColor( bkgnd ) ); } - } - else - { - FillRect(Dc, &Rect, GetSysColorBrush(bkgnd)); - } - SetBkMode(Dc, TRANSPARENT); + rect = lpitem->Rect; - /* vertical separator */ - if (! MenuBar && 0 != (Item->fType & MF_MENUBARBREAK)) - { - HPEN oldPen; - RECT rc = Rect; - rc.left -= 3; - rc.top = 3; - rc.bottom = Height - 3; - if (flat_menu) + if (lpitem->fType & MF_OWNERDRAW) { - oldPen = SelectObject( Dc, GetStockObject(DC_PEN) ); - SetDCPenColor(Dc, GetSysColor(COLOR_BTNSHADOW)); - MoveToEx( Dc, rc.left, rc.top, NULL ); - LineTo( Dc, rc.left, rc.bottom ); - SelectObject( Dc, oldPen ); + /* + ** Experimentation under Windows reveals that an owner-drawn + ** menu is given the rectangle which includes the space it requested + ** in its response to WM_MEASUREITEM _plus_ width for a checkmark + ** and a popup-menu arrow. This is the value of lpitem->rect. + ** Windows will leave all drawing to the application except for + ** the popup-menu arrow. Windows always draws that itself, after + ** the menu owner has finished drawing. + */ + DRAWITEMSTRUCT dis; + + dis.CtlType = ODT_MENU; + dis.CtlID = 0; + dis.itemID = lpitem->wID; + dis.itemData = (DWORD)lpitem->dwItemData; + dis.itemState = 0; + if (lpitem->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED; + if (lpitem->fState & MF_GRAYED) dis.itemState |= ODS_GRAYED | ODS_DISABLED; + if (lpitem->fState & MF_HILITE) dis.itemState |= ODS_SELECTED; + dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */ + dis.hwndItem = (HWND) MenuInfo->Self; + dis.hDC = hdc; + dis.rcItem = rect; + TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, " + "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd, + dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem, + dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right, + dis.rcItem.bottom); + SendMessageW(WndOwner, WM_DRAWITEM, 0, (LPARAM) &dis); + /* Draw the popup-menu arrow */ + if (lpitem->fType & MF_POPUP) + { + RECT rectTemp; + CopyRect(&rectTemp, &rect); + rectTemp.left = rectTemp.right - GetSystemMetrics(SM_CXMENUCHECK); + DrawFrameControl(hdc, &rectTemp, DFC_MENU, DFCS_MENUARROW); + } + return; + } + + if (menuBar && (lpitem->fType & MF_SEPARATOR)) return; + + if (lpitem->fState & MF_HILITE) + { + if (flat_menu) + { + InflateRect (&rect, -1, -1); + FillRect(hdc, &rect, GetSysColorBrush(COLOR_MENUHILIGHT)); + InflateRect (&rect, 1, 1); + FrameRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT)); + } + else + { + if(menuBar) + DrawEdge(hdc, &rect, BDR_SUNKENOUTER, BF_RECT); + else + FillRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT)); + } } else - DrawEdge(Dc, &rc, EDGE_ETCHED, BF_LEFT); - } + FillRect( hdc, &rect, GetSysColorBrush(bkgnd) ); - /* horizontal separator */ - if (0 != (Item->fType & MF_SEPARATOR)) - { - HPEN oldPen; - RECT rc = Rect; - rc.left++; - rc.right--; - rc.top += SEPARATOR_HEIGHT / 2; - if (flat_menu) + SetBkMode( hdc, TRANSPARENT ); + + /* vertical separator */ + if (!menuBar && (lpitem->fType & MF_MENUBARBREAK)) { - oldPen = SelectObject( Dc, GetStockObject(DC_PEN) ); - SetDCPenColor(Dc, GetSysColor(COLOR_BTNSHADOW)); - MoveToEx( Dc, rc.left, rc.top, NULL ); - LineTo( Dc, rc.right, rc.top ); - SelectObject( Dc, oldPen ); + HPEN oldPen; + RECT rc = rect; + + rc.left -= 3; + rc.top = 3; + rc.bottom = Height - 3; + if (flat_menu) + { + oldPen = SelectObject( hdc, GetStockObject(DC_PEN) ); + SetDCPenColor(hdc, GetSysColor(COLOR_BTNSHADOW)); + MoveToEx( hdc, rc.left, rc.top, NULL ); + LineTo( hdc, rc.left, rc.bottom ); + SelectObject( hdc, oldPen ); + } + else + DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT); + } + + /* horizontal separator */ + if (lpitem->fType & MF_SEPARATOR) + { + HPEN oldPen; + RECT rc = rect; + + rc.left++; + rc.right--; + rc.top += SEPARATOR_HEIGHT / 2; + if (flat_menu) + { + oldPen = SelectObject( hdc, GetStockObject(DC_PEN) ); + SetDCPenColor( hdc, GetSysColor(COLOR_BTNSHADOW)); + MoveToEx( hdc, rc.left, rc.top, NULL ); + LineTo( hdc, rc.right, rc.top ); + SelectObject( hdc, oldPen ); + } + else + DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP); + return; } - else - DrawEdge(Dc, &rc, EDGE_ETCHED, BF_TOP); - return; - } #if 0 - /* helper lines for debugging */ - /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */ - FrameRect(Dc, &Rect, GetStockObject(BLACK_BRUSH)); - SelectObject(Dc, GetStockObject(DC_PEN)); - SetDCPenColor(Dc, GetSysColor(COLOR_WINDOWFRAME)); - MoveToEx(Dc, Rect.left, (Rect.top + Rect.bottom) / 2, NULL); - LineTo(Dc, Rect.right, (Rect.top + Rect.bottom) / 2); + /* helper lines for debugging */ + /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */ + FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH)); + SelectObject(hdc, GetStockObject(DC_PEN)); + SetDCPenColor(hdc, GetSysColor(COLOR_WINDOWFRAME)); + MoveToEx(hdc, rect.left, (rect.top + rect.bottom) / 2, NULL); + LineTo(hdc, rect.right, (rect.top + rect.bottom) / 2); #endif - if (! MenuBar) - { - INT y = Rect.top + Rect.bottom; - RECT Rc = Rect; - UINT CheckBitmapWidth = GetSystemMetrics(SM_CXMENUCHECK); - UINT CheckBitmapHeight = GetSystemMetrics(SM_CYMENUCHECK); - int checked = FALSE; - /* Draw the check mark - * - * FIXME: - * Custom checkmark bitmaps are monochrome but not always 1bpp. - */ - if( !(MenuInfo->dwStyle & MNS_NOCHECK)) - { - HBITMAP bm = 0 != (Item->fState & MF_CHECKED) ? Item->hbmpChecked : Item->hbmpUnchecked; - if (NULL != bm) /* we have a custom bitmap */ - { - HDC DcMem = CreateCompatibleDC(Dc); - SelectObject(DcMem, bm); - BitBlt(Dc, Rc.left, (y - CheckBitmapHeight) / 2, - CheckBitmapWidth, CheckBitmapHeight, - DcMem, 0, 0, SRCCOPY); - DeleteDC(DcMem); - checked = TRUE; - } - else if (0 != (Item->fState & MF_CHECKED)) /* standard bitmaps */ - { - RECT rectTemp; - CopyRect(&rectTemp, &Rect); - rectTemp.right = rectTemp.left + GetSystemMetrics(SM_CXMENUCHECK); - DrawFrameControl(Dc, &rectTemp, DFC_MENU, - 0 != (Item->fType & MFT_RADIOCHECK) ? + if (!menuBar) + { + HBITMAP bm; + INT y = rect.top + rect.bottom; + RECT rc = rect; + int checked = FALSE; + UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK ); + UINT check_bitmap_height = GetSystemMetrics( SM_CYMENUCHECK ); + /* Draw the check mark + * + * FIXME: + * Custom checkmark bitmaps are monochrome but not always 1bpp. + */ + if( !(MenuInfo->dwStyle & MNS_NOCHECK)) { + bm = (lpitem->fState & MF_CHECKED) ? lpitem->hbmpChecked : + lpitem->hbmpUnchecked; + if (bm) /* we have a custom bitmap */ + { + HDC hdcMem = CreateCompatibleDC( hdc ); + + SelectObject( hdcMem, bm ); + BitBlt( hdc, rc.left, (y - check_bitmap_height) / 2, + check_bitmap_width, check_bitmap_height, + hdcMem, 0, 0, SRCCOPY ); + DeleteDC( hdcMem ); + checked = TRUE; + } + else if (lpitem->fState & MF_CHECKED) /* standard bitmaps */ + { + RECT r; + CopyRect(&r, &rect); + r.right = r.left + GetSystemMetrics(SM_CXMENUCHECK); + DrawFrameControl( hdc, &r, DFC_MENU, + (lpitem->fType & MFT_RADIOCHECK) ? DFCS_MENUBULLET : DFCS_MENUCHECK); - checked = TRUE; - } - } - if (Item->hbmpItem) - { - RECT bmpRect; - CopyRect(&bmpRect, &Rect); - if (!(MenuInfo->dwStyle & MNS_CHECKORBMP) && !(MenuInfo->dwStyle & MNS_NOCHECK)) - bmpRect.left += CheckBitmapWidth + 2; - if (!(checked && (MenuInfo->dwStyle & MNS_CHECKORBMP))) - { - bmpRect.right = bmpRect.left + MenuInfo->maxBmpSize.cx; - MenuDrawBitmapItem(Dc, Item, &bmpRect, MenuInfo->Self, WndOwner, Action, MenuBar); - } - } - /* Draw the popup-menu arrow */ - if (0 != (Item->fType & MF_POPUP)) - { - RECT rectTemp; - CopyRect(&rectTemp, &Rect); - rectTemp.left = rectTemp.right - GetSystemMetrics(SM_CXMENUCHECK); - DrawFrameControl(Dc, &rectTemp, DFC_MENU, DFCS_MENUARROW); - } - Rect.left += 4; - if( !(MenuInfo->dwStyle & MNS_NOCHECK)) - Rect.left += CheckBitmapWidth; - Rect.right -= CheckBitmapWidth; - } - else if (Item->hbmpItem) /* Draw the bitmap */ - { - MenuDrawBitmapItem(Dc, Item, &Rect, MenuInfo->Self, WndOwner, Action, MenuBar); - } - - /* No bitmap - process text if present */ - if (Item->Text) - { - register int i = 0; - HFONT FontOld = NULL; - - UINT uFormat = MenuBar ? DT_CENTER | DT_VCENTER | DT_SINGLELINE - : DT_LEFT | DT_VCENTER | DT_SINGLELINE; - - if(MenuInfo->dwStyle & MNS_CHECKORBMP) - Rect.left += max(0, MenuInfo->maxBmpSize.cx - GetSystemMetrics(SM_CXMENUCHECK)); - else - Rect.left += MenuInfo->maxBmpSize.cx; - - if (0 != (Item->fState & MFS_DEFAULT)) - { - FontOld = SelectObject(Dc, hMenuFontBold); - } - - if (MenuBar) - { - Rect.left += MENU_BAR_ITEMS_SPACE / 2; - Rect.right -= MENU_BAR_ITEMS_SPACE / 2; - } - - Text = (PWCHAR) Item->dwTypeData; - if(Text) - { - for (i = 0; L'\0' != Text[i]; i++) - { - if (L'\t' == Text[i] || L'\b' == Text[i]) - { - break; + checked = TRUE; } } - } + if ( lpitem->hbmpItem ) + { + RECT bmpRect; + CopyRect(&bmpRect, &rect); + if (!(MenuInfo->dwStyle & MNS_CHECKORBMP) && !(MenuInfo->dwStyle & MNS_NOCHECK)) + bmpRect.left += check_bitmap_width + 2; + if (!(checked && (MenuInfo->dwStyle & MNS_CHECKORBMP))) + { + bmpRect.right = bmpRect.left + MenuInfo->maxBmpSize.cx; + MenuDrawBitmapItem(hdc, lpitem, &bmpRect, MenuInfo->Self, WndOwner, odaction, menuBar); + } + } + /* Draw the popup-menu arrow */ + if (lpitem->fType & MF_POPUP) + { + RECT rectTemp; + CopyRect(&rectTemp, &rect); + rectTemp.left = rectTemp.right - GetSystemMetrics(SM_CXMENUCHECK); + DrawFrameControl(hdc, &rectTemp, DFC_MENU, DFCS_MENUARROW); + } + rect.left += 4; + if( !(MenuInfo->dwStyle & MNS_NOCHECK)) + rect.left += check_bitmap_width; + rect.right -= check_bitmap_width; + } + else if( lpitem->hbmpItem) + { /* Draw the bitmap */ + MenuDrawBitmapItem(hdc, lpitem, &rect, MenuInfo->Self, WndOwner, odaction, menuBar); + } - if (0 != (Item->fState & MF_GRAYED)) - { - if (0 == (Item->fState & MF_HILITE)) - { - ++Rect.left; ++Rect.top; ++Rect.right; ++Rect.bottom; - SetTextColor(Dc, RGB(0xff, 0xff, 0xff)); - DrawTextW(Dc, Text, i, &Rect, uFormat); - --Rect.left; --Rect.top; --Rect.right; --Rect.bottom; - } - SetTextColor(Dc, RGB(0x80, 0x80, 0x80)); + /* process text if present */ + if (lpitem->Text) + { + register int i = 0; + HFONT hfontOld = 0; + + UINT uFormat = menuBar ? DT_CENTER | DT_VCENTER | DT_SINGLELINE + : DT_LEFT | DT_VCENTER | DT_SINGLELINE; + + if(MenuInfo->dwStyle & MNS_CHECKORBMP) + rect.left += max(0, MenuInfo->maxBmpSize.cx - GetSystemMetrics(SM_CXMENUCHECK)); + else + rect.left += MenuInfo->maxBmpSize.cx; + + if ( lpitem->fState & MFS_DEFAULT ) + { + hfontOld = SelectObject(hdc, hMenuFontBold); } - DrawTextW(Dc, Text, i, &Rect, uFormat); + if (menuBar) { + rect.left += MENU_BAR_ITEMS_SPACE / 2; + rect.right -= MENU_BAR_ITEMS_SPACE / 2; + } - /* paint the shortcut text */ - if (! MenuBar && L'\0' != Text[i]) /* There's a tab or flush-right char */ + Text = (PWCHAR) lpitem->dwTypeData; + if(Text) { - if (L'\t' == Text[i]) + for (i = 0; L'\0' != Text[i]; i++) + if (Text[i] == L'\t' || Text[i] == L'\b') + break; + } + + if(lpitem->fState & MF_GRAYED) + { + if (!(lpitem->fState & MF_HILITE) ) { - Rect.left = Item->XTab; - uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE; + ++rect.left; ++rect.top; ++rect.right; ++rect.bottom; + SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); + DrawTextW( hdc, Text, i, &rect, uFormat ); + --rect.left; --rect.top; --rect.right; --rect.bottom; + } + SetTextColor(hdc, RGB(0x80, 0x80, 0x80)); + } + + DrawTextW( hdc, Text, i, &rect, uFormat); + + /* paint the shortcut text */ + if (!menuBar && L'\0' != Text[i]) /* There's a tab or flush-right char */ + { + if (L'\t' == Text[i]) + { + rect.left = lpitem->XTab; + uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE; } - else + else { - Rect.right = Item->XTab; - uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE; + rect.right = lpitem->XTab; + uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE; } - if (0 != (Item->fState & MF_GRAYED)) + if (lpitem->fState & MF_GRAYED) { - if (0 == (Item->fState & MF_HILITE)) + if (!(lpitem->fState & MF_HILITE) ) { - ++Rect.left; ++Rect.top; ++Rect.right; ++Rect.bottom; - SetTextColor(Dc, RGB(0xff, 0xff, 0xff)); - DrawTextW(Dc, Text + i + 1, -1, &Rect, uFormat); - --Rect.left; --Rect.top; --Rect.right; --Rect.bottom; + ++rect.left; ++rect.top; ++rect.right; ++rect.bottom; + SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); + DrawTextW( hdc, Text + i + 1, -1, &rect, uFormat); + --rect.left; --rect.top; --rect.right; --rect.bottom; } - SetTextColor(Dc, RGB(0x80, 0x80, 0x80)); - } - DrawTextW(Dc, Text + i + 1, -1, &Rect, uFormat); + SetTextColor(hdc, RGB(0x80, 0x80, 0x80)); + } + DrawTextW( hdc, Text + i + 1, -1, &rect, uFormat ); } - if (NULL != FontOld) - { - SelectObject(Dc, FontOld); - } - } + if (hfontOld) + SelectObject (hdc, hfontOld); + } } /*********************************************************************** @@ -917,61 +1313,187 @@ MenuDrawMenuItem(HWND hWnd, PROSMENUINFO MenuInfo, HWND WndOwner, HDC Dc, * * Paint a popup menu. */ -static void FASTCALL -MenuDrawPopupMenu(HWND Wnd, HDC Dc, HMENU Menu) +static void FASTCALL MenuDrawPopupMenu(HWND hwnd, HDC hdc, HMENU hmenu ) { - HBRUSH PrevBrush = NULL; - HPEN PrevPen; - RECT Rect; - ROSMENUINFO MenuInfo; - ROSMENUITEMINFO ItemInfo; - UINT u; + HBRUSH hPrevBrush = 0; + RECT rect; - TRACE("wnd=%x dc=%x menu=%x\n", Wnd, Dc, Menu); + TRACE("wnd=%p dc=%p menu=%p\n", hwnd, hdc, hmenu); - GetClientRect(Wnd, &Rect); + GetClientRect( hwnd, &rect ); - if (NULL != (PrevBrush = SelectObject(Dc, GetSysColorBrush(COLOR_MENU))) - && NULL != SelectObject(Dc, hMenuFont)) + if((hPrevBrush = SelectObject( hdc, GetSysColorBrush(COLOR_MENU) )) + && (SelectObject( hdc, hMenuFont))) { - Rectangle(Dc, Rect.left, Rect.top, Rect.right, Rect.bottom); + HPEN hPrevPen; - PrevPen = SelectObject(Dc, GetStockObject(NULL_PEN)); - if (NULL != PrevPen) + Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom ); + + hPrevPen = SelectObject( hdc, GetStockObject( NULL_PEN ) ); + if ( hPrevPen ) { - BOOL flat_menu = FALSE; + BOOL flat_menu = FALSE; + ROSMENUINFO MenuInfo; + ROSMENUITEMINFO ItemInfo; - SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0); - if (flat_menu) - FrameRect(Dc, &Rect, GetSysColorBrush(COLOR_BTNSHADOW)); - else - DrawEdge(Dc, &Rect, EDGE_RAISED, BF_RECT); + SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0); + if (flat_menu) + FrameRect(hdc, &rect, GetSysColorBrush(COLOR_BTNSHADOW)); + else + DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT); - /* draw menu items */ - - if (MenuGetRosMenuInfo(&MenuInfo, Menu) && 0 != MenuInfo.MenuItemCount) + /* draw menu items */ + if (MenuGetRosMenuInfo(&MenuInfo, hmenu) && MenuInfo.MenuItemCount) { - MenuInitRosMenuItemInfo(&ItemInfo); + UINT u; + + MenuInitRosMenuItemInfo(&ItemInfo); - for (u = 0; u < MenuInfo.MenuItemCount; u++) + for (u = 0; u < MenuInfo.MenuItemCount; u++) { - if (MenuGetRosMenuItemInfo(MenuInfo.Self, u, &ItemInfo)) + if (MenuGetRosMenuItemInfo(MenuInfo.Self, u, &ItemInfo)) { - MenuDrawMenuItem(Wnd, &MenuInfo, MenuInfo.WndOwner, Dc, &ItemInfo, - MenuInfo.Height, FALSE, ODA_DRAWENTIRE); + MenuDrawMenuItem(hwnd, &MenuInfo, MenuInfo.WndOwner, hdc, &ItemInfo, + MenuInfo.Height, FALSE, ODA_DRAWENTIRE); } } - MenuCleanupRosMenuItemInfo(&ItemInfo); - } - } - else - { - SelectObject(Dc, PrevBrush); - } + MenuCleanupRosMenuItemInfo(&ItemInfo); + } + } else + { + SelectObject( hdc, hPrevBrush ); + } } } +/*********************************************************************** + * MenuDrawMenuBar + * + * Paint a menu bar. Returns the height of the menu bar. + * called from [windows/nonclient.c] + */ +UINT MenuDrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd, + BOOL suppress_draw) +{ + ROSMENUINFO lppop; + HFONT hfontOld = 0; + HMENU hMenu = GetMenu(hwnd); + + if (! MenuGetRosMenuInfo(&lppop, hMenu) || lprect == NULL) + { + return GetSystemMetrics(SM_CYMENU); + } + + if (suppress_draw) + { + hfontOld = SelectObject(hDC, hMenuFont); + + MenuMenuBarCalcSize(hDC, lprect, &lppop, hwnd); + + lprect->bottom = lprect->top + lppop.Height; + + if (hfontOld) SelectObject( hDC, hfontOld); + return lppop.Height; + } + else + return DrawMenuBarTemp(hwnd, hDC, lprect, hMenu, NULL); +} + +/*********************************************************************** + * MenuShowPopup + * + * Display a popup menu. + */ +static BOOL FASTCALL MenuShowPopup(HWND hwndOwner, HMENU hmenu, UINT id, UINT flags, + INT x, INT y, INT xanchor, INT yanchor ) +{ + ROSMENUINFO MenuInfo; + ROSMENUITEMINFO ItemInfo; + UINT width, height; + POINT pt; + HMONITOR monitor; + MONITORINFO info; + + TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n", + hwndOwner, hmenu, id, x, y, xanchor, yanchor); + + if (! MenuGetRosMenuInfo(&MenuInfo, hmenu)) return FALSE; + if (MenuInfo.FocusedItem != NO_SELECTED_ITEM) + { + MenuInitRosMenuItemInfo(&ItemInfo); + if (MenuGetRosMenuItemInfo(MenuInfo.Self, MenuInfo.FocusedItem, &ItemInfo)) + { + ItemInfo.fMask |= MIIM_STATE; + ItemInfo.fState &= ~(MF_HILITE|MF_MOUSESELECT); + MenuSetRosMenuItemInfo(MenuInfo.Self, MenuInfo.FocusedItem, &ItemInfo); + } + MenuCleanupRosMenuItemInfo(&ItemInfo); + MenuInfo.FocusedItem = NO_SELECTED_ITEM; + } + + /* store the owner for DrawItem */ + MenuInfo.WndOwner = hwndOwner; + MenuSetRosMenuInfo(&MenuInfo); + + MenuPopupMenuCalcSize(&MenuInfo, hwndOwner); + + /* adjust popup menu pos so that it fits within the desktop */ + + width = MenuInfo.Width + GetSystemMetrics(SM_CXBORDER); + height = MenuInfo.Height + GetSystemMetrics(SM_CYBORDER); + + /* FIXME: should use item rect */ + pt.x = x; + pt.y = y; + monitor = MonitorFromPoint( pt, MONITOR_DEFAULTTONEAREST ); + info.cbSize = sizeof(info); + GetMonitorInfoW( monitor, &info ); + + if( flags & TPM_RIGHTALIGN ) x -= width; + if( flags & TPM_CENTERALIGN ) x -= width / 2; + + if( flags & TPM_BOTTOMALIGN ) y -= height; + if( flags & TPM_VCENTERALIGN ) y -= height / 2; + + if( x + width > info.rcWork.right) + { + if( xanchor && x >= width - xanchor ) + x -= width - xanchor; + + if( x + width > info.rcWork.right) + x = info.rcWork.right - width; + } + if( x < info.rcWork.left ) x = info.rcWork.left; + + if( y + height > info.rcWork.bottom) + { + if( yanchor && y >= height + yanchor ) + y -= height + yanchor; + + if( y + height > info.rcWork.bottom) + y = info.rcWork.bottom - height; + } + if( y < info.rcWork.top ) y = info.rcWork.top; + + /* NOTE: In Windows, top menu popup is not owned. */ + MenuInfo.Wnd = CreateWindowExW( 0, POPUPMENU_CLASS_ATOMW, NULL, + WS_POPUP, x, y, width, height, + hwndOwner, 0, (HINSTANCE) GetWindowLongPtrW(hwndOwner, GWLP_HINSTANCE), + (LPVOID) MenuInfo.Self); + if ( !MenuInfo.Wnd || ! MenuSetRosMenuInfo(&MenuInfo)) return FALSE; + if (!TopPopup) { + TopPopup = MenuInfo.Wnd; + } + + /* Display the window */ + + SetWindowPos( MenuInfo.Wnd, HWND_TOPMOST, 0, 0, 0, 0, + SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); + UpdateWindow( MenuInfo.Wnd ); + return TRUE; +} + LRESULT WINAPI PopupMenuWndProcA(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam) { @@ -1320,7 +1842,6 @@ MenuInit(VOID) return TRUE; } - VOID MenuCleanup(VOID) { @@ -1337,435 +1858,6 @@ MenuCleanup(VOID) } } - - -/*********************************************************************** - * MenuCalcItemSize - * - * Calculate the size of the menu item and store it in ItemInfo->rect. - */ -static void FASTCALL -MenuCalcItemSize(HDC Dc, PROSMENUITEMINFO ItemInfo, PROSMENUINFO MenuInfo, HWND WndOwner, - INT OrgX, INT OrgY, BOOL MenuBar) -{ - PWCHAR p; - INT itemheight = 0; - UINT CheckBitmapWidth = GetSystemMetrics(SM_CXMENUCHECK); - - TRACE("dc=%x owner=%x (%d,%d)\n", Dc, WndOwner, OrgX, OrgY); - - MenuCharSize.cx = GdiGetCharDimensions( Dc, NULL, &MenuCharSize.cy ); - - SetRect(&ItemInfo->Rect, OrgX, OrgY, OrgX, OrgY); - - if (0 != (ItemInfo->fType & MF_OWNERDRAW)) - { - /* - ** Experimentation under Windows reveals that an owner-drawn - ** menu is expected to return the size of the content part of - ** the menu item, not including the checkmark nor the submenu - ** arrow. Windows adds those values itself and returns the - ** enlarged rectangle on subsequent WM_DRAWITEM messages. - */ - MEASUREITEMSTRUCT mis; - mis.CtlType = ODT_MENU; - mis.CtlID = 0; - mis.itemID = ItemInfo->wID; - mis.itemData = (DWORD)ItemInfo->dwItemData; - mis.itemHeight = HIWORD( GetDialogBaseUnits()); - mis.itemWidth = 0; - SendMessageW(WndOwner, WM_MEASUREITEM, 0, (LPARAM) &mis); - /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average - * width of a menufont character to the width of an owner-drawn menu. - */ - ItemInfo->Rect.right += mis.itemWidth + 2 * MenuCharSize.cx; - - if (MenuBar) - { - /* under at least win95 you seem to be given a standard - height for the menu and the height value is ignored */ - ItemInfo->Rect.bottom += GetSystemMetrics(SM_CYMENUSIZE); - } - else - { - ItemInfo->Rect.bottom += mis.itemHeight; - } - - TRACE("id=%04x size=%dx%d\n", ItemInfo->wID, mis.itemWidth, mis.itemHeight); - return; - } - - if (0 != (ItemInfo->fType & MF_SEPARATOR)) - { - ItemInfo->Rect.bottom += SEPARATOR_HEIGHT; - if( !MenuBar) - ItemInfo->Rect.right += CheckBitmapWidth + MenuCharSize.cx; - return; - } - - ItemInfo->XTab = 0; - - if (ItemInfo->hbmpItem) - { - SIZE Size; - - if (!MenuBar) /* hbmpItem */ - { - MenuGetBitmapItemSize(ItemInfo, &Size, WndOwner ); - /* Keep the size of the bitmap in callback mode to be able - * to draw it correctly */ - ItemInfo->Rect.right = ItemInfo->Rect.left + Size.cx; - if (MenuInfo->maxBmpSize.cx < abs(Size.cx) + MENU_ITEM_HBMP_SPACE || - MenuInfo->maxBmpSize.cy < abs(Size.cy)) - { - MenuInfo->maxBmpSize.cx = abs(Size.cx) + MENU_ITEM_HBMP_SPACE; - MenuInfo->maxBmpSize.cy = abs(Size.cy); - } - MenuSetRosMenuInfo(MenuInfo); - itemheight = Size.cy + 2; - - if( !(MenuInfo->dwStyle & MNS_NOCHECK)) - ItemInfo->Rect.right += 2 * CheckBitmapWidth; - ItemInfo->Rect.right += 4 + MenuCharSize.cx; - ItemInfo->XTab = ItemInfo->Rect.right; - ItemInfo->Rect.right += CheckBitmapWidth; - } - else /* hbmpItem & MenuBar */ - { - MenuGetBitmapItemSize(ItemInfo, &Size, WndOwner ); - ItemInfo->Rect.right += Size.cx; - if( ItemInfo->Text) ItemInfo->Rect.right += 2; - itemheight = Size.cy; - - /* Special case: Minimize button doesn't have a space behind it. */ - if (ItemInfo->hbmpItem == (HBITMAP)HBMMENU_MBAR_MINIMIZE || - ItemInfo->hbmpItem == (HBITMAP)HBMMENU_MBAR_MINIMIZE_D) - ItemInfo->Rect.right -= 1; - } - } - else if (!MenuBar) - { - if( !(MenuInfo->dwStyle & MNS_NOCHECK)) - ItemInfo->Rect.right += CheckBitmapWidth; - ItemInfo->Rect.right += 4 + MenuCharSize.cx; - ItemInfo->XTab = ItemInfo->Rect.right; - ItemInfo->Rect.right += CheckBitmapWidth; - } - - /* it must be a text item - unless it's the system menu */ - if (0 == (ItemInfo->fType & MF_SYSMENU) && ItemInfo->Text) - { - HFONT hfontOld = NULL; - RECT rc = ItemInfo->Rect; - LONG txtheight, txtwidth; - - if ( ItemInfo->fState & MFS_DEFAULT ) - { - hfontOld = SelectObject( Dc, hMenuFontBold ); - } - if (MenuBar) - { - txtheight = DrawTextW( Dc, ItemInfo->dwTypeData, -1, &rc, - DT_SINGLELINE|DT_CALCRECT); - ItemInfo->Rect.right += rc.right - rc.left; - itemheight = max( max( itemheight, txtheight), - GetSystemMetrics( SM_CYMENU) - 1); - ItemInfo->Rect.right += 2 * MenuCharSize.cx; - } - else - { - if ((p = strchrW( ItemInfo->dwTypeData, '\t' )) != NULL) - { - RECT tmprc = rc; - LONG tmpheight; - int n = (int)( p - ItemInfo->dwTypeData); - /* Item contains a tab (only meaningful in popup menus) */ - /* get text size before the tab */ - txtheight = DrawTextW( Dc, ItemInfo->dwTypeData, n, &rc, - DT_SINGLELINE|DT_CALCRECT); - txtwidth = rc.right - rc.left; - p += 1; /* advance past the Tab */ - /* get text size after the tab */ - tmpheight = DrawTextW( Dc, p, -1, &tmprc, DT_SINGLELINE|DT_CALCRECT); - ItemInfo->XTab += txtwidth; - txtheight = max( txtheight, tmpheight); - txtwidth += MenuCharSize.cx + /* space for the tab */ - tmprc.right - tmprc.left; /* space for the short cut */ - } - else - { - txtheight = DrawTextW( Dc, ItemInfo->dwTypeData, -1, &rc, - DT_SINGLELINE|DT_CALCRECT); - txtwidth = rc.right - rc.left; - ItemInfo->XTab += txtwidth; - } - ItemInfo->Rect.right += 2 + txtwidth; - itemheight = max( itemheight, max( txtheight + 2, MenuCharSize.cy + 4)); - } - if (hfontOld) SelectObject (Dc, hfontOld); - } - else if( MenuBar) - { - itemheight = max( itemheight, GetSystemMetrics(SM_CYMENU)-1); - } - ItemInfo->Rect.bottom += itemheight; - TRACE("(%ld,%ld)-(%ld,%ld)\n", ItemInfo->Rect.left, ItemInfo->Rect.top, ItemInfo->Rect.right, ItemInfo->Rect.bottom); -} - -/*********************************************************************** - * MenuPopupMenuCalcSize - * - * Calculate the size of a popup menu. - */ -static void FASTCALL -MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo, HWND WndOwner) -{ - ROSMENUITEMINFO ItemInfo; - HDC Dc; - int Start, i; - int OrgX, OrgY, MaxX, MaxTab, MaxTabWidth; - - MenuInfo->Width = MenuInfo->Height = 0; - if (0 == MenuInfo->MenuItemCount) - { - MenuSetRosMenuInfo(MenuInfo); - return; - } - - Dc = GetDC(NULL); - SelectObject(Dc, hMenuFont); - - Start = 0; - MaxX = 2 + 1; - - MenuInfo->maxBmpSize.cx = 0; - MenuInfo->maxBmpSize.cy = 0; - - MenuInitRosMenuItemInfo(&ItemInfo); - while (Start < MenuInfo->MenuItemCount) - { - OrgX = MaxX; - OrgY = 2; - - MaxTab = MaxTabWidth = 0; - - /* Parse items until column break or end of menu */ - for (i = Start; i < MenuInfo->MenuItemCount; i++) - { - if (! MenuGetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo)) - { - MenuCleanupRosMenuItemInfo(&ItemInfo); - MenuSetRosMenuInfo(MenuInfo); - return; - } - if (i != Start && - 0 != (ItemInfo.fType & (MF_MENUBREAK | MF_MENUBARBREAK))) - { - break; - } - MenuCalcItemSize(Dc, &ItemInfo, MenuInfo, WndOwner, OrgX, OrgY, FALSE); - if (! MenuSetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo)) - { - MenuCleanupRosMenuItemInfo(&ItemInfo); - MenuSetRosMenuInfo(MenuInfo); - return; - } -// Not sure here,, The patch from wine removes this. -// if (0 != (ItemInfo.fType & MF_MENUBARBREAK)) -// { -// OrgX++; -// } - MaxX = max(MaxX, ItemInfo.Rect.right); - OrgY = ItemInfo.Rect.bottom; - if ((ItemInfo.Text) && 0 != ItemInfo.XTab) - { - MaxTab = max(MaxTab, ItemInfo.XTab); - MaxTabWidth = max(MaxTabWidth, ItemInfo.Rect.right - ItemInfo.XTab); - } - } - - /* Finish the column (set all items to the largest width found) */ - MaxX = max(MaxX, MaxTab + MaxTabWidth); - while (Start < i) - { - if (MenuGetRosMenuItemInfo(MenuInfo->Self, Start, &ItemInfo)) - { - ItemInfo.Rect.right = MaxX; - if ((ItemInfo.Text) && 0 != ItemInfo.XTab) - { - ItemInfo.XTab = MaxTab; - } - MenuSetRosMenuItemInfo(MenuInfo->Self, Start, &ItemInfo); - } - Start++; - } - MenuInfo->Height = max(MenuInfo->Height, OrgY); - } - - MenuInfo->Width = MaxX; - - /* space for 3d border */ - MenuInfo->Height += 2; - MenuInfo->Width += 2; - - ReleaseDC(NULL, Dc); - MenuCleanupRosMenuItemInfo(&ItemInfo); - MenuSetRosMenuInfo(MenuInfo); -} - -/*********************************************************************** - * MenuMenuBarCalcSize - * - * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap - * height is off by 1 pixel which causes lengthy window relocations when - * active document window is maximized/restored. - * - * Calculate the size of the menu bar. - */ -static void FASTCALL -MenuMenuBarCalcSize(HDC Dc, LPRECT Rect, PROSMENUINFO MenuInfo, HWND WndOwner) -{ - ROSMENUITEMINFO ItemInfo; - int Start, i, OrgX, OrgY, MaxY, HelpPos; - - if (NULL == Rect || NULL == MenuInfo) - { - return; - } - if (0 == MenuInfo->MenuItemCount) - { - return; - } - - TRACE("left=%ld top=%ld right=%ld bottom=%ld\n", - Rect->left, Rect->top, Rect->right, Rect->bottom); - MenuInfo->Width = Rect->right - Rect->left; - MenuInfo->Height = 0; - MaxY = Rect->top + 1; - Start = 0; - HelpPos = -1; - - MenuInfo->maxBmpSize.cx = 0; - MenuInfo->maxBmpSize.cy = 0; - - MenuInitRosMenuItemInfo(&ItemInfo); - while (Start < MenuInfo->MenuItemCount) - { - if (! MenuGetRosMenuItemInfo(MenuInfo->Self, Start, &ItemInfo)) - { - MenuCleanupRosMenuItemInfo(&ItemInfo); - return; - } - OrgX = Rect->left; - OrgY = MaxY; - - /* Parse items until line break or end of menu */ - for (i = Start; i < MenuInfo->MenuItemCount; i++) - { - if (-1 == HelpPos && 0 != (ItemInfo.fType & MF_RIGHTJUSTIFY)) - { - HelpPos = i; - } - if (i != Start && - 0 != (ItemInfo.fType & (MF_MENUBREAK | MF_MENUBARBREAK))) - { - break; - } - - TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", OrgX, OrgY); - MenuCalcItemSize(Dc, &ItemInfo, MenuInfo, WndOwner, OrgX, OrgY, TRUE); - if (! MenuSetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo)) - { - MenuCleanupRosMenuItemInfo(&ItemInfo); - return; - } - - if (ItemInfo.Rect.right > Rect->right) - { - if (i != Start) - { - break; - } - else - { - ItemInfo.Rect.right = Rect->right; - } - } - MaxY = max(MaxY, ItemInfo.Rect.bottom ); - OrgX = ItemInfo.Rect.right; - if (i + 1 < MenuInfo->MenuItemCount) - { - if (! MenuGetRosMenuItemInfo(MenuInfo->Self, i + 1, &ItemInfo)) - { - MenuCleanupRosMenuItemInfo(&ItemInfo); - return; - } - } - } - -/* FIXME: Is this really needed? */ /*NO! it is not needed, why make the -HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */ -#if 0 - /* Finish the line (set all items to the largest height found) */ - while (Start < i) - { - if (MenuGetRosMenuItemInfo(MenuInfo->Self, Start, &ItemInfo)) - { - ItemInfo.Rect.bottom = MaxY; - MenuSetRosMenuItemInfo(MenuInfo->Self, Start, &ItemInfo); - } - Start++; - } -#else - Start = i; /* This works! */ -#endif - } - - Rect->bottom = MaxY; - MenuInfo->Height = Rect->bottom - Rect->top; - MenuSetRosMenuInfo(MenuInfo); - - if (-1 != HelpPos) - { - /* Flush right all items between the MF_RIGHTJUSTIFY and */ - /* the last item (if several lines, only move the last line) */ - if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->MenuItemCount - 1, &ItemInfo)) - { - MenuCleanupRosMenuItemInfo(&ItemInfo); - return; - } - OrgY = ItemInfo.Rect.top; - OrgX = Rect->right; - for (i = MenuInfo->MenuItemCount - 1; HelpPos <= i; i--) - { - if (i < HelpPos) - { - break; /* done */ - } - if (ItemInfo.Rect.top != OrgY) - { - break; /* Other line */ - } - if (OrgX <= ItemInfo.Rect.right) - { - break; /* Too far right already */ - } - ItemInfo.Rect.left += OrgX - ItemInfo.Rect.right; - ItemInfo.Rect.right = OrgX; - OrgX = ItemInfo.Rect.left; - MenuSetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo); - if (HelpPos + 1 <= i && - ! MenuGetRosMenuItemInfo(MenuInfo->Self, i - 1, &ItemInfo)) - { - MenuCleanupRosMenuItemInfo(&ItemInfo); - return; - } - } - } - - MenuCleanupRosMenuItemInfo(&ItemInfo); -} - /*********************************************************************** * DrawMenuBarTemp (USER32.@) * @@ -1843,44 +1935,6 @@ DrawMenuBarTemp(HWND Wnd, HDC DC, LPRECT Rect, HMENU Menu, HFONT Font) return MenuInfo.Height; } - -/*********************************************************************** - * MenuDrawMenuBar - * - * Paint a menu bar. Returns the height of the menu bar. - * called from [windows/nonclient.c] - */ -UINT MenuDrawMenuBar(HDC DC, LPRECT Rect, HWND Wnd, BOOL SuppressDraw) -{ - ROSMENUINFO MenuInfo; - HFONT FontOld = NULL; - HMENU Menu = GetMenu(Wnd); - - if (NULL == Rect || ! MenuGetRosMenuInfo(&MenuInfo, Menu)) - { - return GetSystemMetrics(SM_CYMENU); - } - - if (SuppressDraw) - { - FontOld = SelectObject(DC, hMenuFont); - - MenuMenuBarCalcSize(DC, Rect, &MenuInfo, Wnd); - - Rect->bottom = Rect->top + MenuInfo.Height; - - if (NULL != FontOld) - { - SelectObject(DC, FontOld); - } - return MenuInfo.Height; - } - else - { - return DrawMenuBarTemp(Wnd, DC, Rect, Menu, NULL); - } -} - /*********************************************************************** * MenuInitTracking */ @@ -1929,112 +1983,6 @@ MenuInitTracking(HWND Wnd, HMENU Menu, BOOL Popup, UINT Flags) return TRUE; } - -/*********************************************************************** - * MenuShowPopup - * - * Display a popup menu. - */ -static BOOL FASTCALL -MenuShowPopup(HWND WndOwner, HMENU Menu, UINT Id, UINT flags, - INT X, INT Y, INT XAnchor, INT YAnchor ) -{ - ROSMENUINFO MenuInfo; - ROSMENUITEMINFO ItemInfo; - UINT Width, Height; - POINT pt; - HMONITOR monitor; - MONITORINFO info; - - TRACE("owner=%x hmenu=%x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n", - WndOwner, Menu, Id, X, Y, XAnchor, YAnchor); - - if (! MenuGetRosMenuInfo(&MenuInfo, Menu)) - { - return FALSE; - } - - if (NO_SELECTED_ITEM != MenuInfo.FocusedItem) - { - MenuInitRosMenuItemInfo(&ItemInfo); - if (MenuGetRosMenuItemInfo(MenuInfo.Self, MenuInfo.FocusedItem, &ItemInfo)) - { - ItemInfo.fMask |= MIIM_STATE; - ItemInfo.fState &= ~(MF_HILITE|MF_MOUSESELECT); - MenuSetRosMenuItemInfo(MenuInfo.Self, MenuInfo.FocusedItem, &ItemInfo); - } - MenuCleanupRosMenuItemInfo(&ItemInfo); - MenuInfo.FocusedItem = NO_SELECTED_ITEM; - } - - /* store the owner for DrawItem */ - MenuInfo.WndOwner = WndOwner; - MenuSetRosMenuInfo(&MenuInfo); - - MenuPopupMenuCalcSize(&MenuInfo, WndOwner); - - /* adjust popup menu pos so that it fits within the desktop */ - - Width = MenuInfo.Width + GetSystemMetrics(SM_CXBORDER); - Height = MenuInfo.Height + GetSystemMetrics(SM_CYBORDER); - - /* FIXME: should use item rect */ - pt.x = X; - pt.y = Y; - monitor = MonitorFromPoint( pt, MONITOR_DEFAULTTONEAREST ); - info.cbSize = sizeof(info); - GetMonitorInfoW( monitor, &info ); - - if( flags & TPM_RIGHTALIGN ) X -= Width; - if( flags & TPM_CENTERALIGN ) X -= Width / 2; - - if( flags & TPM_BOTTOMALIGN ) Y -= Height; - if( flags & TPM_VCENTERALIGN ) Y -= Height / 2; - - if (X + Width > info.rcWork.right) - { - if ( XAnchor && X >= Width - XAnchor) - X -= Width - XAnchor; - - if ( X + Width > info.rcWork.right) - X = info.rcWork.right - Width; - } - - if ( X < info.rcWork.left ) X = info.rcWork.left; - - if (Y + Height > info.rcWork.bottom) - { - if ( YAnchor && Y >= Height + YAnchor) - Y -= Height + YAnchor; - - if ( Y + Height > info.rcWork.bottom) - Y = info.rcWork.bottom - Height; - } - - if ( Y < info.rcWork.top ) Y = info.rcWork.top; - - /* NOTE: In Windows, top menu popup is not owned. */ - MenuInfo.Wnd = CreateWindowExW(0, POPUPMENU_CLASS_ATOMW, NULL, - WS_POPUP, X, Y, Width, Height, - WndOwner, 0, (HINSTANCE) GetWindowLongPtrW(WndOwner, GWLP_HINSTANCE), - (LPVOID) MenuInfo.Self); - if (NULL == MenuInfo.Wnd || ! MenuSetRosMenuInfo(&MenuInfo)) - { - return FALSE; - } - if (NULL == TopPopup) - { - TopPopup = MenuInfo.Wnd; - } - - /* Display the window */ - SetWindowPos(MenuInfo.Wnd, HWND_TOPMOST, 0, 0, 0, 0, - SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); - UpdateWindow(MenuInfo.Wnd); - - return TRUE; -} - /*********************************************************************** * MenuFindSubMenu * @@ -3280,78 +3228,6 @@ MenuKeyRight(MTRACKER *Mt, UINT Flags) } } -/*********************************************************************** - * MenuFindItemByKey - * - * Find the menu item selected by a key press. - * Return item id, -1 if none, -2 if we should close the menu. - */ -static UINT FASTCALL -MenuFindItemByKey(HWND WndOwner, PROSMENUINFO MenuInfo, - WCHAR Key, BOOL ForceMenuChar) -{ - ROSMENUINFO SysMenuInfo; - PROSMENUITEMINFO Items, ItemInfo; - LRESULT MenuChar; - UINT i; - - TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key, Key, MenuInfo); - - if (NULL == MenuInfo || ! IsMenu(MenuInfo->Self)) - { - if (MenuGetRosMenuInfo(&SysMenuInfo, GetSystemMenu(WndOwner, FALSE))) - { - MenuInfo = &SysMenuInfo; - } - else - { - MenuInfo = NULL; - } - } - - if (NULL != MenuInfo) - { - if (MenuGetAllRosMenuItemInfo(MenuInfo->Self, &Items) <= 0) - { - return -1; - } - if (! ForceMenuChar) - { - Key = toupperW(Key); - ItemInfo = Items; - for (i = 0; i < MenuInfo->MenuItemCount; i++, ItemInfo++) - { - if ((ItemInfo->Text) && NULL != ItemInfo->dwTypeData) - { - WCHAR *p = (WCHAR *) ItemInfo->dwTypeData - 2; - do - { - p = strchrW(p + 2, '&'); - } - while (NULL != p && L'&' == p[1]); - if (NULL != p && (toupperW(p[1]) == Key)) - { - return i; - } - } - } - } - - MenuChar = SendMessageW(WndOwner, WM_MENUCHAR, - MAKEWPARAM(Key, MenuInfo->Flags), (LPARAM) MenuInfo->Self); - if (2 == HIWORD(MenuChar)) - { - return LOWORD(MenuChar); - } - if (1 == HIWORD(MenuChar)) - { - return (UINT) (-2); - } - } - - return (UINT)(-1); -} - /*********************************************************************** * MenuTrackMenu * @@ -3437,7 +3313,7 @@ MenuTrackMenu(HMENU Menu, UINT Flags, INT x, INT y, } /* check if EndMenu() tried to cancel us, by posting this message */ - if (WM_CANCELMODE == Msg.message) + if (Msg.message == WM_CANCELMODE) { /* we are now out of the loop */ fEndMenu = TRUE; @@ -3452,13 +3328,13 @@ MenuTrackMenu(HMENU Menu, UINT Flags, INT x, INT y, TranslateMessage(&Msg); Mt.Pt = Msg.pt; - if (Msg.hwnd == MenuInfo.Wnd || WM_TIMER != Msg.message) + if (Msg.hwnd == MenuInfo.Wnd || Msg.message != WM_TIMER) { EnterIdleSent = FALSE; } fRemove = FALSE; - if (WM_MOUSEFIRST <= Msg.message && Msg.message <= WM_MOUSELAST) + if ((Msg.message >= WM_MOUSEFIRST) && (Msg.message <= WM_MOUSELAST)) { /* * Use the mouse coordinates in lParam instead of those in the MSG @@ -3477,10 +3353,7 @@ MenuTrackMenu(HMENU Menu, UINT Flags, INT x, INT y, case WM_RBUTTONDBLCLK: case WM_RBUTTONDOWN: - if (0 == (Flags & TPM_RIGHTBUTTON)) - { - break; - } + if (!(Flags & TPM_RIGHTBUTTON)) break; /* fall through */ case WM_LBUTTONDBLCLK: case WM_LBUTTONDOWN: @@ -3491,14 +3364,11 @@ MenuTrackMenu(HMENU Menu, UINT Flags, INT x, INT y, break; case WM_RBUTTONUP: - if (0 == (Flags & TPM_RIGHTBUTTON)) - { - break; - } + if (0 == (Flags & TPM_RIGHTBUTTON)) break; /* fall through */ case WM_LBUTTONUP: /* Check if a menu was selected by the mouse */ - if (NULL != Menu) + if (Menu) { ExecutedMenuId = MenuButtonUp(&Mt, Menu, Flags); @@ -3518,13 +3388,13 @@ MenuTrackMenu(HMENU Menu, UINT Flags, INT x, INT y, case WM_MOUSEMOVE: if (Menu) { - fEndMenu |= ! MenuMouseMove(&Mt, Menu, Flags); + fEndMenu |= !MenuMouseMove(&Mt, Menu, Flags); } break; } /* switch(Msg.message) - mouse */ } - else if (WM_KEYFIRST <= Msg.message && Msg.message <= WM_KEYLAST) + else if ((Msg.message >= WM_KEYFIRST) && (Msg.message <= WM_KEYLAST)) { fRemove = TRUE; /* Keyboard messages are always removed */ switch(Msg.message) From 4670adcf3596ad481e4f4374266b1714ff3db25d Mon Sep 17 00:00:00 2001 From: Daniel Reimer Date: Tue, 16 Mar 2010 22:37:53 +0000 Subject: [PATCH 47/61] Update some more apps. (OpenOffice 3.2.0, SciTE 2.03) svn path=/trunk/; revision=46232 --- .../applications/rapps/rapps/openoffice3.0.txt | 18 +++++++++--------- .../base/applications/rapps/rapps/scite.txt | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/reactos/base/applications/rapps/rapps/openoffice3.0.txt b/reactos/base/applications/rapps/rapps/openoffice3.0.txt index ebfc63ede1c..b9ee71bd025 100644 --- a/reactos/base/applications/rapps/rapps/openoffice3.0.txt +++ b/reactos/base/applications/rapps/rapps/openoffice3.0.txt @@ -2,30 +2,30 @@ [Section] Name = OpenOffice 3.0 -Version = 3.1.1 +Version = 3.2.0 Licence = LGPL Description = THE Open Source Office Suite. -Size = 134.3MB +Size = 135.4MB Category = 6 URLSite = http://www.openoffice.org/ -URLDownload = http://ftp.tu-chemnitz.de/pub/openoffice/stable/3.1.1/OOo_3.1.1_Win32Intel_install_en-US.exe +URLDownload = http://ftp.tu-chemnitz.de/pub/openoffice/stable/3.2.0/OOo_3.2.0_Win32Intel_install_en-US.exe CDPath = none [Section.0407] Description = DIE Open Source Office Suite. URLSite = http://de.openoffice.org/ -Size = 142.9MB -URLDownload = http://ftp.tu-chemnitz.de/pub/openoffice/localized/de/3.1.1/OOo_3.1.1_Win32Intel_install_de.exe +Size = 145.8MB +URLDownload = http://ftp.tu-chemnitz.de/pub/openoffice/localized/de/3.2.0/OOo_3.2.0_Win32Intel_install_de.exe [Section.040a] Description = La suite de ofimática de código abierto. URLSite = http://es.openoffice.org/ Version = 3.1.0 -Size = 130.0MB -URLDownload = http://ftp.tu-chemnitz.de/pub/openoffice/localized/es/3.1.0/OOo_3.1.0_Win32Intel_install_es.exe +Size = 119.4MB +URLDownload = http://ftp.tu-chemnitz.de/pub/openoffice/localized/es/3.2.0/OOo_3.2.0_Win32Intel_install_es.exe [Section.0415] Description = Otwarty pakiet biurowy. URLSite = http://pl.openoffice.org/ -Size = 147.1MB -URLDownload = http://ftp.tu-chemnitz.de/pub/openoffice/localized/pl/3.1.1/OOo_3.1.1_Win32Intel_install_pl.exe +Size = 133.2MB +URLDownload = http://ftp.tu-chemnitz.de/pub/openoffice/localized/pl/3.2.0/OOo_3.2.0_Win32Intel_install_pl.exe diff --git a/reactos/base/applications/rapps/rapps/scite.txt b/reactos/base/applications/rapps/rapps/scite.txt index 5e2562dacbe..fc3d9d50cca 100644 --- a/reactos/base/applications/rapps/rapps/scite.txt +++ b/reactos/base/applications/rapps/rapps/scite.txt @@ -2,13 +2,13 @@ [Section] Name = SciTE -Version = 2.02 +Version = 2.03 Licence = Freeware Description = SciTE is a SCIntilla based Text Editor. Originally built to demonstrate Scintilla, it has grown to be a generally useful editor with facilities for building and running programs. Size = 0.6M Category = 7 URLSite = http://www.scintilla.org/ -URLDownload = http://ovh.dl.sourceforge.net/sourceforge/scintilla/Sc202.exe +URLDownload = http://ovh.dl.sourceforge.net/sourceforge/scintilla/Sc203.exe CDPath = none [Section.0407] From 174145f20c8b682eceb1e8e5f7cf715941b13fc4 Mon Sep 17 00:00:00 2001 From: Eric Kohl Date: Tue, 16 Mar 2010 23:10:03 +0000 Subject: [PATCH 48/61] [ADVAPI32] - Create a service status handle when a service starts and destroy it after it has been stopped. svn path=/trunk/; revision=46233 --- reactos/dll/win32/advapi32/service/scm.c | 55 ------------- reactos/dll/win32/advapi32/service/sctrl.c | 90 +++++++++++++++++++++- 2 files changed, 88 insertions(+), 57 deletions(-) diff --git a/reactos/dll/win32/advapi32/service/scm.c b/reactos/dll/win32/advapi32/service/scm.c index e10e7f1fb4c..c3a05da4bf9 100644 --- a/reactos/dll/win32/advapi32/service/scm.c +++ b/reactos/dll/win32/advapi32/service/scm.c @@ -131,61 +131,6 @@ SVCCTL_HANDLEW_unbind(SVCCTL_HANDLEW szMachineName, } -handle_t __RPC_USER -RPC_SERVICE_STATUS_HANDLE_bind(RPC_SERVICE_STATUS_HANDLE hServiceStatus) -{ - handle_t hBinding = NULL; - LPWSTR pszStringBinding; - RPC_STATUS status; - - TRACE("RPC_SERVICE_STATUS_HANDLE_bind() called\n"); - - status = RpcStringBindingComposeW(NULL, - L"ncacn_np", - NULL, - L"\\pipe\\ntsvcs", - NULL, - &pszStringBinding); - if (status != RPC_S_OK) - { - ERR("RpcStringBindingCompose returned 0x%x\n", status); - return NULL; - } - - /* Set the binding handle that will be used to bind to the server. */ - status = RpcBindingFromStringBindingW(pszStringBinding, - &hBinding); - if (status != RPC_S_OK) - { - ERR("RpcBindingFromStringBinding returned 0x%x\n", status); - } - - status = RpcStringFreeW(&pszStringBinding); - if (status != RPC_S_OK) - { - ERR("RpcStringFree returned 0x%x\n", status); - } - - return hBinding; -} - - -void __RPC_USER -RPC_SERVICE_STATUS_HANDLE_unbind(RPC_SERVICE_STATUS_HANDLE hServiceStatus, - handle_t hBinding) -{ - RPC_STATUS status; - - TRACE("RPC_SERVICE_STATUS_HANDLE_unbind() called\n"); - - status = RpcBindingFree(&hBinding); - if (status != RPC_S_OK) - { - ERR("RpcBindingFree returned 0x%x\n", status); - } -} - - DWORD ScmRpcStatusToWinError(RPC_STATUS Status) { diff --git a/reactos/dll/win32/advapi32/service/sctrl.c b/reactos/dll/win32/advapi32/service/sctrl.c index ca6f1648fe0..90810bcca3c 100644 --- a/reactos/dll/win32/advapi32/service/sctrl.c +++ b/reactos/dll/win32/advapi32/service/sctrl.c @@ -41,10 +41,87 @@ typedef struct _ACTIVE_SERVICE static DWORD dwActiveServiceCount = 0; static PACTIVE_SERVICE lpActiveServices = NULL; +static handle_t hStatusBinding = NULL; /* FUNCTIONS *****************************************************************/ +handle_t __RPC_USER +RPC_SERVICE_STATUS_HANDLE_bind(RPC_SERVICE_STATUS_HANDLE hServiceStatus) +{ + return hStatusBinding; +} + + +void __RPC_USER +RPC_SERVICE_STATUS_HANDLE_unbind(RPC_SERVICE_STATUS_HANDLE hServiceStatus, + handle_t hBinding) +{ +} + + +static RPC_STATUS +ScCreateStatusBinding(VOID) +{ + LPWSTR pszStringBinding; + RPC_STATUS status; + + TRACE("ScCreateStatusBinding() called\n"); + + status = RpcStringBindingComposeW(NULL, + L"ncacn_np", + NULL, + L"\\pipe\\ntsvcs", + NULL, + &pszStringBinding); + if (status != RPC_S_OK) + { + ERR("RpcStringBindingCompose returned 0x%x\n", status); + return status; + } + + /* Set the binding handle that will be used to bind to the server. */ + status = RpcBindingFromStringBindingW(pszStringBinding, + &hStatusBinding); + if (status != RPC_S_OK) + { + ERR("RpcBindingFromStringBinding returned 0x%x\n", status); + } + + status = RpcStringFreeW(&pszStringBinding); + if (status != RPC_S_OK) + { + ERR("RpcStringFree returned 0x%x\n", status); + } + + return status; +} + + +static RPC_STATUS +ScDestroyStatusBinding(VOID) +{ + RPC_STATUS status; + + TRACE("ScDestroyStatusBinding() called\n"); + + if (hStatusBinding == NULL) + return RPC_S_OK; + + status = RpcBindingFree(&hStatusBinding); + if (status != RPC_S_OK) + { + ERR("RpcBindingFree returned 0x%x\n", status); + } + else + { + hStatusBinding = NULL; + } + + return status; +} + + static PACTIVE_SERVICE ScLookupServiceByServiceName(LPCWSTR lpServiceName) { @@ -259,7 +336,6 @@ ScConnectControlPipe(HANDLE *hPipe) TRACE("Sent Process ID %lu\n", dwProcessId); - return ERROR_SUCCESS; } @@ -403,7 +479,7 @@ ScServiceDispatcher(HANDLE hPipe, } else { - dwError = ERROR_NOT_FOUND; + dwError = ERROR_SERVICE_DOES_NOT_EXIST; } ReplyPacket.dwError = dwError; @@ -747,7 +823,12 @@ StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA * lpServiceStartTable) return FALSE; } + ScCreateStatusBinding(); + ScServiceDispatcher(hPipe, lpMessageBuffer, 256); + + ScDestroyStatusBinding(); + CloseHandle(hPipe); /* Free the message buffer */ @@ -837,7 +918,12 @@ StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW * lpServiceStartTable) return FALSE; } + ScCreateStatusBinding(); + ScServiceDispatcher(hPipe, lpMessageBuffer, 256); + + ScDestroyStatusBinding(); + CloseHandle(hPipe); /* Free the message buffer */ From 85b127e4c1296edddc5ff27734c114026ddb1419 Mon Sep 17 00:00:00 2001 From: Christoph von Wittich Date: Wed, 17 Mar 2010 00:11:31 +0000 Subject: [PATCH 49/61] [USER32] reduce diff to wine svn path=/trunk/; revision=46236 --- reactos/dll/win32/user32/windows/menu.c | 1263 +++++++++++------------ 1 file changed, 596 insertions(+), 667 deletions(-) diff --git a/reactos/dll/win32/user32/windows/menu.c b/reactos/dll/win32/user32/windows/menu.c index badf2d923c1..c90dbd6fbcc 100644 --- a/reactos/dll/win32/user32/windows/menu.c +++ b/reactos/dll/win32/user32/windows/menu.c @@ -57,7 +57,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(menu); /* Use global popup window because there's no way 2 menus can * be tracked at the same time. */ -static HWND TopPopup; +static HWND top_popup; /* Flag set by EndMenu() to force an exit from menu tracking */ static BOOL fEndMenu = FALSE; @@ -349,6 +349,49 @@ MenuDrawPopupGlyph(HDC dc, LPRECT r, INT_PTR popupMagic, BOOL inactive, BOOL hil DeleteObject(hFont); } +/*********************************************************************** + * MenuFindSubMenu + * + * Find a Sub menu. Return the position of the submenu, and modifies + * *hmenu in case it is found in another sub-menu. + * If the submenu cannot be found, NO_SELECTED_ITEM is returned. + */ +static UINT FASTCALL MenuFindSubMenu(HMENU *hmenu, HMENU hSubTarget ) +{ + ROSMENUINFO menu; + UINT i; + ROSMENUITEMINFO item; + + if (((*hmenu)==(HMENU)0xffff) || + (!MenuGetRosMenuInfo(&menu, *hmenu))) + return NO_SELECTED_ITEM; + + MenuInitRosMenuItemInfo(&item); + for (i = 0; i < menu.MenuItemCount; i++) + { + if (! MenuGetRosMenuItemInfo(menu.Self, i, &item)) + { + MenuCleanupRosMenuItemInfo(&item); + return NO_SELECTED_ITEM; + } + if (!(item.fType & MF_POPUP)) continue; + if (item.hSubMenu == hSubTarget) { + MenuCleanupRosMenuItemInfo(&item); + return i; + } + else { + HMENU hsubmenu = item.hSubMenu; + UINT pos = MenuFindSubMenu(&hsubmenu, hSubTarget ); + if (pos != NO_SELECTED_ITEM) { + *hmenu = hsubmenu; + return pos; + } + } + } + MenuCleanupRosMenuItemInfo(&item); + return NO_SELECTED_ITEM; +} + /*********************************************************************** * MenuFindItemByKey * @@ -1482,8 +1525,8 @@ static BOOL FASTCALL MenuShowPopup(HWND hwndOwner, HMENU hmenu, UINT id, UINT fl hwndOwner, 0, (HINSTANCE) GetWindowLongPtrW(hwndOwner, GWLP_HINSTANCE), (LPVOID) MenuInfo.Self); if ( !MenuInfo.Wnd || ! MenuSetRosMenuInfo(&MenuInfo)) return FALSE; - if (!TopPopup) { - TopPopup = MenuInfo.Wnd; + if (!top_popup) { + top_popup = MenuInfo.Wnd; } /* Display the window */ @@ -1494,8 +1537,156 @@ static BOOL FASTCALL MenuShowPopup(HWND hwndOwner, HMENU hmenu, UINT id, UINT fl return TRUE; } -LRESULT WINAPI -PopupMenuWndProcA(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam) +/*********************************************************************** + * MenuSelectItem + */ +static void FASTCALL MenuSelectItem(HWND hwndOwner, PROSMENUINFO hmenu, UINT wIndex, + BOOL sendMenuSelect, HMENU topmenu) +{ + ROSMENUITEMINFO ItemInfo; + ROSMENUINFO TopMenuInfo; + HDC hdc; + + TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner, hmenu, wIndex, sendMenuSelect); + + if (!hmenu || !hmenu->MenuItemCount || !hmenu->Wnd) return; + if (hmenu->FocusedItem == wIndex) return; + if (hmenu->Flags & MF_POPUP) hdc = GetDC(hmenu->Wnd); + else hdc = GetDCEx(hmenu->Wnd, 0, DCX_CACHE | DCX_WINDOW); + if (!top_popup) { + top_popup = hmenu->Wnd; + } + + SelectObject( hdc, hMenuFont ); + + MenuInitRosMenuItemInfo(&ItemInfo); + + /* Clear previous highlighted item */ + if (hmenu->FocusedItem != NO_SELECTED_ITEM) + { + if (MenuGetRosMenuItemInfo(hmenu->Self, hmenu->FocusedItem, &ItemInfo)) + { + ItemInfo.fMask |= MIIM_STATE; + ItemInfo.fState &= ~(MF_HILITE|MF_MOUSESELECT); + MenuSetRosMenuItemInfo(hmenu->Self, hmenu->FocusedItem, &ItemInfo); + } + MenuDrawMenuItem(hmenu->Wnd, hmenu, hwndOwner, hdc, &ItemInfo, + hmenu->Height, ! (hmenu->Flags & MF_POPUP), + ODA_SELECT); + } + + /* Highlight new item (if any) */ + hmenu->FocusedItem = wIndex; + MenuSetRosMenuInfo(hmenu); + if (hmenu->FocusedItem != NO_SELECTED_ITEM) + { + if (MenuGetRosMenuItemInfo(hmenu->Self, hmenu->FocusedItem, &ItemInfo)) + { + if (!(ItemInfo.fType & MF_SEPARATOR)) + { + ItemInfo.fMask |= MIIM_STATE; + ItemInfo.fState |= MF_HILITE; + MenuSetRosMenuItemInfo(hmenu->Self, hmenu->FocusedItem, &ItemInfo); + MenuDrawMenuItem(hmenu->Wnd, hmenu, hwndOwner, hdc, + &ItemInfo, hmenu->Height, ! (hmenu->Flags & MF_POPUP), + ODA_SELECT); + } + if (sendMenuSelect) + { + SendMessageW(hwndOwner, WM_MENUSELECT, + MAKELONG(ItemInfo.fType & MF_POPUP ? wIndex : ItemInfo.wID, + ItemInfo.fType | ItemInfo.fState | MF_MOUSESELECT | + (hmenu->Flags & MF_SYSMENU)), (LPARAM) hmenu->Self); + } + } + } + else if (sendMenuSelect) { + if(topmenu) { + int pos; + pos = MenuFindSubMenu(&topmenu, hmenu->Self); + if (pos != NO_SELECTED_ITEM) + { + if (MenuGetRosMenuInfo(&TopMenuInfo, topmenu) + && MenuGetRosMenuItemInfo(topmenu, pos, &ItemInfo)) + { + SendMessageW(hwndOwner, WM_MENUSELECT, + MAKELONG(Pos, ItemInfo.fType | ItemInfo.fState + | MF_MOUSESELECT + | (TopMenuInfo.Flags & MF_SYSMENU)), + (LPARAM) topmenu); + } + } + } + } + MenuCleanupRosMenuItemInfo(&ItemInfo); + ReleaseDC(hmenu->Wnd, hdc); +} + +/*********************************************************************** + * MenuMoveSelection + * + * Moves currently selected item according to the Offset parameter. + * If there is no selection then it should select the last item if + * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT. + */ +static void FASTCALL +MenuMoveSelection(HWND WndOwner, PROSMENUINFO MenuInfo, INT Offset) +{ + INT i; + ROSMENUITEMINFO ItemInfo; + INT OrigPos; + + TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner, MenuInfo, Offset); + + /* Prevent looping */ + if (0 == MenuInfo->MenuItemCount || 0 == Offset) + return; + else if (Offset < -1) + Offset = -1; + else if (Offset > 1) + Offset = 1; + + MenuInitRosMenuItemInfo(&ItemInfo); + + OrigPos = MenuInfo->FocusedItem; + if (OrigPos == NO_SELECTED_ITEM) /* NO_SELECTED_ITEM is not -1 ! */ + { + OrigPos = 0; + i = -1; + } + else + { + i = MenuInfo->FocusedItem; + } + + do + { + /* Step */ + i += Offset; + /* Clip and wrap around */ + if (i < 0) + { + i = MenuInfo->MenuItemCount - 1; + } + else if (i >= MenuInfo->MenuItemCount) + { + i = 0; + } + /* If this is a good candidate; */ + if (MenuGetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo) && + 0 == (ItemInfo.fType & MF_SEPARATOR)) + { + MenuSelectItem(WndOwner, MenuInfo, i, TRUE, NULL); + MenuCleanupRosMenuItemInfo(&ItemInfo); + return; + } + } while (i != OrigPos); + + /* Not found */ + MenuCleanupRosMenuItemInfo(&ItemInfo); +} + +LRESULT WINAPI PopupMenuWndProcA(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam) { TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam); @@ -1532,9 +1723,9 @@ PopupMenuWndProcA(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam) case WM_DESTROY: /* zero out global pointer in case resident popup window was destroyed. */ - if (Wnd == TopPopup) + if (Wnd == top_popup) { - TopPopup = NULL; + top_popup = NULL; } break; @@ -1604,9 +1795,9 @@ PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam) case WM_DESTROY: /* zero out global pointer in case resident popup window was destroyed. */ - if (Wnd == TopPopup) + if (Wnd == top_popup) { - TopPopup = NULL; + top_popup = NULL; } break; @@ -1639,66 +1830,6 @@ PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam) return 0; } -/********************************************************************** - * MENUEX_ParseResource - * - * Parse an extended menu resource and add items to the menu. - * Return a pointer to the end of the resource. - * - * FIXME - should we be passing an LPCSTR to a predominantly UNICODE function? - */ -static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu) -{ - WORD resinfo; - - do - { - MENUITEMINFOW mii; - - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_STATE | MIIM_ID | MIIM_FTYPE; - mii.fType = GET_DWORD(res); - res += sizeof(DWORD); - mii.fState = GET_DWORD(res); - res += sizeof(DWORD); - mii.wID = GET_DWORD(res); - res += sizeof(DWORD); - resinfo = GET_WORD(res); - res += sizeof(WORD); - /* Align the text on a word boundary. */ - res += (~((int)res - 1)) & 1; - mii.dwTypeData = (LPWSTR) res; - res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR); - /* Align the following fields on a dword boundary. */ - res += (~((int)res - 1)) & 3; - - if (resinfo & 1) /* Pop-up? */ - { - /* DWORD helpid = GET_DWORD(res); FIXME: use this. */ - res += sizeof(DWORD); - mii.hSubMenu = CreatePopupMenu(); - if (!mii.hSubMenu) - return NULL; - if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) - { - DestroyMenu(mii.hSubMenu); - return NULL; - } - mii.fMask |= MIIM_SUBMENU; - mii.fType |= MF_POPUP; - mii.wID = (UINT) mii.hSubMenu; - } - else if(!*mii.dwTypeData && !(mii.fType & MF_SEPARATOR)) - { - mii.fType |= MF_SEPARATOR; - } - InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii); - } - while (!(resinfo & MF_END)); - return res; -} - - /********************************************************************** * MENU_ParseResource * @@ -1709,72 +1840,126 @@ static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu) */ static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode ) { - WORD flags, id = 0; - HMENU hSubMenu; - LPCSTR str; - BOOL end = FALSE; + WORD flags, id = 0; + HMENU hSubMenu; + LPCSTR str; + BOOL end = FALSE; - do - { - flags = GET_WORD(res); - - /* remove MF_END flag before passing it to AppendMenu()! */ - end = (flags & MF_END); - if(end) flags ^= MF_END; - - res += sizeof(WORD); - if(!(flags & MF_POPUP)) + do { - id = GET_WORD(res); - res += sizeof(WORD); - } - str = res; - if(!unicode) - res += strlen(str) + 1; - else - res += (strlenW((LPCWSTR)str) + 1) * sizeof(WCHAR); - if (flags & MF_POPUP) - { - hSubMenu = CreatePopupMenu(); - if(!hSubMenu) return NULL; - if(!(res = MENU_ParseResource(res, hSubMenu, unicode))) - return NULL; - if(!unicode) - AppendMenuA(hMenu, flags, (UINT)hSubMenu, str); - else - AppendMenuW(hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str); - } - else /* Not a popup */ - { - if(!unicode) - { - if (*str == 0) - flags = MF_SEPARATOR; - } - else - { - if (*(LPCWSTR)str == 0) - flags = MF_SEPARATOR; - } + flags = GET_WORD(res); - if (flags & MF_SEPARATOR) - { - if (!(flags & (MF_GRAYED | MF_DISABLED))) - flags |= MF_GRAYED | MF_DISABLED; - } + /* remove MF_END flag before passing it to AppendMenu()! */ + end = (flags & MF_END); + if(end) flags ^= MF_END; - if(!unicode) - AppendMenuA(hMenu, flags, id, *str ? str : NULL); - else - AppendMenuW(hMenu, flags, id, + res += sizeof(WORD); + if(!(flags & MF_POPUP)) + { + id = GET_WORD(res); + res += sizeof(WORD); + } + str = res; + if(!unicode) + res += strlen(str) + 1; + else + res += (strlenW((LPCWSTR)str) + 1) * sizeof(WCHAR); + if (flags & MF_POPUP) + { + hSubMenu = CreatePopupMenu(); + if(!hSubMenu) return NULL; + if(!(res = MENU_ParseResource(res, hSubMenu, unicode))) + return NULL; + if(!unicode) + AppendMenuA(hMenu, flags, (UINT)hSubMenu, str); + else + AppendMenuW(hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str); + } + else /* Not a popup */ + { + if(!unicode) + { + if (*str == 0) + flags = MF_SEPARATOR; + } + else + { + if (*(LPCWSTR)str == 0) + flags = MF_SEPARATOR; + } + + if (flags & MF_SEPARATOR) + { + if (!(flags & (MF_GRAYED | MF_DISABLED))) + flags |= MF_GRAYED | MF_DISABLED; + } + + if(!unicode) + AppendMenuA(hMenu, flags, id, *str ? str : NULL); + else + AppendMenuW(hMenu, flags, id, *(LPCWSTR)str ? (LPCWSTR)str : NULL); - } - } while(!end); - - return res; + } + } while(!end); + return res; } +/********************************************************************** + * MENUEX_ParseResource + * + * Parse an extended menu resource and add items to the menu. + * Return a pointer to the end of the resource. + */ +static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu) +{ + WORD resinfo; + do { + MENUITEMINFOW mii; + + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_STATE | MIIM_ID | MIIM_FTYPE; + mii.fType = GET_DWORD(res); + res += sizeof(DWORD); + mii.fState = GET_DWORD(res); + res += sizeof(DWORD); + mii.wID = GET_DWORD(res); + res += sizeof(DWORD); + resinfo = GET_WORD(res); + res += sizeof(WORD); + /* Align the text on a word boundary. */ + res += (~((UINT_PTR)res - 1)) & 1; + mii.dwTypeData = (LPWSTR) res; + res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR); + /* Align the following fields on a dword boundary. */ + res += (~((UINT_PTR)res - 1)) & 3; + + TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n", + mii.fType, mii.fState, mii.wID, resinfo, mii.dwTypeData); + + if (resinfo & 1) { /* Pop-up? */ + /* DWORD helpid = GET_DWORD(res); FIXME: use this. */ + res += sizeof(DWORD); + mii.hSubMenu = CreatePopupMenu(); + if (!mii.hSubMenu) + return NULL; + if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) { + DestroyMenu(mii.hSubMenu); + return NULL; + } + mii.fMask |= MIIM_SUBMENU; + mii.fType |= MF_POPUP; + mii.wID = (UINT) mii.hSubMenu; + } + else if(!*mii.dwTypeData && !(mii.fType & MF_SEPARATOR)) + { + mii.fType |= MF_SEPARATOR; + } + InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii); + } while (!(resinfo & MF_END)); + return res; +} + NTSTATUS WINAPI User32LoadSysMenuTemplateForKernel(PVOID Arguments, ULONG ArgumentLength) { @@ -1935,272 +2120,6 @@ DrawMenuBarTemp(HWND Wnd, HDC DC, LPRECT Rect, HMENU Menu, HFONT Font) return MenuInfo.Height; } -/*********************************************************************** - * MenuInitTracking - */ -static BOOL FASTCALL -MenuInitTracking(HWND Wnd, HMENU Menu, BOOL Popup, UINT Flags) -{ - TRACE("Wnd=%p Menu=%p\n", Wnd, Menu); - - HideCaret(0); - - /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */ - if (0 == (Flags & TPM_NONOTIFY)) - { - SendMessageW(Wnd, WM_ENTERMENULOOP, Popup, 0); - } - - SendMessageW(Wnd, WM_SETCURSOR, (WPARAM) Wnd, HTCAPTION); - - if (0 == (Flags & TPM_NONOTIFY)) - { - ROSMENUINFO MenuInfo; - - SendMessageW(Wnd, WM_INITMENU, (WPARAM)Menu, 0); - - MenuGetRosMenuInfo(&MenuInfo, Menu); - - if (0 == MenuInfo.Height) - { - /* app changed/recreated menu bar entries in WM_INITMENU - Recalculate menu sizes else clicks will not work */ - SetWindowPos(Wnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | - SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED ); - - } - /* This makes the menus of applications built with Delphi work. - * It also enables menus to be displayed in more than one window, - * but there are some bugs left that need to be fixed in this case. - */ - if(MenuInfo.Self == Menu) - { - MenuInfo.Wnd = Wnd; - MenuSetRosMenuInfo(&MenuInfo); - } - } - - return TRUE; -} - -/*********************************************************************** - * MenuFindSubMenu - * - * Find a Sub menu. Return the position of the submenu, and modifies - * *hmenu in case it is found in another sub-menu. - * If the submenu cannot be found, NO_SELECTED_ITEM is returned. - */ -static UINT FASTCALL -MenuFindSubMenu(HMENU *Menu, HMENU SubTarget) -{ - ROSMENUINFO MenuInfo; - ROSMENUITEMINFO ItemInfo; - UINT i; - HMENU SubMenu; - UINT Pos; - - if ((HMENU) 0xffff == *Menu - || ! MenuGetRosMenuInfo(&MenuInfo, *Menu)) - { - return NO_SELECTED_ITEM; - } - - MenuInitRosMenuItemInfo(&ItemInfo); - for (i = 0; i < MenuInfo.MenuItemCount; i++) - { - if (! MenuGetRosMenuItemInfo(MenuInfo.Self, i, &ItemInfo)) - { - MenuCleanupRosMenuItemInfo(&ItemInfo); - return NO_SELECTED_ITEM; - } - if (0 == (ItemInfo.fType & MF_POPUP)) - { - continue; - } - if (ItemInfo.hSubMenu == SubTarget) - { - MenuCleanupRosMenuItemInfo(&ItemInfo); - return i; - } - SubMenu = ItemInfo.hSubMenu; - Pos = MenuFindSubMenu(&SubMenu, SubTarget); - if (NO_SELECTED_ITEM != Pos) - { - *Menu = SubMenu; - return Pos; - } - } - MenuCleanupRosMenuItemInfo(&ItemInfo); - - return NO_SELECTED_ITEM; -} - -/*********************************************************************** - * MenuSelectItem - */ -static void FASTCALL -MenuSelectItem(HWND WndOwner, PROSMENUINFO MenuInfo, UINT Index, - BOOL SendMenuSelect, HMENU TopMenu) -{ - HDC Dc; - ROSMENUITEMINFO ItemInfo; - ROSMENUINFO TopMenuInfo; - int Pos; - - TRACE("owner=%x menu=%p index=0x%04x select=0x%04x\n", WndOwner, MenuInfo, Index, SendMenuSelect); - - if (NULL == MenuInfo || 0 == MenuInfo->MenuItemCount || NULL == MenuInfo->Wnd) - { - return; - } - - if (MenuInfo->FocusedItem == Index) - { - return; - } - - if (0 != (MenuInfo->Flags & MF_POPUP)) - { - Dc = GetDC(MenuInfo->Wnd); - } - else - { - Dc = GetDCEx(MenuInfo->Wnd, 0, DCX_CACHE | DCX_WINDOW); - } - - if (NULL == TopPopup) - { - TopPopup = MenuInfo->Wnd; - } - - SelectObject(Dc, hMenuFont); - MenuInitRosMenuItemInfo(&ItemInfo); - /* Clear previous highlighted item */ - if (NO_SELECTED_ITEM != MenuInfo->FocusedItem) - { - if (MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo)) - { - ItemInfo.fMask |= MIIM_STATE; - ItemInfo.fState &= ~(MF_HILITE|MF_MOUSESELECT); - MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo); - } - MenuDrawMenuItem(MenuInfo->Wnd, MenuInfo, WndOwner, Dc, &ItemInfo, - MenuInfo->Height, ! (MenuInfo->Flags & MF_POPUP), - ODA_SELECT); - } - - /* Highlight new item (if any) */ - MenuInfo->FocusedItem = Index; - MenuSetRosMenuInfo(MenuInfo); - if (NO_SELECTED_ITEM != MenuInfo->FocusedItem) - { - if (MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo)) - { - if (0 == (ItemInfo.fType & MF_SEPARATOR)) - { - ItemInfo.fMask |= MIIM_STATE; - ItemInfo.fState |= MF_HILITE; - MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo); - MenuDrawMenuItem(MenuInfo->Wnd, MenuInfo, WndOwner, Dc, - &ItemInfo, MenuInfo->Height, ! (MenuInfo->Flags & MF_POPUP), - ODA_SELECT); - } - if (SendMenuSelect) - { - SendMessageW(WndOwner, WM_MENUSELECT, - MAKELONG(ItemInfo.fType & MF_POPUP ? Index : ItemInfo.wID, - ItemInfo.fType | ItemInfo.fState | MF_MOUSESELECT | - (MenuInfo->Flags & MF_SYSMENU)), (LPARAM) MenuInfo->Self); - } - } - } - else if (SendMenuSelect) - { - if (NULL != TopMenu) - { - Pos = MenuFindSubMenu(&TopMenu, MenuInfo->Self); - if (NO_SELECTED_ITEM != Pos) - { - if (MenuGetRosMenuInfo(&TopMenuInfo, TopMenu) - && MenuGetRosMenuItemInfo(TopMenu, Pos, &ItemInfo)) - { - SendMessageW(WndOwner, WM_MENUSELECT, - MAKELONG(Pos, ItemInfo.fType | ItemInfo.fState - | MF_MOUSESELECT - | (TopMenuInfo.Flags & MF_SYSMENU)), - (LPARAM) TopMenu); - } - } - } - } - MenuCleanupRosMenuItemInfo(&ItemInfo); - ReleaseDC(MenuInfo->Wnd, Dc); -} - -/*********************************************************************** - * MenuMoveSelection - * - * Moves currently selected item according to the Offset parameter. - * If there is no selection then it should select the last item if - * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT. - */ -static void FASTCALL -MenuMoveSelection(HWND WndOwner, PROSMENUINFO MenuInfo, INT Offset) -{ - INT i; - ROSMENUITEMINFO ItemInfo; - INT OrigPos; - - TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner, MenuInfo, Offset); - - /* Prevent looping */ - if (0 == MenuInfo->MenuItemCount || 0 == Offset) - return; - else if (Offset < -1) - Offset = -1; - else if (Offset > 1) - Offset = 1; - - MenuInitRosMenuItemInfo(&ItemInfo); - - OrigPos = MenuInfo->FocusedItem; - if (OrigPos == NO_SELECTED_ITEM) /* NO_SELECTED_ITEM is not -1 ! */ - { - OrigPos = 0; - i = -1; - } - else - { - i = MenuInfo->FocusedItem; - } - - do - { - /* Step */ - i += Offset; - /* Clip and wrap around */ - if (i < 0) - { - i = MenuInfo->MenuItemCount - 1; - } - else if (i >= MenuInfo->MenuItemCount) - { - i = 0; - } - /* If this is a good candidate; */ - if (MenuGetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo) && - 0 == (ItemInfo.fType & MF_SEPARATOR)) - { - MenuSelectItem(WndOwner, MenuInfo, i, TRUE, NULL); - MenuCleanupRosMenuItemInfo(&ItemInfo); - return; - } - } while (i != OrigPos); - - /* Not found */ - MenuCleanupRosMenuItemInfo(&ItemInfo); -} - /*********************************************************************** * MenuInitSysMenuPopup * @@ -2400,7 +2319,7 @@ MenuHideSubPopups(HWND WndOwner, PROSMENUINFO MenuInfo, BOOL SendMenuSelect) TRACE("owner=%x menu=%x 0x%04x\n", WndOwner, MenuInfo, SendMenuSelect); - if (NULL != MenuInfo && NULL != TopPopup && NO_SELECTED_ITEM != MenuInfo->FocusedItem) + if (NULL != MenuInfo && NULL != top_popup && NO_SELECTED_ITEM != MenuInfo->FocusedItem) { MenuInitRosMenuItemInfo(&ItemInfo); ItemInfo.fMask |= MIIM_FTYPE | MIIM_STATE; @@ -3150,36 +3069,29 @@ MenuKeyLeft(MTRACKER* Mt, UINT Flags) * * Handle a VK_RIGHT key event in a menu. */ -static void FASTCALL -MenuKeyRight(MTRACKER *Mt, UINT Flags) +static void FASTCALL MenuKeyRight(MTRACKER *Mt, UINT Flags) { - HMENU MenuTmp; - ROSMENUINFO MenuInfo; - ROSMENUINFO CurrentMenuInfo; - UINT NextCol; + HMENU hmenutmp; + ROSMENUINFO MenuInfo; + ROSMENUINFO CurrentMenuInfo; + UINT NextCol; - TRACE("MenuKeyRight called, cur %p, top %p.\n", + TRACE("MenuKeyRight called, cur %p, top %p.\n", Mt->CurrentMenu, Mt->TopMenu); - if (! MenuGetRosMenuInfo(&MenuInfo, Mt->TopMenu)) - { - return; - } - if (0 != (MenuInfo.Flags & MF_POPUP) || (Mt->CurrentMenu != Mt->TopMenu)) + if (! MenuGetRosMenuInfo(&MenuInfo, Mt->TopMenu)) return; + if ((MenuInfo.Flags & MF_POPUP) || (Mt->CurrentMenu != Mt->TopMenu)) { /* If already displaying a popup, try to display sub-popup */ - MenuTmp = Mt->CurrentMenu; + hmenutmp = Mt->CurrentMenu; if (MenuGetRosMenuInfo(&CurrentMenuInfo, Mt->CurrentMenu)) { Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, &CurrentMenuInfo, TRUE, Flags); } /* if subpopup was displayed then we are done */ - if (MenuTmp != Mt->CurrentMenu) - { - return; - } + if (hmenutmp != Mt->CurrentMenu) return; } if (! MenuGetRosMenuInfo(&CurrentMenuInfo, Mt->CurrentMenu)) @@ -3203,20 +3115,18 @@ MenuKeyRight(MTRACKER *Mt, UINT Flags) if (Mt->CurrentMenu != Mt->TopMenu) { MenuHideSubPopups(Mt->OwnerWnd, &MenuInfo, FALSE ); - MenuTmp = Mt->CurrentMenu = Mt->TopMenu; + hmenutmp = Mt->CurrentMenu = Mt->TopMenu; } else { - MenuTmp = NULL; + hmenutmp = NULL; } /* try to move to the next item */ - if (! MenuDoNextMenu(Mt, VK_RIGHT)) - { + if ( !MenuDoNextMenu(Mt, VK_RIGHT)) MenuMoveSelection(Mt->OwnerWnd, &MenuInfo, ITEM_NEXT); - } - if (NULL != MenuTmp || 0 != (Mt->TrackFlags & TF_SUSPENDPOPUP)) + if ( hmenutmp || Mt->TrackFlags & TF_SUSPENDPOPUP ) { if (! MenuSuspendPopup(Mt, WM_KEYDOWN) && MenuGetRosMenuInfo(&MenuInfo, Mt->TopMenu)) @@ -3233,220 +3143,211 @@ MenuKeyRight(MTRACKER *Mt, UINT Flags) * * Menu tracking code. */ -static INT FASTCALL -MenuTrackMenu(HMENU Menu, UINT Flags, INT x, INT y, - HWND Wnd, const RECT *Rect ) +static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, + HWND hwnd, const RECT *lprect ) { - MSG Msg; - ROSMENUINFO MenuInfo; - ROSMENUITEMINFO ItemInfo; - BOOL fRemove; - INT ExecutedMenuId = -1; - MTRACKER Mt; - BOOL EnterIdleSent = FALSE; + MSG msg; + ROSMENUINFO MenuInfo; + ROSMENUITEMINFO ItemInfo; + BOOL fRemove; + INT executedMenuId = -1; + MTRACKER mt; + BOOL enterIdleSent = FALSE; - Mt.TrackFlags = 0; - Mt.CurrentMenu = Menu; - Mt.TopMenu = Menu; - Mt.OwnerWnd = Wnd; - Mt.Pt.x = x; - Mt.Pt.y = y; + mt.TrackFlags = 0; + mt.CurrentMenu = hmenu; + mt.TopMenu = hmenu; + mt.OwnerWnd = hwnd; + mt.Pt.x = x; + mt.Pt.y = y; - TRACE("Menu=%x Flags=0x%08x (%d,%d) Wnd=%x (%ld,%ld)-(%ld,%ld)\n", - Menu, Flags, x, y, Wnd, Rect ? Rect->left : 0, Rect ? Rect->top : 0, - Rect ? Rect->right : 0, Rect ? Rect->bottom : 0); + TRACE("hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n", + hmenu, wFlags, x, y, hwnd, lprect ? lprect->left : 0, lprect ? lprect->top : 0, + lprect ? lprect->right : 0, lprect ? lprect->bottom : 0); - if (!IsMenu(Menu)) - { - SetLastError( ERROR_INVALID_MENU_HANDLE ); - return FALSE; - } - - fEndMenu = FALSE; - if (! MenuGetRosMenuInfo(&MenuInfo, Menu)) + if (!IsMenu(hmenu)) { - return FALSE; + SetLastError( ERROR_INVALID_MENU_HANDLE ); + return FALSE; } - if (0 != (Flags & TPM_BUTTONDOWN)) + fEndMenu = FALSE; + if (! MenuGetRosMenuInfo(&MenuInfo, hmenu)) { - /* Get the result in order to start the tracking or not */ - fRemove = MenuButtonDown(&Mt, Menu, Flags); - fEndMenu = ! fRemove; + return FALSE; } - SetCapture(Mt.OwnerWnd); - (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER, Mt.OwnerWnd); - - ERR("MenuTrackMenu 1\n"); - while (! fEndMenu) + if (wFlags & TPM_BUTTONDOWN) { - PVOID menu = ValidateHandle(Mt.CurrentMenu, VALIDATE_TYPE_MENU); - if (!menu) /* sometimes happens if I do a window manager close */ - break; + /* Get the result in order to start the tracking or not */ + fRemove = MenuButtonDown( &mt, hmenu, wFlags ); + fEndMenu = !fRemove; + } - /* we have to keep the message in the queue until it's - * clear that menu loop is not over yet. */ + SetCapture(mt.OwnerWnd); + (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER, mt.OwnerWnd); - for (;;) + ERR("MenuTrackMenu 1\n"); + while (! fEndMenu) + { + PVOID menu = ValidateHandle(mt.CurrentMenu, VALIDATE_TYPE_MENU); + if (!menu) /* sometimes happens if I do a window manager close */ + break; + + /* we have to keep the message in the queue until it's + * clear that menu loop is not over yet. */ + + for (;;) { - if (PeekMessageW(&Msg, 0, 0, 0, PM_NOREMOVE)) + if (PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE )) { - if (! CallMsgFilterW(&Msg, MSGF_MENU)) - { - break; - } - /* remove the message from the queue */ - PeekMessageW(&Msg, 0, Msg.message, Msg.message, PM_REMOVE ); + if (!CallMsgFilterW( &msg, MSGF_MENU )) break; + /* remove the message from the queue */ + PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE ); } - else + else { - if (! EnterIdleSent) + if (!enterIdleSent) { - HWND Win = (0 != (Flags & TPM_ENTERIDLEEX) - && 0 != (MenuInfo.Flags & MF_POPUP)) ? MenuInfo.Wnd : NULL; - EnterIdleSent = TRUE; - SendMessageW(Mt.OwnerWnd, WM_ENTERIDLE, MSGF_MENU, (LPARAM) Win); + HWND win = (wFlags & TPM_ENTERIDLEEX) && (MenuInfo.Flags & MF_POPUP) ? MenuInfo.Wnd : NULL; + enterIdleSent = TRUE; + SendMessageW( mt.OwnerWnd, WM_ENTERIDLE, MSGF_MENU, (LPARAM) win); } - WaitMessage(); + WaitMessage(); } } - /* check if EndMenu() tried to cancel us, by posting this message */ - if (Msg.message == WM_CANCELMODE) + /* check if EndMenu() tried to cancel us, by posting this message */ + if (msg.message == WM_CANCELMODE) { - /* we are now out of the loop */ - fEndMenu = TRUE; + /* we are now out of the loop */ + fEndMenu = TRUE; - /* remove the message from the queue */ - PeekMessageW(&Msg, 0, Msg.message, Msg.message, PM_REMOVE); + /* remove the message from the queue */ + PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE ); - /* break out of internal loop, ala ESCAPE */ - break; + /* break out of internal loop, ala ESCAPE */ + break; } - TranslateMessage(&Msg); - Mt.Pt = Msg.pt; + TranslateMessage( &msg ); + mt.Pt = msg.pt; - if (Msg.hwnd == MenuInfo.Wnd || Msg.message != WM_TIMER) + if ( (msg.hwnd == MenuInfo.Wnd) || (msg.message!=WM_TIMER) ) + enterIdleSent=FALSE; + + fRemove = FALSE; + if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST)) { - EnterIdleSent = FALSE; - } + /* + * Use the mouse coordinates in lParam instead of those in the MSG + * struct to properly handle synthetic messages. They are already + * in screen coordinates. + */ + mt.Pt.x = (short)LOWORD(msg.lParam); + mt.Pt.y = (short)HIWORD(msg.lParam); - fRemove = FALSE; - if ((Msg.message >= WM_MOUSEFIRST) && (Msg.message <= WM_MOUSELAST)) - { - /* - * Use the mouse coordinates in lParam instead of those in the MSG - * struct to properly handle synthetic messages. They are already - * in screen coordinates. - */ - Mt.Pt.x = (short) LOWORD(Msg.lParam); - Mt.Pt.y = (short) HIWORD(Msg.lParam); + /* Find a menu for this mouse event */ + hmenu = MenuPtMenu(mt.TopMenu, mt.Pt); - /* Find a menu for this mouse event */ - Menu = MenuPtMenu(Mt.TopMenu, Mt.Pt); - - switch(Msg.message) + switch(msg.message) { - /* no WM_NC... messages in captured state */ + /* no WM_NC... messages in captured state */ - case WM_RBUTTONDBLCLK: - case WM_RBUTTONDOWN: - if (!(Flags & TPM_RIGHTBUTTON)) break; + case WM_RBUTTONDBLCLK: + case WM_RBUTTONDOWN: + if (!(wFlags & TPM_RIGHTBUTTON)) break; /* fall through */ - case WM_LBUTTONDBLCLK: - case WM_LBUTTONDOWN: + case WM_LBUTTONDBLCLK: + case WM_LBUTTONDOWN: /* If the message belongs to the menu, removes it from the queue */ /* Else, end menu tracking */ - fRemove = MenuButtonDown(&Mt, Menu, Flags); - fEndMenu = ! fRemove; + fRemove = MenuButtonDown(&mt, hmenu, wFlags); + fEndMenu = !fRemove; break; - case WM_RBUTTONUP: - if (0 == (Flags & TPM_RIGHTBUTTON)) break; + case WM_RBUTTONUP: + if (!(wFlags & TPM_RIGHTBUTTON)) break; /* fall through */ - case WM_LBUTTONUP: + case WM_LBUTTONUP: /* Check if a menu was selected by the mouse */ - if (Menu) - { - ExecutedMenuId = MenuButtonUp(&Mt, Menu, Flags); + if (hmenu) + { + executedMenuId = MenuButtonUp( &mt, hmenu, wFlags); - /* End the loop if ExecutedMenuId is an item ID */ - /* or if the job was done (ExecutedMenuId = 0). */ - fEndMenu = fRemove = (-1 != ExecutedMenuId); - } + /* End the loop if executedMenuId is an item ID */ + /* or if the job was done (executedMenuId = 0). */ + fEndMenu = fRemove = (executedMenuId != -1); + } else - { + { /* No menu was selected by the mouse */ /* if the function was called by TrackPopupMenu, continue with the menu tracking. If not, stop it */ - fEndMenu = (0 != (Flags & TPM_POPUPMENU) ? FALSE : TRUE); - } + fEndMenu = ((wFlags & TPM_POPUPMENU) ? FALSE : TRUE); + } break; - case WM_MOUSEMOVE: - if (Menu) - { - fEndMenu |= !MenuMouseMove(&Mt, Menu, Flags); - } + case WM_MOUSEMOVE: + if (hmenu) + fEndMenu |= !MenuMouseMove(&mt, hmenu, wFlags); break; - } /* switch(Msg.message) - mouse */ - } - else if ((Msg.message >= WM_KEYFIRST) && (Msg.message <= WM_KEYLAST)) + } /* switch(Msg.message) - mouse */ + } + else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST)) { fRemove = TRUE; /* Keyboard messages are always removed */ - switch(Msg.message) + switch(msg.message) { case WM_SYSKEYDOWN: case WM_KEYDOWN: - switch(Msg.wParam) + switch(msg.wParam) { case VK_MENU: fEndMenu = TRUE; break; case VK_HOME: case VK_END: - if (MenuGetRosMenuInfo(&MenuInfo, Mt.CurrentMenu)) + if (MenuGetRosMenuInfo(&MenuInfo, mt.CurrentMenu)) { - MenuSelectItem(Mt.OwnerWnd, &MenuInfo, NO_SELECTED_ITEM, + MenuSelectItem(mt.OwnerWnd, &MenuInfo, NO_SELECTED_ITEM, FALSE, 0 ); - MenuMoveSelection(Mt.OwnerWnd, &MenuInfo, - VK_HOME == Msg.wParam ? ITEM_NEXT : ITEM_PREV); + MenuMoveSelection(mt.OwnerWnd, &MenuInfo, + VK_HOME == msg.wParam ? ITEM_NEXT : ITEM_PREV); } break; case VK_UP: case VK_DOWN: /* If on menu bar, pull-down the menu */ - if (MenuGetRosMenuInfo(&MenuInfo, Mt.CurrentMenu)) + if (MenuGetRosMenuInfo(&MenuInfo, mt.CurrentMenu)) { - if (0 == (MenuInfo.Flags & MF_POPUP)) + if (!(MenuInfo.Flags & MF_POPUP)) { - if (MenuGetRosMenuInfo(&MenuInfo, Mt.TopMenu)) + if (MenuGetRosMenuInfo(&MenuInfo, mt.TopMenu)) { - Mt.CurrentMenu = MenuShowSubPopup(Mt.OwnerWnd, &MenuInfo, - TRUE, Flags); + mt.CurrentMenu = MenuShowSubPopup(mt.OwnerWnd, &MenuInfo, + TRUE, wFlags); } } else /* otherwise try to move selection */ { - MenuMoveSelection(Mt.OwnerWnd, &MenuInfo, - VK_DOWN == Msg.wParam ? ITEM_NEXT : ITEM_PREV); + MenuMoveSelection(mt.OwnerWnd, &MenuInfo, + VK_DOWN == msg.wParam ? ITEM_NEXT : ITEM_PREV); } } break; case VK_LEFT: - MenuKeyLeft(&Mt, Flags); + MenuKeyLeft(&mt, wFlags); break; case VK_RIGHT: - MenuKeyRight(&Mt, Flags); + MenuKeyRight(&mt, wFlags); break; case VK_ESCAPE: - fEndMenu = MenuKeyEscape(&Mt, Flags); + fEndMenu = MenuKeyEscape(&mt, wFlags); break; case VK_F1: @@ -3454,12 +3355,9 @@ MenuTrackMenu(HMENU Menu, UINT Flags, INT x, INT y, HELPINFO hi; hi.cbSize = sizeof(HELPINFO); hi.iContextType = HELPINFO_MENUITEM; - if (MenuGetRosMenuInfo(&MenuInfo, Mt.CurrentMenu)) + if (MenuGetRosMenuInfo(&MenuInfo, mt.CurrentMenu)) { - if (NO_SELECTED_ITEM == MenuInfo.FocusedItem) - { - hi.iCtrlId = 0; - } + if (MenuInfo.FocusedItem == NO_SELECTED_ITEM) hi.iCtrlId = 0; else { MenuInitRosMenuItemInfo(&ItemInfo); @@ -3476,10 +3374,10 @@ MenuTrackMenu(HMENU Menu, UINT Flags, INT x, INT y, MenuCleanupRosMenuItemInfo(&ItemInfo); } } - hi.hItemHandle = Menu; - hi.dwContextId = MenuInfo.dwContextHelpID; - hi.MousePos = Msg.pt; - SendMessageW(Wnd, WM_HELP, 0, (LPARAM) &hi); + hi.hItemHandle = hmenu; + hi.dwContextId = MenuInfo.dwContextHelpID; + hi.MousePos = msg.pt; + SendMessageW(hwnd, WM_HELP, 0, (LPARAM) &hi); break; } @@ -3488,187 +3386,218 @@ MenuTrackMenu(HMENU Menu, UINT Flags, INT x, INT y, } break; /* WM_KEYDOWN */ - case WM_CHAR: - case WM_SYSCHAR: + case WM_CHAR: + case WM_SYSCHAR: { - UINT Pos; + UINT pos; - if (! MenuGetRosMenuInfo(&MenuInfo, Mt.CurrentMenu)) + if (! MenuGetRosMenuInfo(&MenuInfo, mt.CurrentMenu)) break; + if (msg.wParam == L'\r' || msg.wParam == L' ') { - break; - } - if (L'\r' == Msg.wParam || L' ' == Msg.wParam) - { - ExecutedMenuId = MenuExecFocusedItem(&Mt, &MenuInfo, Flags); - fEndMenu = (ExecutedMenuId != -2); - break; + executedMenuId = MenuExecFocusedItem(&mt, &MenuInfo, wFlags); + fEndMenu = (executedMenuId != -2); + break; } - /* Hack to avoid control chars. */ - /* We will find a better way real soon... */ - if (Msg.wParam < 32) - { - break; - } + /* Hack to avoid control chars. */ + /* We will find a better way real soon... */ + if (msg.wParam < 32) break; - Pos = MenuFindItemByKey(Mt.OwnerWnd, &MenuInfo, - LOWORD(Msg.wParam), FALSE); - if ((UINT) -2 == Pos) + pos = MenuFindItemByKey(mt.OwnerWnd, &MenuInfo, + LOWORD(msg.wParam), FALSE); + if (pos == (UINT)-2) fEndMenu = TRUE; + else if (pos == (UINT)-1) MessageBeep(0); + else { - fEndMenu = TRUE; + MenuSelectItem(mt.OwnerWnd, &MenuInfo, pos, + TRUE, 0); + executedMenuId = MenuExecFocusedItem(&mt, &MenuInfo, wFlags); + fEndMenu = (executedMenuId != -2); } - else if ((UINT) -1 == Pos) - { - MessageBeep(0); - } - else - { - MenuSelectItem(Mt.OwnerWnd, &MenuInfo, Pos, TRUE, 0); - ExecutedMenuId = MenuExecFocusedItem(&Mt, &MenuInfo, Flags); - fEndMenu = (-2 != ExecutedMenuId); - } - } - break; + } + break; } /* switch(msg.message) - kbd */ } - else + else { - PeekMessageW( &Msg, 0, Msg.message, Msg.message, PM_REMOVE ); - DispatchMessageW(&Msg); - continue; + PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE ); + DispatchMessageW( &msg ); + continue; } - if (! fEndMenu) - { - fRemove = TRUE; - } + if (!fEndMenu) fRemove = TRUE; - /* finally remove message from the queue */ + /* finally remove message from the queue */ - if (fRemove && 0 == (Mt.TrackFlags & TF_SKIPREMOVE)) - { - PeekMessageW(&Msg, 0, Msg.message, Msg.message, PM_REMOVE); - } - else - { - Mt.TrackFlags &= ~TF_SKIPREMOVE; - } + if (fRemove && !(mt.TrackFlags & TF_SKIPREMOVE) ) + PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE ); + else mt.TrackFlags &= ~TF_SKIPREMOVE; } - ERR("MenuTrackMenu 2\n"); - (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER, NULL); - SetCapture(NULL); /* release the capture */ + (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER, NULL); + SetCapture(NULL); /* release the capture */ - /* If dropdown is still painted and the close box is clicked on - then the menu will be destroyed as part of the DispatchMessage above. - This will then invalidate the menu handle in Mt.hTopMenu. We should - check for this first. */ - if (IsMenu(Mt.TopMenu)) + /* If dropdown is still painted and the close box is clicked on + then the menu will be destroyed as part of the DispatchMessage above. + This will then invalidate the menu handle in mt.hTopMenu. We should + check for this first. */ + if( IsMenu( mt.TopMenu ) ) { - if (IsWindow(Mt.OwnerWnd)) + if (IsWindow(mt.OwnerWnd)) { - if (MenuGetRosMenuInfo(&MenuInfo, Mt.TopMenu)) + if (MenuGetRosMenuInfo(&MenuInfo, mt.TopMenu)) { - MenuHideSubPopups(Mt.OwnerWnd, &MenuInfo, FALSE); + MenuHideSubPopups(mt.OwnerWnd, &MenuInfo, FALSE); - if (0 != (MenuInfo.Flags & MF_POPUP)) + if (MenuInfo.Flags & MF_POPUP) { - DestroyWindow(MenuInfo.Wnd); - MenuInfo.Wnd = NULL; + DestroyWindow(MenuInfo.Wnd); + MenuInfo.Wnd = NULL; - if (!(MenuInfo.Flags & TPM_NONOTIFY)) - SendMessageW( Mt.OwnerWnd, WM_UNINITMENUPOPUP, (WPARAM)Mt.TopMenu, + if (!(MenuInfo.Flags & TPM_NONOTIFY)) + SendMessageW( mt.OwnerWnd, WM_UNINITMENUPOPUP, (WPARAM)mt.TopMenu, MAKELPARAM(0, IS_SYSTEM_MENU(&MenuInfo)) ); } - MenuSelectItem(Mt.OwnerWnd, &MenuInfo, NO_SELECTED_ITEM, FALSE, NULL); + MenuSelectItem( mt.OwnerWnd, &MenuInfo, NO_SELECTED_ITEM, FALSE, 0 ); } - SendMessageW(Mt.OwnerWnd, WM_MENUSELECT, MAKELONG(0, 0xffff), 0); + SendMessageW( mt.OwnerWnd, WM_MENUSELECT, MAKEWPARAM(0, 0xffff), 0 ); } - if (MenuGetRosMenuInfo(&MenuInfo, Mt.TopMenu)) + /* Reset the variable for hiding menu */ + if (MenuGetRosMenuInfo(&MenuInfo, mt.TopMenu)) { - /* Reset the variable for hiding menu */ - MenuInfo.TimeToHide = FALSE; - MenuSetRosMenuInfo(&MenuInfo); + MenuInfo.TimeToHide = FALSE; + MenuSetRosMenuInfo(&MenuInfo); } } - /* The return value is only used by TrackPopupMenu */ - if (!(Flags & TPM_RETURNCMD)) return TRUE; - if (ExecutedMenuId < 0) ExecutedMenuId = 0; - return ExecutedMenuId; + /* The return value is only used by TrackPopupMenu */ + if (!(wFlags & TPM_RETURNCMD)) return TRUE; + if (executedMenuId == -1) executedMenuId = 0; + return executedMenuId; } +/*********************************************************************** + * MenuInitTracking + */ +static BOOL FASTCALL MenuInitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags) +{ + ROSMENUINFO MenuInfo; + + TRACE("hwnd=%p hmenu=%p\n", hWnd, hMenu); + + HideCaret(0); + + /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */ + if (!(wFlags & TPM_NONOTIFY)) + SendMessageW( hWnd, WM_ENTERMENULOOP, bPopup, 0 ); + + SendMessageW( hWnd, WM_SETCURSOR, (WPARAM)hWnd, HTCAPTION ); + + if (!(wFlags & TPM_NONOTIFY)) + { + SendMessageW( hWnd, WM_INITMENU, (WPARAM)hMenu, 0 ); + + MenuGetRosMenuInfo(&MenuInfo, hMenu); + + if (!MenuInfo.Height) + { + /* app changed/recreated menu bar entries in WM_INITMENU + Recalculate menu sizes else clicks will not work */ + SetWindowPos(hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | + SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED ); + + } + /* This makes the menus of applications built with Delphi work. + * It also enables menus to be displayed in more than one window, + * but there are some bugs left that need to be fixed in this case. + */ + if(MenuInfo.Self == hMenu) + { + MenuInfo.Wnd = hWnd; + MenuSetRosMenuInfo(&MenuInfo); + } + } + + return TRUE; +} /*********************************************************************** * MenuExitTracking */ -static BOOL FASTCALL -MenuExitTracking(HWND Wnd) +static BOOL FASTCALL MenuExitTracking(HWND hWnd) { - TRACE("hwnd=%p\n", Wnd); + TRACE("hwnd=%p\n", hWnd); - SendMessageW(Wnd, WM_EXITMENULOOP, 0, 0); - ShowCaret(0); - return TRUE; + SendMessageW( hWnd, WM_EXITMENULOOP, 0, 0 ); + ShowCaret(0); + top_popup = 0; + return TRUE; } - -VOID -MenuTrackMouseMenuBar(HWND Wnd, ULONG Ht, POINT Pt) +/*********************************************************************** + * MenuTrackMouseMenuBar + * + * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand(). + */ +VOID MenuTrackMouseMenuBar( HWND hWnd, ULONG ht, POINT pt) { - HMENU Menu = (HTSYSMENU == Ht) ? NtUserGetSystemMenu(Wnd, FALSE) : GetMenu(Wnd); - UINT Flags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON; + HMENU hMenu = (ht == HTSYSMENU) ? NtUserGetSystemMenu( hWnd, FALSE) : GetMenu(hWnd); + UINT wFlags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON; - TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", Wnd, Ht, Pt.x, Pt.y); + TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", hWnd, ht, pt.x, pt.y); - if (IsMenu(Menu)) + if (IsMenu(hMenu)) { - /* map point to parent client coordinates */ - HWND Parent = GetAncestor(Wnd, GA_PARENT ); - if (Parent != GetDesktopWindow()) + /* map point to parent client coordinates */ + HWND Parent = GetAncestor(hWnd, GA_PARENT ); + if (Parent != GetDesktopWindow()) { - ScreenToClient(Parent, &Pt); + ScreenToClient(Parent, &pt); } - MenuInitTracking(Wnd, Menu, FALSE, Flags); - MenuTrackMenu(Menu, Flags, Pt.x, Pt.y, Wnd, NULL); - MenuExitTracking(Wnd); + MenuInitTracking(hWnd, hMenu, FALSE, wFlags); + MenuTrackMenu(hMenu, wFlags, pt.x, pt.y, hWnd, NULL); + MenuExitTracking(hWnd); } } -VOID -MenuTrackKbdMenuBar(HWND hWnd, UINT wParam, WCHAR wChar) +/*********************************************************************** + * MenuTrackKbdMenuBar + * + * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand(). + */ +VOID MenuTrackKbdMenuBar(HWND hwnd, UINT wParam, WCHAR wChar) { UINT uItem = NO_SELECTED_ITEM; HMENU hTrackMenu; ROSMENUINFO MenuInfo; UINT wFlags = TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON; - TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hWnd, wParam, wChar); + TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hwnd, wParam, wChar); /* find window that has a menu */ - while (!((GetWindowLongPtrW( hWnd, GWL_STYLE ) & + while (!((GetWindowLongPtrW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) != WS_CHILD)) - if (!(hWnd = GetAncestor( hWnd, GA_PARENT ))) return; + if (!(hwnd = GetAncestor( hwnd, GA_PARENT ))) return; /* check if we have to track a system menu */ - hTrackMenu = GetMenu( hWnd ); - if (!hTrackMenu || IsIconic(hWnd) || wChar == ' ' ) + hTrackMenu = GetMenu( hwnd ); + if (!hTrackMenu || IsIconic(hwnd) || wChar == ' ' ) { - if (!(GetWindowLongPtrW( hWnd, GWL_STYLE ) & WS_SYSMENU)) return; - hTrackMenu = NtUserGetSystemMenu(hWnd, FALSE); + if (!(GetWindowLongPtrW( hwnd, GWL_STYLE ) & WS_SYSMENU)) return; + hTrackMenu = NtUserGetSystemMenu(hwnd, FALSE); uItem = 0; wParam |= HTSYSMENU; /* prevent item lookup */ } if (!IsMenu( hTrackMenu )) return; - MenuInitTracking( hWnd, hTrackMenu, FALSE, wFlags ); + MenuInitTracking( hwnd, hTrackMenu, FALSE, wFlags ); if (! MenuGetRosMenuInfo(&MenuInfo, hTrackMenu)) { @@ -3677,7 +3606,7 @@ MenuTrackKbdMenuBar(HWND hWnd, UINT wParam, WCHAR wChar) if( wChar && wChar != ' ' ) { - uItem = MenuFindItemByKey( hWnd, &MenuInfo, wChar, (wParam & HTSYSMENU) ); + uItem = MenuFindItemByKey( hwnd, &MenuInfo, wChar, (wParam & HTSYSMENU) ); if ( uItem >= (UINT)(-2) ) { if( uItem == (UINT)(-1) ) MessageBeep(0); @@ -3687,7 +3616,7 @@ MenuTrackKbdMenuBar(HWND hWnd, UINT wParam, WCHAR wChar) } } - MenuSelectItem( hWnd, &MenuInfo, uItem, TRUE, 0 ); + MenuSelectItem( hwnd, &MenuInfo, uItem, TRUE, 0 ); if (wParam & HTSYSMENU) { @@ -3698,14 +3627,14 @@ MenuTrackKbdMenuBar(HWND hWnd, UINT wParam, WCHAR wChar) else { if( uItem == NO_SELECTED_ITEM ) - MenuMoveSelection( hWnd, &MenuInfo, ITEM_NEXT ); + MenuMoveSelection( hwnd, &MenuInfo, ITEM_NEXT ); else - PostMessageW( hWnd, WM_KEYDOWN, VK_DOWN, 0L ); + PostMessageW( hwnd, WM_KEYDOWN, VK_DOWN, 0L ); } track_menu: - MenuTrackMenu( hTrackMenu, wFlags, 0, 0, hWnd, NULL ); - MenuExitTracking( hWnd ); + MenuTrackMenu( hTrackMenu, wFlags, 0, 0, hwnd, NULL ); + MenuExitTracking( hwnd ); } From 6c45294b53dffafff9dcc3aac5038a7bde7fe326 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Wed, 17 Mar 2010 05:02:06 +0000 Subject: [PATCH 50/61] - Add a hack to disable ACPI if VMware is detected - This hack circumvents the main blocker that prevents enabling ACPI in trunk svn path=/trunk/; revision=46237 --- reactos/drivers/bus/acpi/acpica/tables/tbutils.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/reactos/drivers/bus/acpi/acpica/tables/tbutils.c b/reactos/drivers/bus/acpi/acpica/tables/tbutils.c index ec2a88e283d..a0f27580d0d 100644 --- a/reactos/drivers/bus/acpi/acpica/tables/tbutils.c +++ b/reactos/drivers/bus/acpi/acpica/tables/tbutils.c @@ -592,6 +592,7 @@ AcpiTbParseRootTable ( UINT32 Length; UINT8 *TableEntry; ACPI_STATUS Status; + ACPI_TABLE_HEADER LocalHeader; ACPI_FUNCTION_TRACE (TbParseRootTable); @@ -646,6 +647,14 @@ AcpiTbParseRootTable ( AcpiTbPrintTableHeader (Address, Table); + AcpiTbCleanupTableHeader (&LocalHeader, Table); + if (strstr(LocalHeader.AslCompilerId, "VMW")) + { + ACPI_ERROR ((AE_INFO, "VMware detected; ACPI has been disabled\n")); + AcpiOsUnmapMemory (Table, sizeof (ACPI_TABLE_HEADER)); + return_ACPI_STATUS (AE_ERROR); + } + /* Get the length of the full table, verify length and map entire table */ Length = Table->Length; From e77675a0a9f6ed2e7450c67f272e2577317df0c1 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Wed, 17 Mar 2010 05:30:22 +0000 Subject: [PATCH 51/61] - Define NDEBUG and demote several non-critical debug prints to DPRINT svn path=/trunk/; revision=46238 --- reactos/drivers/bus/acpi/acpienum.c | 2 +- reactos/drivers/bus/acpi/busmgr/bus.c | 2 +- reactos/drivers/bus/acpi/busmgr/power.c | 2 +- reactos/drivers/bus/acpi/busmgr/system.c | 2 +- reactos/drivers/bus/acpi/busmgr/utils.c | 2 +- reactos/drivers/bus/acpi/buspdo.c | 2 +- reactos/drivers/bus/acpi/main.c | 6 +++--- reactos/drivers/bus/acpi/osl.c | 8 ++++---- reactos/drivers/bus/acpi/pnp.c | 2 +- reactos/drivers/bus/acpi/power.c | 2 +- 10 files changed, 15 insertions(+), 15 deletions(-) diff --git a/reactos/drivers/bus/acpi/acpienum.c b/reactos/drivers/bus/acpi/acpienum.c index 13e72ddb9f4..c011dbadd63 100644 --- a/reactos/drivers/bus/acpi/acpienum.c +++ b/reactos/drivers/bus/acpi/acpienum.c @@ -13,7 +13,7 @@ #include #include -//#define NDEBUG +#define NDEBUG #include #define HAS_CHILDREN(d) ((d)->children.next != &((d)->children)) diff --git a/reactos/drivers/bus/acpi/busmgr/bus.c b/reactos/drivers/bus/acpi/busmgr/bus.c index 949cfd2bd65..34aa0766c04 100644 --- a/reactos/drivers/bus/acpi/busmgr/bus.c +++ b/reactos/drivers/bus/acpi/busmgr/bus.c @@ -34,7 +34,7 @@ #include #include -//#define NDEBUG +#define NDEBUG #include #define _COMPONENT ACPI_BUS_COMPONENT diff --git a/reactos/drivers/bus/acpi/busmgr/power.c b/reactos/drivers/bus/acpi/busmgr/power.c index 6c6bc0814bf..77a37198ed7 100644 --- a/reactos/drivers/bus/acpi/busmgr/power.c +++ b/reactos/drivers/bus/acpi/busmgr/power.c @@ -46,7 +46,7 @@ #include #include -//#define NDEBUG +#define NDEBUG #include diff --git a/reactos/drivers/bus/acpi/busmgr/system.c b/reactos/drivers/bus/acpi/busmgr/system.c index d0f0503f366..ca5a0852bf9 100644 --- a/reactos/drivers/bus/acpi/busmgr/system.c +++ b/reactos/drivers/bus/acpi/busmgr/system.c @@ -32,7 +32,7 @@ #include #include "list.h" -//#define NDEBUG +#define NDEBUG #include ACPI_STATUS acpi_system_save_state(UINT32); diff --git a/reactos/drivers/bus/acpi/busmgr/utils.c b/reactos/drivers/bus/acpi/busmgr/utils.c index 67eaed017ca..2a82e49604c 100644 --- a/reactos/drivers/bus/acpi/busmgr/utils.c +++ b/reactos/drivers/bus/acpi/busmgr/utils.c @@ -30,7 +30,7 @@ #include #include -//#define NDEBUG +#define NDEBUG #include /* Modified for ReactOS and latest ACPICA diff --git a/reactos/drivers/bus/acpi/buspdo.c b/reactos/drivers/bus/acpi/buspdo.c index 6fe0f864ef3..ec253359b83 100644 --- a/reactos/drivers/bus/acpi/buspdo.c +++ b/reactos/drivers/bus/acpi/buspdo.c @@ -8,7 +8,7 @@ #include #include -//#define NDEBUG +#define NDEBUG #include #ifdef ALLOC_PRAGMA diff --git a/reactos/drivers/bus/acpi/main.c b/reactos/drivers/bus/acpi/main.c index d8d8b3e7dad..3d1170eefd6 100644 --- a/reactos/drivers/bus/acpi/main.c +++ b/reactos/drivers/bus/acpi/main.c @@ -6,7 +6,7 @@ #include #include -//#define NDEBUG +#define NDEBUG #include #ifdef ALLOC_PRAGMA @@ -35,7 +35,7 @@ Bus_AddDevice( DPRINT("Add Device: 0x%p\n", PhysicalDeviceObject); - DPRINT1("#################### Bus_CreateClose Creating FDO Device ####################\n"); + DPRINT("#################### Bus_CreateClose Creating FDO Device ####################\n"); status = IoCreateDevice(DriverObject, sizeof(FDO_DEVICE_DATA), NULL, @@ -134,7 +134,7 @@ Bus_AddDevice( goto End; } - DPRINT1("AddDevice: %p to %p->%p (%ws) \n", + DPRINT("AddDevice: %p to %p->%p (%ws) \n", deviceObject, deviceData->NextLowerDriver, PhysicalDeviceObject, diff --git a/reactos/drivers/bus/acpi/osl.c b/reactos/drivers/bus/acpi/osl.c index 760c9cb83ad..1c55c32cb1a 100644 --- a/reactos/drivers/bus/acpi/osl.c +++ b/reactos/drivers/bus/acpi/osl.c @@ -90,7 +90,7 @@ AcpiOsInitialize (void) ACPI_STATUS AcpiOsTerminate(void) { - DPRINT1("AcpiOsTerminate() called\n"); + DPRINT("AcpiOsTerminate() called\n"); if (AcpiInterruptHandlerRegistered) AcpiOsRemoveInterruptHandler(AcpiIrqNumber, AcpiIrqHandler); @@ -329,7 +329,7 @@ AcpiOsRemoveInterruptHandler ( void AcpiOsStall (UINT32 microseconds) { - DPRINT1("AcpiOsStall %d\n",microseconds); + DPRINT("AcpiOsStall %d\n",microseconds); KeStallExecutionProcessor(microseconds); return; } @@ -337,7 +337,7 @@ AcpiOsStall (UINT32 microseconds) void AcpiOsSleep (ACPI_INTEGER milliseconds) { - DPRINT1("AcpiOsSleep %d\n", milliseconds); + DPRINT("AcpiOsSleep %d\n", milliseconds); KeStallExecutionProcessor(milliseconds*1000); return; } @@ -664,7 +664,7 @@ AcpiOsExecute ( ACPI_OSD_EXEC_CALLBACK Function, void *Context) { - DPRINT1("AcpiOsExecute\n"); + DPRINT("AcpiOsExecute\n"); KeInsertQueueDpc(&AcpiDpc, (PVOID)Function, (PVOID)Context); diff --git a/reactos/drivers/bus/acpi/pnp.c b/reactos/drivers/bus/acpi/pnp.c index 4778dc66c2e..c82a3905023 100644 --- a/reactos/drivers/bus/acpi/pnp.c +++ b/reactos/drivers/bus/acpi/pnp.c @@ -7,7 +7,7 @@ #include #include -//#define NDEBUG +#define NDEBUG #include #ifdef ALLOC_PRAGMA diff --git a/reactos/drivers/bus/acpi/power.c b/reactos/drivers/bus/acpi/power.c index 3af99c96402..2f7175c74ad 100644 --- a/reactos/drivers/bus/acpi/power.c +++ b/reactos/drivers/bus/acpi/power.c @@ -6,7 +6,7 @@ #include #include -//#define NDEBUG +#define NDEBUG #include NTSTATUS From fa481444a7b5aa5d2f72273ab547f9ec26de2778 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Wed, 17 Mar 2010 06:19:01 +0000 Subject: [PATCH 52/61] - Don't acquire the mutex in the ISR handler because we're at a raised IRQL - Fixes VirtualBox Additions with ACPI enabled svn path=/trunk/; revision=46239 --- reactos/drivers/bus/acpi/acpica/events/evgpe.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/reactos/drivers/bus/acpi/acpica/events/evgpe.c b/reactos/drivers/bus/acpi/acpica/events/evgpe.c index 17738b38404..00d72e54722 100644 --- a/reactos/drivers/bus/acpi/acpica/events/evgpe.c +++ b/reactos/drivers/bus/acpi/acpica/events/evgpe.c @@ -505,7 +505,7 @@ AcpiEvGpeDetect ( UINT8 EnabledStatusByte; UINT32 StatusReg; UINT32 EnableReg; - ACPI_CPU_FLAGS Flags; + //ACPI_CPU_FLAGS Flags; UINT32 i; UINT32 j; @@ -524,7 +524,7 @@ AcpiEvGpeDetect ( * Note: Not necessary to obtain the hardware lock, since the GPE * registers are owned by the GpeLock. */ - Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); + //Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); /* Examine all GPE blocks attached to this interrupt level */ @@ -596,7 +596,7 @@ AcpiEvGpeDetect ( UnlockAndExit: - AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + //AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); return (IntStatus); } From 82b827258423528b2b6ff0bc1cec9a5e8881219a Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Wed, 17 Mar 2010 07:16:08 +0000 Subject: [PATCH 53/61] - Check that the device number is not invalid - ACPI now crashes later on VMware svn path=/trunk/; revision=46240 --- reactos/drivers/bus/acpi/osl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reactos/drivers/bus/acpi/osl.c b/reactos/drivers/bus/acpi/osl.c index 1c55c32cb1a..d86e70bcb7c 100644 --- a/reactos/drivers/bus/acpi/osl.c +++ b/reactos/drivers/bus/acpi/osl.c @@ -466,7 +466,7 @@ AcpiOsReadPciConfiguration ( NTSTATUS Status; PCI_SLOT_NUMBER slot; - if (Register == 0) + if (Register == 0 || PciId->Device == 0) return AE_ERROR; slot.u.AsULONG = 0; @@ -498,7 +498,7 @@ AcpiOsWritePciConfiguration ( ULONG buf = Value; PCI_SLOT_NUMBER slot; - if (Register == 0) + if (Register == 0 || PciId->Device == 0) return AE_ERROR; slot.u.AsULONG = 0; From 44b4c1e7d15462d1dba4ebe386c9ad95ecbb33e2 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Wed, 17 Mar 2010 08:48:57 +0000 Subject: [PATCH 54/61] - Check that the memory location that we are trying to read is valid - Remove the VMware hack - ACPI works on all tested VMs now (QEMU, VirtualBox, and VMware) - Just a resource code issue remains and prevents us from enabling ACPI by default svn path=/trunk/; revision=46241 --- reactos/drivers/bus/acpi/acpica/tables/tbutils.c | 9 --------- reactos/drivers/bus/acpi/osl.c | 6 ++++-- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/reactos/drivers/bus/acpi/acpica/tables/tbutils.c b/reactos/drivers/bus/acpi/acpica/tables/tbutils.c index a0f27580d0d..ec2a88e283d 100644 --- a/reactos/drivers/bus/acpi/acpica/tables/tbutils.c +++ b/reactos/drivers/bus/acpi/acpica/tables/tbutils.c @@ -592,7 +592,6 @@ AcpiTbParseRootTable ( UINT32 Length; UINT8 *TableEntry; ACPI_STATUS Status; - ACPI_TABLE_HEADER LocalHeader; ACPI_FUNCTION_TRACE (TbParseRootTable); @@ -647,14 +646,6 @@ AcpiTbParseRootTable ( AcpiTbPrintTableHeader (Address, Table); - AcpiTbCleanupTableHeader (&LocalHeader, Table); - if (strstr(LocalHeader.AslCompilerId, "VMW")) - { - ACPI_ERROR ((AE_INFO, "VMware detected; ACPI has been disabled\n")); - AcpiOsUnmapMemory (Table, sizeof (ACPI_TABLE_HEADER)); - return_ACPI_STATUS (AE_ERROR); - } - /* Get the length of the full table, verify length and map entire table */ Length = Table->Length; diff --git a/reactos/drivers/bus/acpi/osl.c b/reactos/drivers/bus/acpi/osl.c index d86e70bcb7c..9e2f35e2192 100644 --- a/reactos/drivers/bus/acpi/osl.c +++ b/reactos/drivers/bus/acpi/osl.c @@ -466,7 +466,8 @@ AcpiOsReadPciConfiguration ( NTSTATUS Status; PCI_SLOT_NUMBER slot; - if (Register == 0 || PciId->Device == 0) + if (Register == 0 || PciId->Device == 0 || + Register + Width > PCI_COMMON_HDR_LENGTH) return AE_ERROR; slot.u.AsULONG = 0; @@ -498,7 +499,8 @@ AcpiOsWritePciConfiguration ( ULONG buf = Value; PCI_SLOT_NUMBER slot; - if (Register == 0 || PciId->Device == 0) + if (Register == 0 || PciId->Device == 0 || + Register + Width > PCI_COMMON_HDR_LENGTH) return AE_ERROR; slot.u.AsULONG = 0; From 2545746a8075ab7fa74d32975e82a623330c73bb Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Wed, 17 Mar 2010 09:25:07 +0000 Subject: [PATCH 55/61] - Set the resource pointer back to the start of the list before looping a second time - Remove the duplicate OSL - Disable more debug prints - ROS with ACPI has been booted successfully on VirtualBox (with additions), QEMU, and VMware svn path=/trunk/; revision=46242 --- reactos/drivers/bus/acpi/acpica/acpica.rbuild | 3 - reactos/drivers/bus/acpi/acpica/osl/osl.c | 751 ------------------ reactos/drivers/bus/acpi/buspdo.c | 2 + reactos/drivers/bus/acpi/osl.c | 2 + 4 files changed, 4 insertions(+), 754 deletions(-) delete mode 100644 reactos/drivers/bus/acpi/acpica/osl/osl.c diff --git a/reactos/drivers/bus/acpi/acpica/acpica.rbuild b/reactos/drivers/bus/acpi/acpica/acpica.rbuild index b23eed8d5b2..ce6fee8791f 100644 --- a/reactos/drivers/bus/acpi/acpica/acpica.rbuild +++ b/reactos/drivers/bus/acpi/acpica/acpica.rbuild @@ -83,9 +83,6 @@ nsxfname.c nsxfobj.c - psargs.c psloop.c diff --git a/reactos/drivers/bus/acpi/acpica/osl/osl.c b/reactos/drivers/bus/acpi/acpica/osl/osl.c deleted file mode 100644 index a8c240a77d2..00000000000 --- a/reactos/drivers/bus/acpi/acpica/osl/osl.c +++ /dev/null @@ -1,751 +0,0 @@ -/******************************************************************************* -* * -* ACPI Component Architecture Operating System Layer (OSL) for ReactOS * -* * -*******************************************************************************/ - -#include - -#define NDEBUG -#include - -#define NUM_SEMAPHORES 128 - -static PKINTERRUPT AcpiInterrupt; -static BOOLEAN AcpiInterruptHandlerRegistered = FALSE; -static ACPI_OSD_HANDLER AcpiIrqHandler = NULL; -static PVOID AcpiIrqContext = NULL; -static ULONG AcpiIrqNumber = 0; -static KDPC AcpiDpc; -static PVOID IVTVirtualAddress = NULL; - - -typedef struct semaphore_entry -{ - UINT16 MaxUnits; - UINT16 CurrentUnits; - void *OsHandle; -} SEMAPHORE_ENTRY; - -static SEMAPHORE_ENTRY AcpiGbl_Semaphores[NUM_SEMAPHORES]; - -VOID NTAPI -OslDpcStub( - IN PKDPC Dpc, - IN PVOID DeferredContext, - IN PVOID SystemArgument1, - IN PVOID SystemArgument2) -{ - ACPI_OSD_EXEC_CALLBACK Routine = (ACPI_OSD_EXEC_CALLBACK)SystemArgument1; - - DPRINT("OslDpcStub()\n"); - DPRINT("Calling [%p]([%p])\n", Routine, SystemArgument2); - (*Routine)(SystemArgument2); -} - -BOOLEAN NTAPI -OslIsrStub( - PKINTERRUPT Interrupt, - PVOID ServiceContext) -{ - INT32 Status; - - Status = (*AcpiIrqHandler)(AcpiIrqContext); - - if (ACPI_SUCCESS(Status)) - return TRUE; - else - return FALSE; -} - -ACPI_STATUS -AcpiOsRemoveInterruptHandler ( - UINT32 InterruptNumber, - ACPI_OSD_HANDLER ServiceRoutine); - -ACPI_STATUS -AcpiOsInitialize (void) -{ - DPRINT("AcpiOsInitialize called\n"); - -#ifndef NDEBUG - /* Verboseness level of the acpica core */ - AcpiDbgLevel = 0x00FFFFFF; - AcpiDbgLayer = 0xFFFFFFFF; -#endif - - UINT32 i; - - for (i = 0; i < NUM_SEMAPHORES; i++) - { - AcpiGbl_Semaphores[i].OsHandle = NULL; - } - - KeInitializeDpc(&AcpiDpc, OslDpcStub, NULL); - - return AE_OK; -} - -ACPI_STATUS -AcpiOsTerminate(void) -{ - DPRINT1("AcpiOsTerminate() called\n"); - - if (AcpiInterruptHandlerRegistered) - AcpiOsRemoveInterruptHandler(AcpiIrqNumber, AcpiIrqHandler); - - return AE_OK; -} - -void ACPI_INTERNAL_VAR_XFACE -AcpiOsPrintf ( - const char *Fmt, - ...) -{ - va_list Args; - va_start (Args, Fmt); - - AcpiOsVprintf (Fmt, Args); - - va_end (Args); - return; -} - -void -AcpiOsVprintf ( - const char *Fmt, - va_list Args) -{ - vDbgPrintEx (-1, DPFLTR_ERROR_LEVEL, Fmt, Args); - return; -} - -void * -AcpiOsAllocate (ACPI_SIZE size) -{ - DPRINT("AcpiOsAllocate size %d\n",size); - return ExAllocatePool(NonPagedPool, size); -} - -void * -AcpiOsCallocate(ACPI_SIZE size) -{ - PVOID ptr = ExAllocatePool(NonPagedPool, size); - if (ptr) - memset(ptr, 0, size); - return ptr; -} - -void -AcpiOsFree(void *ptr) -{ - if (!ptr) - DPRINT1("Attempt to free null pointer!!!\n"); - ExFreePool(ptr); -} - -#ifndef ACPI_USE_LOCAL_CACHE - -void* -AcpiOsAcquireObjectHelper ( - POOL_TYPE PoolType, - SIZE_T NumberOfBytes, - ULONG Tag) -{ - void* Alloc = ExAllocatePool(PoolType, NumberOfBytes); - - /* acpica expects memory allocated from cache to be zeroed */ - RtlZeroMemory(Alloc,NumberOfBytes); - return Alloc; -} - -ACPI_STATUS -AcpiOsCreateCache ( - char *CacheName, - UINT16 ObjectSize, - UINT16 MaxDepth, - ACPI_CACHE_T **ReturnCache) -{ - PNPAGED_LOOKASIDE_LIST Lookaside = - ExAllocatePool(NonPagedPool,sizeof(NPAGED_LOOKASIDE_LIST)); - - ExInitializeNPagedLookasideList(Lookaside, - (PALLOCATE_FUNCTION)AcpiOsAcquireObjectHelper,// custom memory allocator - NULL, - 0, - ObjectSize, - 'IPCA', - 0); - *ReturnCache = (ACPI_CACHE_T *)Lookaside; - - DPRINT("AcpiOsCreateCache %p\n", Lookaside); - return (AE_OK); -} - -ACPI_STATUS -AcpiOsDeleteCache ( - ACPI_CACHE_T *Cache) -{ - DPRINT("AcpiOsDeleteCache %p\n", Cache); - ExDeleteNPagedLookasideList( - (PNPAGED_LOOKASIDE_LIST) Cache); - ExFreePool(Cache); - return (AE_OK); -} - -ACPI_STATUS -AcpiOsPurgeCache ( - ACPI_CACHE_T *Cache) -{ - DPRINT("AcpiOsPurgeCache\n"); - /* No such functionality for LookAside lists */ - return (AE_OK); -} - -void * -AcpiOsAcquireObject ( - ACPI_CACHE_T *Cache) -{ - PNPAGED_LOOKASIDE_LIST List = (PNPAGED_LOOKASIDE_LIST)Cache; - DPRINT("AcpiOsAcquireObject from %p\n", Cache); - void* ptr = - ExAllocateFromNPagedLookasideList(List); - ASSERT(ptr); - - RtlZeroMemory(ptr,List->L.Size); - return ptr; -} - -ACPI_STATUS -AcpiOsReleaseObject ( - ACPI_CACHE_T *Cache, - void *Object) -{ - DPRINT("AcpiOsReleaseObject %p from %p\n",Object, Cache); - ExFreeToNPagedLookasideList( - (PNPAGED_LOOKASIDE_LIST)Cache, - Object); - return (AE_OK); -} - -#endif - -void * -AcpiOsMapMemory ( - ACPI_PHYSICAL_ADDRESS phys, - ACPI_SIZE length) -{ - PHYSICAL_ADDRESS Address; - - DPRINT("AcpiOsMapMemory(phys 0x%X size 0x%X)\n", (ULONG)phys, length); - if (phys == 0x0) - { - IVTVirtualAddress = ExAllocatePool(NonPagedPool, length); - return IVTVirtualAddress; - } - - Address.QuadPart = (ULONG)phys; - return MmMapIoSpace(Address, length, MmNonCached); -} - -void -AcpiOsUnmapMemory ( - void *virt, - ACPI_SIZE length) -{ - DPRINT("AcpiOsUnmapMemory()\n"); - - if (virt == 0x0) - { - ExFreePool(IVTVirtualAddress); - return; - } - MmUnmapIoSpace(virt, length); -} - -UINT32 -AcpiOsInstallInterruptHandler ( - UINT32 InterruptNumber, - ACPI_OSD_HANDLER ServiceRoutine, - void *Context) -{ - ULONG Vector; - KIRQL DIrql; - KAFFINITY Affinity; - NTSTATUS Status; - - DPRINT("AcpiOsInstallInterruptHandler()\n"); - Vector = HalGetInterruptVector( - Internal, - 0, - InterruptNumber, - 0, - &DIrql, - &Affinity); - - AcpiIrqNumber = InterruptNumber; - AcpiIrqHandler = ServiceRoutine; - AcpiIrqContext = Context; - AcpiInterruptHandlerRegistered = TRUE; - - Status = IoConnectInterrupt( - &AcpiInterrupt, - OslIsrStub, - NULL, - NULL, - Vector, - DIrql, - DIrql, - LevelSensitive, /* FIXME: LevelSensitive or Latched? */ - TRUE, - Affinity, - FALSE); - - if (!NT_SUCCESS(Status)) - { - DPRINT("Could not connect to interrupt %d\n", Vector); - return AE_ERROR; - } - return AE_OK; -} - -ACPI_STATUS -AcpiOsRemoveInterruptHandler ( - UINT32 InterruptNumber, - ACPI_OSD_HANDLER ServiceRoutine) -{ - DPRINT("AcpiOsRemoveInterruptHandler()\n"); - if (AcpiInterruptHandlerRegistered) - { - IoDisconnectInterrupt(AcpiInterrupt); - AcpiInterrupt = NULL; - AcpiInterruptHandlerRegistered = FALSE; - } - - return AE_OK; -} - -void -AcpiOsStall (UINT32 microseconds) -{ - DPRINT1("AcpiOsStall %d\n",microseconds); - KeStallExecutionProcessor(microseconds); - return; -} - -void -AcpiOsSleep (ACPI_INTEGER milliseconds) -{ - DPRINT1("AcpiOsSleep %d\n", milliseconds); - KeStallExecutionProcessor(milliseconds*1000); - return; -} - -ACPI_STATUS -AcpiOsReadPort ( - ACPI_IO_ADDRESS Address, - UINT32 *Value, - UINT32 Width) -{ - DPRINT("AcpiOsReadPort %p, width %d\n",Address,Width); - - switch (Width) - { - case 8: - *Value = READ_PORT_UCHAR((PUCHAR)Address); - break; - - case 16: - *Value = READ_PORT_USHORT((PUSHORT)Address); - break; - - case 32: - *Value = READ_PORT_ULONG((PULONG)Address); - break; - default: - DPRINT1("AcpiOsReadPort got bad width: %d\n",Width); - return (AE_BAD_PARAMETER); - break; - } - return (AE_OK); -} - -ACPI_STATUS -AcpiOsWritePort ( - ACPI_IO_ADDRESS Address, - UINT32 Value, - UINT32 Width) -{ - DPRINT("AcpiOsWritePort %p, width %d\n",Address,Width); - switch (Width) - { - case 8: - WRITE_PORT_UCHAR((PUCHAR)Address, Value); - break; - - case 16: - WRITE_PORT_USHORT((PUSHORT)Address, Value); - break; - - case 32: - WRITE_PORT_ULONG((PULONG)Address, Value); - break; - - default: - DPRINT1("AcpiOsWritePort got bad width: %d\n",Width); - return (AE_BAD_PARAMETER); - break; - } - return (AE_OK); -} - -ACPI_STATUS -AcpiOsReadMemory ( - ACPI_PHYSICAL_ADDRESS Address, - UINT32 *Value, - UINT32 Width) -{ - DPRINT("AcpiOsReadMemory %p\n", Address); - switch (Width) - { - case 8: - *Value = (*(PUCHAR)(ULONG)Address); - break; - case 16: - *Value = (*(PUSHORT)(ULONG)Address); - break; - case 32: - *Value = (*(PULONG)(ULONG)Address); - break; - - default: - DPRINT1("AcpiOsReadMemory got bad width: %d\n",Width); - return (AE_BAD_PARAMETER); - break; - } - return (AE_OK); -} - - -ACPI_STATUS -AcpiOsWriteMemory ( - ACPI_PHYSICAL_ADDRESS Address, - UINT32 Value, - UINT32 Width) -{ - DPRINT("AcpiOsWriteMemory %p\n", Address); - switch (Width) - { - case 8: - *(PUCHAR)(ULONG)Address = Value; - break; - case 16: - *(PUSHORT)(ULONG)Address = Value; - break; - case 32: - *(PULONG)(ULONG)Address = Value; - break; - - default: - DPRINT1("AcpiOsWriteMemory got bad width: %d\n",Width); - return (AE_BAD_PARAMETER); - break; - } - - return (AE_OK); -} - -ACPI_STATUS -AcpiOsReadPciConfiguration ( - ACPI_PCI_ID *PciId, - UINT32 Register, - void *Value, - UINT32 Width) -{ - NTSTATUS Status; - PCI_SLOT_NUMBER slot; - - if (Register == 0) - return AE_ERROR; - - slot.u.AsULONG = 0; - slot.u.bits.DeviceNumber = PciId->Bus; - slot.u.bits.FunctionNumber = PciId->Function; - - DPRINT("AcpiOsReadPciConfiguration, slot=0x%X, func=0x%X\n", slot.u.AsULONG, Register); - Status = HalGetBusDataByOffset(PCIConfiguration, - PciId->Bus, - slot.u.AsULONG, - Value, - Register, - Width); - - if (NT_SUCCESS(Status)) - return AE_OK; - else - return AE_ERROR; -} - -ACPI_STATUS -AcpiOsWritePciConfiguration ( - ACPI_PCI_ID *PciId, - UINT32 Register, - ACPI_INTEGER Value, - UINT32 Width) -{ - NTSTATUS Status; - ULONG buf = Value; - PCI_SLOT_NUMBER slot; - - if (Register == 0) - return AE_ERROR; - - slot.u.AsULONG = 0; - slot.u.bits.DeviceNumber = PciId->Bus; - slot.u.bits.FunctionNumber = PciId->Function; - - DPRINT("AcpiOsWritePciConfiguration, slot=0x%x\n", slot.u.AsULONG); - Status = HalSetBusDataByOffset(PCIConfiguration, - PciId->Bus, - slot.u.AsULONG, - &buf, - Register, - Width); - - if (NT_SUCCESS(Status)) - return AE_OK; - else - return AE_ERROR; -} - -ACPI_STATUS -AcpiOsCreateSemaphore ( - UINT32 MaxUnits, - UINT32 InitialUnits, - ACPI_SEMAPHORE *OutHandle) -{ - PFAST_MUTEX Mutex; - - Mutex = ExAllocatePool(NonPagedPool, sizeof(FAST_MUTEX)); - if (!Mutex) - return AE_NO_MEMORY; - - DPRINT("AcpiOsCreateSemaphore() at 0x%X\n", Mutex); - - ExInitializeFastMutex(Mutex); - - *OutHandle = Mutex; - return AE_OK; -} - -ACPI_STATUS -AcpiOsDeleteSemaphore ( - ACPI_SEMAPHORE Handle) -{ - PFAST_MUTEX Mutex = (PFAST_MUTEX)Handle; - - DPRINT("AcpiOsDeleteSemaphore(handle 0x%X)\n", Handle); - - if (!Mutex) - return AE_BAD_PARAMETER; - - ExFreePool(Mutex); - return AE_OK; -} - -ACPI_STATUS -AcpiOsWaitSemaphore( - ACPI_SEMAPHORE Handle, - UINT32 units, - UINT16 timeout) -{ - PFAST_MUTEX Mutex = (PFAST_MUTEX)Handle; - - if (!Mutex || (units < 1)) - { - DPRINT("AcpiOsWaitSemaphore(handle 0x%X, units %d) Bad parameters\n", - Mutex, units); - return AE_BAD_PARAMETER; - } - - DPRINT("Waiting for semaphore %p\n", Handle); - ASSERT(Mutex); - - ExAcquireFastMutex(Mutex); - return AE_OK; -} - -ACPI_STATUS -AcpiOsSignalSemaphore ( - ACPI_HANDLE Handle, - UINT32 Units) -{ - PFAST_MUTEX Mutex = (PFAST_MUTEX)Handle; - - DPRINT("AcpiOsSignalSemaphore %p\n",Handle); - ASSERT(Mutex); - - ExReleaseFastMutex(Mutex); - return AE_OK; -} - -ACPI_STATUS -AcpiOsCreateLock ( - ACPI_SPINLOCK *OutHandle) -{ - DPRINT("AcpiOsCreateLock\n"); - return (AcpiOsCreateSemaphore (1, 1, OutHandle)); -} - -void -AcpiOsDeleteLock ( - ACPI_SPINLOCK Handle) -{ - DPRINT("AcpiOsDeleteLock %p\n", Handle); - AcpiOsDeleteSemaphore (Handle); -} - - -ACPI_CPU_FLAGS -AcpiOsAcquireLock ( - ACPI_HANDLE Handle) -{ - DPRINT("AcpiOsAcquireLock, %p\n", Handle); - AcpiOsWaitSemaphore (Handle, 1, 0xFFFF); - return (0); -} - - -void -AcpiOsReleaseLock ( - ACPI_SPINLOCK Handle, - ACPI_CPU_FLAGS Flags) -{ - DPRINT("AcpiOsReleaseLock %p\n",Handle); - AcpiOsSignalSemaphore (Handle, 1); -} - -ACPI_STATUS -AcpiOsSignal ( - UINT32 Function, - void *Info) -{ - - switch (Function) - { - case ACPI_SIGNAL_FATAL: - if (Info) - AcpiOsPrintf ("AcpiOsBreakpoint: %s ****\n", Info); - else - AcpiOsPrintf ("AcpiOsBreakpoint ****\n"); - break; - case ACPI_SIGNAL_BREAKPOINT: - if (Info) - AcpiOsPrintf ("AcpiOsBreakpoint: %s ****\n", Info); - else - AcpiOsPrintf ("AcpiOsBreakpoint ****\n"); - break; - } - - return (AE_OK); -} - - -ACPI_THREAD_ID -AcpiOsGetThreadId (void) -{ - return (ULONG)PsGetCurrentThreadId(); -} - -ACPI_STATUS -AcpiOsExecute ( - ACPI_EXECUTE_TYPE Type, - ACPI_OSD_EXEC_CALLBACK Function, - void *Context) -{ - DPRINT1("AcpiOsExecute\n"); - - KeInsertQueueDpc(&AcpiDpc, (PVOID)Function, (PVOID)Context); - -#ifdef _MULTI_THREADED - //_beginthread (Function, (unsigned) 0, Context); -#endif - - return 0; -} - -UINT64 -AcpiOsGetTimer (void) -{ - DPRINT("AcpiOsGetTimer\n"); - LARGE_INTEGER Timer; - KeQueryTickCount(&Timer); - - return Timer.QuadPart; -} - -void -AcpiOsDerivePciId( - ACPI_HANDLE rhandle, - ACPI_HANDLE chandle, - ACPI_PCI_ID **PciId) -{ - DPRINT("AcpiOsDerivePciId\n"); - return; -} - -ACPI_STATUS -AcpiOsPredefinedOverride ( - const ACPI_PREDEFINED_NAMES *InitVal, - ACPI_STRING *NewVal) -{ - if (!InitVal || !NewVal) - return AE_BAD_PARAMETER; - - *NewVal = ACPI_OS_NAME; - DPRINT("AcpiOsPredefinedOverride\n"); - return AE_OK; -} - -ACPI_PHYSICAL_ADDRESS -AcpiOsGetRootPointer ( - void); - -ACPI_STATUS -AcpiOsTableOverride ( - ACPI_TABLE_HEADER *ExistingTable, - ACPI_TABLE_HEADER **NewTable) -{ - DPRINT("AcpiOsTableOverride\n"); - *NewTable = NULL; - return (AE_OK); -} - -ACPI_STATUS -AcpiOsValidateInterface ( - char *Interface) -{ - DPRINT("AcpiOsValidateInterface\n"); - return (AE_OK); -} - -ACPI_STATUS -AcpiOsValidateAddress ( - UINT8 SpaceId, - ACPI_PHYSICAL_ADDRESS Address, - ACPI_SIZE Length) -{ - DPRINT("AcpiOsValidateAddress\n"); - return (AE_OK); -} - -ACPI_PHYSICAL_ADDRESS -AcpiOsGetRootPointer ( - void) -{ - DPRINT("AcpiOsGetRootPointer\n"); - ACPI_PHYSICAL_ADDRESS pa = 0; - - AcpiFindRootPointer(&pa); - return pa; -} diff --git a/reactos/drivers/bus/acpi/buspdo.c b/reactos/drivers/bus/acpi/buspdo.c index ec253359b83..4a9498e7ad4 100644 --- a/reactos/drivers/bus/acpi/buspdo.c +++ b/reactos/drivers/bus/acpi/buspdo.c @@ -679,6 +679,7 @@ Bus_PDO_QueryResources( ResourceDescriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors; /* Fill resources list structure */ + resource = Buffer.Pointer; while (resource->Type != ACPI_RESOURCE_TYPE_END_TAG) { switch (resource->Type) @@ -1093,6 +1094,7 @@ Bus_PDO_QueryResourceRequirements( RequirementDescriptor = RequirementsList->List[0].Descriptors; /* Fill resources list structure */ + resource = Buffer.Pointer; while (resource->Type != ACPI_RESOURCE_TYPE_END_TAG) { switch (resource->Type) diff --git a/reactos/drivers/bus/acpi/osl.c b/reactos/drivers/bus/acpi/osl.c index 9e2f35e2192..f2549951e7e 100644 --- a/reactos/drivers/bus/acpi/osl.c +++ b/reactos/drivers/bus/acpi/osl.c @@ -117,7 +117,9 @@ AcpiOsVprintf ( const char *Fmt, va_list Args) { +#ifndef NDEBUG vDbgPrintEx (-1, DPFLTR_ERROR_LEVEL, Fmt, Args); +#endif return; } From cc5a045b544d2f8eb2fdfbe811485866ef4c3610 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Wed, 17 Mar 2010 09:25:55 +0000 Subject: [PATCH 56/61] - Enable ACPI - Please send all complaints to roswarrior ;) svn path=/trunk/; revision=46243 --- reactos/ntoskrnl/io/pnpmgr/pnpmgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reactos/ntoskrnl/io/pnpmgr/pnpmgr.c b/reactos/ntoskrnl/io/pnpmgr/pnpmgr.c index e8418893452..e6346378566 100644 --- a/reactos/ntoskrnl/io/pnpmgr/pnpmgr.c +++ b/reactos/ntoskrnl/io/pnpmgr/pnpmgr.c @@ -13,7 +13,7 @@ #define NDEBUG #include -//#define ENABLE_ACPI +#define ENABLE_ACPI /* GLOBALS *******************************************************************/ From b6e52b15e393bfdab09d8d890bef9465db127608 Mon Sep 17 00:00:00 2001 From: Kamil Hornicek Date: Wed, 17 Mar 2010 12:11:55 +0000 Subject: [PATCH 57/61] [WIN32K] When adding new glyph cache entry convert the glyph bitmap with proper alignment to comply with the new code in EngCreateBitmap and remove the corresponding hack from SURFMEM_bCreateDib. [FREETYPE] When doing 1BPP -> 8BPP conversion set all 8 bits not only the LSB. (Freetype devs were notified of this issue) See issue #5244 for more details. svn path=/trunk/; revision=46246 --- reactos/drivers/video/font/ftfd/freetype.def | 3 + .../lib/3rdparty/freetype/src/base/ftbitmap.c | 18 ++-- reactos/subsystems/win32/win32k/eng/surface.c | 3 - .../win32/win32k/objects/freetype.c | 87 +++++++++---------- 4 files changed, 53 insertions(+), 58 deletions(-) diff --git a/reactos/drivers/video/font/ftfd/freetype.def b/reactos/drivers/video/font/ftfd/freetype.def index 78f842588ee..883a977f464 100644 --- a/reactos/drivers/video/font/ftfd/freetype.def +++ b/reactos/drivers/video/font/ftfd/freetype.def @@ -1,5 +1,8 @@ LIBRARY ftfd.dll EXPORTS + FT_Bitmap_Convert + FT_Bitmap_Done + FT_Bitmap_New FT_Done_Face FT_Done_Glyph FT_Get_Char_Index diff --git a/reactos/lib/3rdparty/freetype/src/base/ftbitmap.c b/reactos/lib/3rdparty/freetype/src/base/ftbitmap.c index 4c1cdf21888..c847eb00d24 100644 --- a/reactos/lib/3rdparty/freetype/src/base/ftbitmap.c +++ b/reactos/lib/3rdparty/freetype/src/base/ftbitmap.c @@ -445,15 +445,15 @@ { FT_Int val = ss[0]; /* avoid a byte->int cast on each line */ + tt[0] = (FT_Byte)( ( val & 0x80 ) ? 0xff : 0); + tt[1] = (FT_Byte)( ( val & 0x40 ) ? 0xff : 0); + tt[2] = (FT_Byte)( ( val & 0x20 ) ? 0xff : 0); + tt[3] = (FT_Byte)( ( val & 0x10 ) ? 0xff : 0); + tt[4] = (FT_Byte)( ( val & 0x08 ) ? 0xff : 0); + tt[5] = (FT_Byte)( ( val & 0x04 ) ? 0xff : 0); + tt[6] = (FT_Byte)( ( val & 0x02 ) ? 0xff : 0); + tt[7] = (FT_Byte)( ( val & 0x01 ) ? 0xff : 0); - tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7 ); - tt[1] = (FT_Byte)( ( val & 0x40 ) >> 6 ); - tt[2] = (FT_Byte)( ( val & 0x20 ) >> 5 ); - tt[3] = (FT_Byte)( ( val & 0x10 ) >> 4 ); - tt[4] = (FT_Byte)( ( val & 0x08 ) >> 3 ); - tt[5] = (FT_Byte)( ( val & 0x04 ) >> 2 ); - tt[6] = (FT_Byte)( ( val & 0x02 ) >> 1 ); - tt[7] = (FT_Byte)( val & 0x01 ); tt += 8; ss += 1; @@ -468,7 +468,7 @@ for ( ; j > 0; j-- ) { - tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7); + tt[0] = (FT_Byte)( ( val & 0x80 ) ? 0xff : 0); val <<= 1; tt += 1; } diff --git a/reactos/subsystems/win32/win32k/eng/surface.c b/reactos/subsystems/win32/win32k/eng/surface.c index 126347bff98..464e7d0c3c1 100644 --- a/reactos/subsystems/win32/win32k/eng/surface.c +++ b/reactos/subsystems/win32/win32k/eng/surface.c @@ -613,9 +613,6 @@ SURFMEM_bCreateDib(IN PDEVBITMAPINFO BitmapInfo, /* For topdown, the base address starts with the bits */ pso->pvScan0 = pso->pvBits; pso->lDelta = ScanLine; - - /* Hack for FreeType/Font Rendering, cannot use the Aligned ScanLine */ - if (BitmapInfo->Format == BMF_1BPP) pso->lDelta = BitmapInfo->Width / 8; } else { diff --git a/reactos/subsystems/win32/win32k/objects/freetype.c b/reactos/subsystems/win32/win32k/objects/freetype.c index bdda9c20cc6..fea0c101ee9 100644 --- a/reactos/subsystems/win32/win32k/objects/freetype.c +++ b/reactos/subsystems/win32/win32k/objects/freetype.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -81,7 +82,7 @@ typedef struct _FONT_CACHE_ENTRY LIST_ENTRY ListEntry; int GlyphIndex; FT_Face Face; - FT_Glyph Glyph; + FT_BitmapGlyph BitmapGlyph; int Height; } FONT_CACHE_ENTRY, *PFONT_CACHE_ENTRY; static LIST_ENTRY FontCacheListHead; @@ -1349,7 +1350,7 @@ ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs) } -FT_Glyph APIENTRY +FT_BitmapGlyph APIENTRY ftGdiGlyphCacheGet( FT_Face Face, INT GlyphIndex, @@ -1376,10 +1377,10 @@ ftGdiGlyphCacheGet( RemoveEntryList(CurrentEntry); InsertHeadList(&FontCacheListHead, CurrentEntry); - return FontEntry->Glyph; + return FontEntry->BitmapGlyph; } -FT_Glyph APIENTRY +FT_BitmapGlyph APIENTRY ftGdiGlyphCacheSet( FT_Face Face, INT GlyphIndex, @@ -1390,6 +1391,8 @@ ftGdiGlyphCacheSet( FT_Glyph GlyphCopy; INT error; PFONT_CACHE_ENTRY NewEntry; + FT_Bitmap AlignedBitmap; + FT_BitmapGlyph BitmapGlyph; error = FT_Get_Glyph(GlyphSlot, &GlyphCopy); if (error) @@ -1397,6 +1400,7 @@ ftGdiGlyphCacheSet( DPRINT1("Failure caching glyph.\n"); return NULL; }; + error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1); if (error) { @@ -1412,22 +1416,34 @@ ftGdiGlyphCacheSet( return NULL; } + BitmapGlyph = (FT_BitmapGlyph)GlyphCopy; + FT_Bitmap_New(&AlignedBitmap); + if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4)) + { + DPRINT1("Conversion failed\n"); + FT_Done_Glyph((FT_Glyph)BitmapGlyph); + return NULL; + } + + FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap); + BitmapGlyph->bitmap = AlignedBitmap; + NewEntry->GlyphIndex = GlyphIndex; NewEntry->Face = Face; - NewEntry->Glyph = GlyphCopy; + NewEntry->BitmapGlyph = BitmapGlyph; NewEntry->Height = Height; InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry); if (FontCacheNumEntries++ > MAX_FONT_CACHE) { NewEntry = (PFONT_CACHE_ENTRY)FontCacheListHead.Blink; - FT_Done_Glyph(NewEntry->Glyph); + FT_Done_Glyph((FT_Glyph)NewEntry->BitmapGlyph); RemoveTailList(&FontCacheListHead); ExFreePool(NewEntry); FontCacheNumEntries--; } - return GlyphCopy; + return BitmapGlyph; } @@ -2112,7 +2128,7 @@ TextIntGetTextExtentPoint(PDC dc, PFONTGDI FontGDI; FT_Face face; FT_GlyphSlot glyph; - FT_Glyph realglyph; + FT_BitmapGlyph realglyph; INT error, n, glyph_index, i, previous; ULONGLONG TotalWidth = 0; FT_CharMap charmap, found = NULL; @@ -2208,7 +2224,7 @@ TextIntGetTextExtentPoint(PDC dc, TotalWidth += delta.x; } - TotalWidth += realglyph->advance.x >> 10; + TotalWidth += realglyph->root.advance.x >> 10; if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit) { @@ -3133,8 +3149,7 @@ GreExtTextOutW( int error, glyph_index, n, i; FT_Face face; FT_GlyphSlot glyph; - FT_Glyph realglyph; - FT_BitmapGlyph realglyph2; + FT_BitmapGlyph realglyph; LONGLONG TextLeft, RealXStart; ULONG TextTop, previous, BackgroundLeft; FT_Bool use_kerning; @@ -3400,7 +3415,7 @@ GreExtTextOutW( TextWidth += delta.x; } - TextWidth += realglyph->advance.x >> 10; + TextWidth += realglyph->root.advance.x >> 10; previous = glyph_index; TempText++; @@ -3475,26 +3490,12 @@ GreExtTextOutW( } DPRINT("TextLeft: %d\n", TextLeft); DPRINT("TextTop: %d\n", TextTop); - - if (realglyph->format == ft_glyph_format_outline) - { - DPRINT1("Should already be done\n"); -// error = FT_Render_Glyph(glyph, RenderMode); - error = FT_Glyph_To_Bitmap(&realglyph, RenderMode, 0, 0); - if (error) - { - DPRINT1("WARNING: Failed to render glyph!\n"); - goto fail2; - } - } - realglyph2 = (FT_BitmapGlyph)realglyph; - - DPRINT("Advance: %d\n", realglyph->advance.x); + DPRINT("Advance: %d\n", realglyph->root.advance.x); if (fuOptions & ETO_OPAQUE) { DestRect.left = BackgroundLeft; - DestRect.right = (TextLeft + (realglyph->advance.x >> 10) + 32) >> 6; + DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6; DestRect.top = TextTop + yoff - ((face->size->metrics.ascender + 32) >> 6); DestRect.bottom = TextTop + yoff + ((32 - face->size->metrics.descender) >> 6); IntEngBitBlt( @@ -3512,31 +3513,25 @@ GreExtTextOutW( BackgroundLeft = DestRect.right; } - DestRect.left = ((TextLeft + 32) >> 6) + realglyph2->left; - DestRect.right = DestRect.left + realglyph2->bitmap.width; - DestRect.top = TextTop + yoff - realglyph2->top; - DestRect.bottom = DestRect.top + realglyph2->bitmap.rows; + DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left; + DestRect.right = DestRect.left + realglyph->bitmap.width; + DestRect.top = TextTop + yoff - realglyph->top; + DestRect.bottom = DestRect.top + realglyph->bitmap.rows; - bitSize.cx = realglyph2->bitmap.width; - bitSize.cy = realglyph2->bitmap.rows; - MaskRect.right = realglyph2->bitmap.width; - MaskRect.bottom = realglyph2->bitmap.rows; + bitSize.cx = realglyph->bitmap.width; + bitSize.cy = realglyph->bitmap.rows; + MaskRect.right = realglyph->bitmap.width; + MaskRect.bottom = realglyph->bitmap.rows; /* * We should create the bitmap out of the loop at the biggest possible * glyph size. Then use memset with 0 to clear it and sourcerect to * limit the work of the transbitblt. - * - * FIXME: DIB bitmaps should have an lDelta which is a multiple of 4. - * Here we pass in the pitch from the FreeType bitmap, which is not - * guaranteed to be a multiple of 4. If it's not, we should expand - * the FreeType bitmap to a temporary bitmap. */ - HSourceGlyph = EngCreateBitmap(bitSize, realglyph2->bitmap.pitch, - (realglyph2->bitmap.pixel_mode == ft_pixel_mode_grays) ? - BMF_8BPP : BMF_1BPP, BMF_TOPDOWN, - realglyph2->bitmap.buffer); + HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch, + BMF_8BPP, BMF_TOPDOWN, + realglyph->bitmap.buffer); if ( !HSourceGlyph ) { DPRINT1("WARNING: EngLockSurface() failed!\n"); @@ -3590,7 +3585,7 @@ GreExtTextOutW( if (NULL == Dx) { - TextLeft += realglyph->advance.x >> 10; + TextLeft += realglyph->root.advance.x >> 10; DPRINT("new TextLeft: %d\n", TextLeft); } else From 69330a579525f6ff1638525fff93bca7b71cfcff Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Wed, 17 Mar 2010 13:12:46 +0000 Subject: [PATCH 58/61] [NTOS] Rewrite Trap exits stubs in raw assembly (2nd try) and remove inline assembly. Bugcheck in KiTrap0DHandler, when the fault was not handled. Replace code patching for sysexit vs iret with a function pointer. Slightly refactor KiSystemServiceHandler/KiFastCallEntryHanlder. Unroll the loop in the systemcall handler and use volatile keyword when reloading TrapFrame and DescriptorTable from the new stack after converting to gui thread to prevent the compiler from optimizing it away (or moving it out of the loop). Add an asm macro KiCallHandler, which expands to call on debug builds to make sure backtraces work as expected and to jmp on release builds for improved performance. Modify KiExitV86Trap to always exit and add DECLSPEC_NORETURN. Use __debugbreak() instead of while(TRUE) on errors in KiExitTrapDebugChecks. The old code hat 2 issues: one was restoring segments in KiExitV86Trap when they shouldn't be, leading to a bugcheck. And the other was a long hang (5 mintes or more) in 3rd stage on qemu when selecting RosDbg, caused by the KiFastCallExitHandler function pointer being initialized with a pointer to the iret handler. Initializing it in code solved the issue. To figure out why is left as an exercise to the reader. svn path=/trunk/; revision=46247 --- .../ntoskrnl/include/internal/i386/asmmacro.S | 156 ++++++- reactos/ntoskrnl/include/internal/trap_x.h | 380 ++---------------- reactos/ntoskrnl/ke/i386/cpu.c | 71 +--- reactos/ntoskrnl/ke/i386/trap.s | 15 +- reactos/ntoskrnl/ke/i386/traphdlr.c | 321 ++++++++------- 5 files changed, 397 insertions(+), 546 deletions(-) diff --git a/reactos/ntoskrnl/include/internal/i386/asmmacro.S b/reactos/ntoskrnl/include/internal/i386/asmmacro.S index d8ca99da594..6ddb9d015ad 100644 --- a/reactos/ntoskrnl/include/internal/i386/asmmacro.S +++ b/reactos/ntoskrnl/include/internal/i386/asmmacro.S @@ -179,6 +179,14 @@ set_sane_segs: mov fs, ax endif +#if DBG + /* Keep the frame chain intact */ + mov eax, [esp + KTRAP_FRAME_EIP] + mov [esp + KTRAP_FRAME_DEBUGEIP], eax + mov [esp + KTRAP_FRAME_DEBUGEBP], ebp + mov ebp, esp +#endif + /* Set parameter 1 (ECX) to point to the frame */ mov ecx, esp @@ -187,11 +195,157 @@ set_sane_segs: ENDM +MACRO(KiCallHandler, Handler) +#if DBG + /* Use a call to get the return address for back traces */ + call Handler +#else + /* Use the faster jmp */ + jmp Handler +#endif + nop +ENDM + MACRO(TRAP_ENTRY, Trap, Flags) EXTERN @&Trap&Handler@4 :PROC PUBLIC _&Trap _&Trap: KiEnterTrap Flags - jmp @&Trap&Handler@4 + KiCallHandler @&Trap&Handler@4 +ENDM + +#define KI_RESTORE_EAX HEX(001) +#define KI_RESTORE_ECX_EDX HEX(002) +#define KI_RESTORE_FS HEX(004) +#define KI_RESTORE_SEGMENTS HEX(008) +#define KI_RESTORE_EFLAGS HEX(010) +#define KI_EXIT_SYSCALL HEX(020) +#define KI_EXIT_JMP HEX(040) +#define KI_EXIT_RET HEX(080) +#define KI_EXIT_IRET HEX(100) +#define KI_EDITED_FRAME HEX(200) +#define KI_RESTORE_VOLATILES (KI_RESTORE_EAX OR KI_RESTORE_ECX_EDX) + +MACRO(KiTrapExitStub, Name, Flags) + +PUBLIC @&Name&@4 +@&Name&@4: + + if (Flags AND KI_RESTORE_EFLAGS) + + /* We will pop EFlags off the stack */ + OffsetEsp = KTRAP_FRAME_EFLAGS + + elseif (Flags AND KI_EXIT_IRET) + + /* This is the IRET frame */ + OffsetEsp = KTRAP_FRAME_EIP + + else + + OffsetEsp = 0 + + endif + + if (Flags AND KI_EDITED_FRAME) + + /* Load the requested ESP */ + mov esp, [ecx + KTRAP_FRAME_TEMPESP] + + /* Put return address on the new stack */ + push [ecx + KTRAP_FRAME_EIP] + + /* Put EFLAGS on the new stack */ + push [ecx + KTRAP_FRAME_EFLAGS] + + else + + /* Point esp to an appropriate member of the frame */ + lea esp, [ecx + OffsetEsp] + + endif + + /* Restore non volatiles */ + mov ebx, [ecx + KTRAP_FRAME_EBX] + mov esi, [ecx + KTRAP_FRAME_ESI] + mov edi, [ecx + KTRAP_FRAME_EDI] + mov ebp, [ecx + KTRAP_FRAME_EBP] + + if (Flags AND KI_RESTORE_EAX) + + /* Restore eax */ + mov eax, [ecx + KTRAP_FRAME_EAX] + + endif + + if (Flags AND KI_RESTORE_ECX_EDX) + + /* Restore volatiles */ + mov edx, [ecx + KTRAP_FRAME_EDX] + mov ecx, [ecx + KTRAP_FRAME_ECX] + + elseif (Flags AND KI_EXIT_JMP) + + /* Load return address into edx */ + mov edx, [esp - OffsetEsp + KTRAP_FRAME_EIP] + + elseif (Flags AND KI_EXIT_SYSCALL) + + /* Set sysexit parameters */ + mov edx, [esp - OffsetEsp + KTRAP_FRAME_EIP] + mov ecx, [esp - OffsetEsp + KTRAP_FRAME_ESP] + + /* Keep interrupts disabled until the sti / sysexit */ + and byte ptr [esp - OffsetEsp + KTRAP_FRAME_EFLAGS + 1], ~(EFLAGS_INTERRUPT_MASK >> 8) + + endif + + if (Flags AND KI_RESTORE_SEGMENTS) + + /* Restore segments for user mode */ + mov ds, [esp - OffsetEsp + KTRAP_FRAME_DS] + mov es, [esp - OffsetEsp + KTRAP_FRAME_ES] + mov gs, [esp - OffsetEsp + KTRAP_FRAME_GS] + + endif + + if ((Flags AND KI_RESTORE_FS) OR (Flags AND KI_RESTORE_SEGMENTS)) + + /* Restore user mode FS */ + mov fs, [esp - OffsetEsp + KTRAP_FRAME_FS] + + endif + + if (Flags AND KI_RESTORE_EFLAGS) + + /* Restore EFLAGS */ + popf + + endif + + if (Flags AND KI_EXIT_SYSCALL) + + /* Enable interrupts and return to user mode. + Both must follow directly after another to be "atomic". */ + sti + sysexit + + elseif (Flags AND KI_EXIT_IRET) + + /* Return with iret */ + iret + + elseif (Flags AND KI_EXIT_JMP) + + /* Return to kernel mode with a jmp */ + jmp edx + + elseif (Flags AND KI_EXIT_RET) + + /* Return to kernel mode with a ret */ + ret + + endif + ENDM diff --git a/reactos/ntoskrnl/include/internal/trap_x.h b/reactos/ntoskrnl/include/internal/trap_x.h index 26e39e4484b..93c5d1fc6c0 100644 --- a/reactos/ntoskrnl/include/internal/trap_x.h +++ b/reactos/ntoskrnl/include/internal/trap_x.h @@ -8,6 +8,8 @@ #pragma once +//#define TRAP_DEBUG 1 + // // Unreachable code hint for GCC 4.5.x, older GCC versions, and MSVC // @@ -23,6 +25,17 @@ #define UNREACHABLE #endif +// +// Helper Code +// +BOOLEAN +FORCEINLINE +KiUserTrap(IN PKTRAP_FRAME TrapFrame) +{ + /* Anything else but Ring 0 is Ring 3 */ + return (TrapFrame->SegCs & MODE_MASK); +} + // // Debug Macros // @@ -78,18 +91,19 @@ KiFillTrapFrameDebug(IN PKTRAP_FRAME TrapFrame) TrapFrame->DbgArgMark = 0xBADB0D00; TrapFrame->DbgEip = TrapFrame->Eip; TrapFrame->DbgEbp = TrapFrame->Ebp; + TrapFrame->PreviousPreviousMode = -1; } VOID FORCEINLINE KiExitTrapDebugChecks(IN PKTRAP_FRAME TrapFrame, - IN KTRAP_STATE_BITS SkipBits) + IN KTRAP_EXIT_SKIP_BITS SkipBits) { /* Make sure interrupts are disabled */ if (__readeflags() & EFLAGS_INTERRUPT_MASK) { DbgPrint("Exiting with interrupts enabled: %lx\n", __readeflags()); - while (TRUE); + __debugbreak(); } /* Make sure this is a real trap frame */ @@ -97,35 +111,35 @@ KiExitTrapDebugChecks(IN PKTRAP_FRAME TrapFrame, { DbgPrint("Exiting with an invalid trap frame? (No MAGIC in trap frame)\n"); KiDumpTrapFrame(TrapFrame); - while (TRUE); + __debugbreak(); } /* Make sure we're not in user-mode or something */ if (Ke386GetFs() != KGDT_R0_PCR) { DbgPrint("Exiting with an invalid FS: %lx\n", Ke386GetFs()); - while (TRUE); + __debugbreak(); } /* Make sure we have a valid SEH chain */ if (KeGetPcr()->NtTib.ExceptionList == 0) { DbgPrint("Exiting with NULL exception chain: %p\n", KeGetPcr()->NtTib.ExceptionList); - while (TRUE); + __debugbreak(); } /* Make sure we're restoring a valid SEH chain */ if (TrapFrame->ExceptionList == 0) { DbgPrint("Entered a trap with a NULL exception chain: %p\n", TrapFrame->ExceptionList); - while (TRUE); + __debugbreak(); } /* If we're ignoring previous mode, make sure caller doesn't actually want it */ if ((SkipBits.SkipPreviousMode) && (TrapFrame->PreviousPreviousMode != -1)) { - DbgPrint("Exiting a trap witout restoring previous mode, yet previous mode seems valid: %lx", TrapFrame->PreviousPreviousMode); - while (TRUE); + DbgPrint("Exiting a trap witout restoring previous mode, yet previous mode seems valid: %lx\n", TrapFrame->PreviousPreviousMode); + __debugbreak(); } } @@ -137,14 +151,14 @@ KiExitSystemCallDebugChecks(IN ULONG SystemCall, KIRQL OldIrql; /* Check if this was a user call */ - if (KiUserMode(TrapFrame)) + if (KiUserTrap(TrapFrame)) { /* Make sure we are not returning with elevated IRQL */ OldIrql = KeGetCurrentIrql(); if (OldIrql != PASSIVE_LEVEL) { /* Forcibly put us in a sane state */ - KeGetPcr()->CurrentIrql = PASSIVE_LEVEL; + KeGetPcr()->Irql = PASSIVE_LEVEL; _disable(); /* Fail */ @@ -154,7 +168,7 @@ KiExitSystemCallDebugChecks(IN ULONG SystemCall, 0, 0); } - +#if 0 /* Make sure we're not attached and that APCs are not disabled */ if ((KeGetCurrentThread()->ApcStateIndex != CurrentApcEnvironment) || (KeGetCurrentThread()->CombinedApcDisable != 0)) @@ -166,6 +180,7 @@ KiExitSystemCallDebugChecks(IN ULONG SystemCall, KeGetCurrentThread()->CombinedApcDisable, 0); } +#endif } } #else @@ -174,340 +189,29 @@ KiExitSystemCallDebugChecks(IN ULONG SystemCall, #define KiExitSystemCallDebugChecks(x, y) #endif -// -// Helper Code -// -BOOLEAN -FORCEINLINE -KiUserTrap(IN PKTRAP_FRAME TrapFrame) -{ - /* Anything else but Ring 0 is Ring 3 */ - return (TrapFrame->SegCs & MODE_MASK); -} - -// -// "BOP" code used by VDM and V8086 Mode -// -VOID -FORCEINLINE -KiIssueBop(VOID) -{ - /* Invalid instruction that an invalid opcode handler must trap and handle */ - asm volatile(".byte 0xC4\n.byte 0xC4\n"); -} - -VOID -FORCEINLINE -KiUserSystemCall(IN PKTRAP_FRAME TrapFrame) -{ - /* - * Kernel call or user call? - * - * This decision is made in inlined assembly because we need to patch - * the relative offset of the user-mode jump to point to the SYSEXIT - * routine if the CPU supports it. The only way to guarantee that a - * relative jnz/jz instruction is generated is to force it with the - * inline assembler. - */ - asm volatile - ( - "test $1, %0\n" /* MODE_MASK */ - ".globl _KiSystemCallExitBranch\n_KiSystemCallExitBranch:\n" - "jnz _KiSystemCallExit\n" - : - : "r"(TrapFrame->SegCs) - ); -} - -// -// Generates an Exit Epilog Stub for the given name -// -#define KI_FUNCTION_CALL 0x1 -#define KI_EDITED_FRAME 0x2 -#define KI_DIRECT_EXIT 0x4 -#define KI_FAST_SYSTEM_CALL_EXIT 0x8 -#define KI_SYSTEM_CALL_EXIT 0x10 -#define KI_SYSTEM_CALL_JUMP 0x20 -#define KiTrapExitStub(x, y) VOID FORCEINLINE DECLSPEC_NORETURN x(IN PKTRAP_FRAME TrapFrame) { KiTrapExit(TrapFrame, y); UNREACHABLE; } -#define KiTrapExitStub2(x, y) VOID FORCEINLINE x(IN PKTRAP_FRAME TrapFrame) { KiTrapExit(TrapFrame, y); } - -// -// How volatiles will be restored -// -#define KI_EAX_NO_VOLATILES 0x0 -#define KI_EAX_ONLY 0x1 -#define KI_ALL_VOLATILES 0x2 - -// -// Exit mechanism to use -// -#define KI_EXIT_IRET 0x0 -#define KI_EXIT_SYSEXIT 0x1 -#define KI_EXIT_JMP 0x2 -#define KI_EXIT_RET 0x3 - -// -// Master Trap Epilog -// -VOID -FORCEINLINE -KiTrapExit(IN PKTRAP_FRAME TrapFrame, - IN ULONG Flags) -{ - ULONG FrameSize = FIELD_OFFSET(KTRAP_FRAME, Eip); - ULONG ExitMechanism = KI_EXIT_IRET, Volatiles = KI_ALL_VOLATILES, NonVolatiles = TRUE; - ULONG EcxField = FIELD_OFFSET(KTRAP_FRAME, Ecx), EdxField = FIELD_OFFSET(KTRAP_FRAME, Edx); - - /* System call exit needs a special label */ - if (Flags & KI_SYSTEM_CALL_EXIT) __asm__ __volatile__ - ( - ".globl _KiSystemCallExit\n_KiSystemCallExit:\n" - ); - - /* Start by making the trap frame equal to the stack */ - __asm__ __volatile__ - ( - "movl %0, %%esp\n" - : - : "r"(TrapFrame) - : "%esp" - ); - - /* Check what kind of trap frame this trap requires */ - if (Flags & KI_FUNCTION_CALL) - { - /* These calls have an EIP on the stack they need */ - ExitMechanism = KI_EXIT_RET; - Volatiles = FALSE; - } - else if (Flags & KI_EDITED_FRAME) - { - /* Edited frames store a new ESP in the error code field */ - FrameSize = FIELD_OFFSET(KTRAP_FRAME, ErrCode); - } - else if (Flags & KI_DIRECT_EXIT) - { - /* Exits directly without restoring anything, interrupt frame on stack */ - NonVolatiles = Volatiles = FALSE; - } - else if (Flags & KI_FAST_SYSTEM_CALL_EXIT) - { - /* We have a fake interrupt stack with a ring transition */ - FrameSize = FIELD_OFFSET(KTRAP_FRAME, V86Es); - ExitMechanism = KI_EXIT_SYSEXIT; - - /* SYSEXIT wants EIP in EDX and ESP in ECX */ - EcxField = FIELD_OFFSET(KTRAP_FRAME, HardwareEsp); - EdxField = FIELD_OFFSET(KTRAP_FRAME, Eip); - } - else if (Flags & KI_SYSTEM_CALL_EXIT) - { - /* Only restore EAX */ - NonVolatiles = KI_EAX_ONLY; - } - else if (Flags & KI_SYSTEM_CALL_JUMP) - { - /* We have a fake interrupt stack with no ring transition */ - FrameSize = FIELD_OFFSET(KTRAP_FRAME, HardwareEsp); - NonVolatiles = KI_EAX_ONLY; - ExitMechanism = KI_EXIT_JMP; - } - - /* Restore the non volatiles */ - if (NonVolatiles) __asm__ __volatile__ - ( - "movl %c[b](%%esp), %%ebx\n" - "movl %c[s](%%esp), %%esi\n" - "movl %c[i](%%esp), %%edi\n" - "movl %c[p](%%esp), %%ebp\n" - : - : [b] "i"(FIELD_OFFSET(KTRAP_FRAME, Ebx)), - [s] "i"(FIELD_OFFSET(KTRAP_FRAME, Esi)), - [i] "i"(FIELD_OFFSET(KTRAP_FRAME, Edi)), - [p] "i"(FIELD_OFFSET(KTRAP_FRAME, Ebp)) - : "%esp" - ); - - /* Restore EAX if volatiles must be restored */ - if (Volatiles) __asm__ __volatile__ - ( - "movl %c[a](%%esp), %%eax\n":: [a] "i"(FIELD_OFFSET(KTRAP_FRAME, Eax)) : "%esp" - ); - - /* Restore the other volatiles if needed */ - if (Volatiles == KI_ALL_VOLATILES) __asm__ __volatile__ - ( - "movl %c[c](%%esp), %%ecx\n" - "movl %c[d](%%esp), %%edx\n" - : - : [c] "i"(EcxField), - [d] "i"(EdxField) - : "%esp" - ); - - /* Ring 0 system calls jump back to EDX */ - if (Flags & KI_SYSTEM_CALL_JUMP) __asm__ __volatile__ - ( - "movl %c[d](%%esp), %%edx\n":: [d] "i"(FIELD_OFFSET(KTRAP_FRAME, Eip)) : "%esp" - ); - - /* Now destroy the trap frame on the stack */ - __asm__ __volatile__ ("addl $%c[e],%%esp\n":: [e] "i"(FrameSize) : "%esp"); - - /* Edited traps need to change to a new ESP */ - if (Flags & KI_EDITED_FRAME) __asm__ __volatile__ ("movl (%%esp), %%esp\n":::"%esp"); - - /* Check the exit mechanism and apply it */ - if (ExitMechanism == KI_EXIT_RET) __asm__ __volatile__("ret\n"::: "%esp"); - else if (ExitMechanism == KI_EXIT_IRET) __asm__ __volatile__("iret\n"::: "%esp"); - else if (ExitMechanism == KI_EXIT_JMP) __asm__ __volatile__("jmp *%%edx\n.globl _KiSystemCallExit2\n_KiSystemCallExit2:\n"::: "%esp"); - else if (ExitMechanism == KI_EXIT_SYSEXIT) __asm__ __volatile__("sti\nsysexit\n"::: "%esp"); -} - -// -// All the specific trap epilog stubs -// -KiTrapExitStub (KiTrapReturn, 0); -KiTrapExitStub (KiDirectTrapReturn, KI_DIRECT_EXIT); -KiTrapExitStub (KiCallReturn, KI_FUNCTION_CALL); -KiTrapExitStub (KiEditedTrapReturn, KI_EDITED_FRAME); -KiTrapExitStub2(KiSystemCallReturn, KI_SYSTEM_CALL_JUMP); -KiTrapExitStub (KiSystemCallSysExitReturn, KI_FAST_SYSTEM_CALL_EXIT); -KiTrapExitStub (KiSystemCallTrapReturn, KI_SYSTEM_CALL_EXIT); - // // Generic Exit Routine // +VOID FASTCALL DECLSPEC_NORETURN KiSystemCallReturn(IN PKTRAP_FRAME TrapFrame); +VOID FASTCALL DECLSPEC_NORETURN KiSystemCallSysExitReturn(IN PKTRAP_FRAME TrapFrame); +VOID FASTCALL DECLSPEC_NORETURN KiSystemCallTrapReturn(IN PKTRAP_FRAME TrapFrame); +VOID FASTCALL DECLSPEC_NORETURN KiEditedTrapReturn(IN PKTRAP_FRAME TrapFrame); +VOID FASTCALL DECLSPEC_NORETURN KiTrapReturn(IN PKTRAP_FRAME TrapFrame); +VOID FASTCALL DECLSPEC_NORETURN KiTrapReturnNoSegments(IN PKTRAP_FRAME TrapFrame); + +typedef VOID -FORCEINLINE -DECLSPEC_NORETURN -KiExitTrap(IN PKTRAP_FRAME TrapFrame, - IN UCHAR Skip) -{ - KTRAP_EXIT_SKIP_BITS SkipBits = { .Bits = Skip }; - PULONG ReturnStack; - - /* Debugging checks */ - KiExitTrapDebugChecks(TrapFrame, SkipBits); +(FASTCALL +*PFAST_SYSTEM_CALL_EXIT)(IN PKTRAP_FRAME TrapFrame) DECLSPEC_NORETURN; - /* Restore the SEH handler chain */ - KeGetPcr()->NtTib.ExceptionList = TrapFrame->ExceptionList; - - /* Check if the previous mode must be restored */ - if (__builtin_expect(!SkipBits.SkipPreviousMode, 0)) /* More INTS than SYSCALLs */ - { - /* Restore it */ - KeGetCurrentThread()->PreviousMode = TrapFrame->PreviousPreviousMode; - } - - /* Check if there are active debug registers */ - if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0)) - { - /* Not handled yet */ - DbgPrint("Need Hardware Breakpoint Support!\n"); - DbgBreakPoint(); - while (TRUE); - } - - /* Check if this was a V8086 trap */ - if (__builtin_expect(TrapFrame->EFlags & EFLAGS_V86_MASK, 0)) KiTrapReturn(TrapFrame); - - /* Check if the trap frame was edited */ - if (__builtin_expect(!(TrapFrame->SegCs & FRAME_EDITED), 0)) - { - /* - * An edited trap frame happens when we need to modify CS and/or ESP but - * don't actually have a ring transition. This happens when a kernelmode - * caller wants to perform an NtContinue to another kernel address, such - * as in the case of SEH (basically, a longjmp), or to a user address. - * - * Therefore, the CPU never saved CS/ESP on the stack because we did not - * get a trap frame due to a ring transition (there was no interrupt). - * Even if we didn't want to restore CS to a new value, a problem occurs - * due to the fact a normal RET would not work if we restored ESP since - * RET would then try to read the result off the stack. - * - * The NT kernel solves this by adding 12 bytes of stack to the exiting - * trap frame, in which EFLAGS, CS, and EIP are stored, and then saving - * the ESP that's being requested into the ErrorCode field. It will then - * exit with an IRET. This fixes both issues, because it gives the stack - * some space where to hold the return address and then end up with the - * wanted stack, and it uses IRET which allows a new CS to be inputted. - * - */ - - /* Set CS that is requested */ - TrapFrame->SegCs = TrapFrame->TempSegCs; - - /* First make space on requested stack */ - ReturnStack = (PULONG)(TrapFrame->TempEsp - 12); - TrapFrame->ErrCode = (ULONG_PTR)ReturnStack; - - /* Now copy IRET frame */ - ReturnStack[0] = TrapFrame->Eip; - ReturnStack[1] = TrapFrame->SegCs; - ReturnStack[2] = TrapFrame->EFlags; - - /* Do special edited return */ - KiEditedTrapReturn(TrapFrame); - } - - /* Check if this is a user trap */ - if (__builtin_expect(KiUserTrap(TrapFrame), 1)) /* Ring 3 is where we spend time */ - { - /* Check if segments should be restored */ - if (!SkipBits.SkipSegments) - { - /* Restore segments */ - Ke386SetGs(TrapFrame->SegGs); - Ke386SetEs(TrapFrame->SegEs); - Ke386SetDs(TrapFrame->SegDs); - Ke386SetFs(TrapFrame->SegFs); - } - - /* Always restore FS since it goes from KPCR to TEB */ - Ke386SetFs(TrapFrame->SegFs); - } - - /* Check for system call -- a system call skips volatiles! */ - if (__builtin_expect(SkipBits.SkipVolatiles, 0)) /* More INTs than SYSCALLs */ - { - /* User or kernel call? */ - KiUserSystemCall(TrapFrame); - - /* Restore EFLags */ - __writeeflags(TrapFrame->EFlags); - - /* Call is kernel, so do a jump back since this wasn't a real INT */ - KiSystemCallReturn(TrapFrame); - - /* If we got here, this is SYSEXIT: are we stepping code? */ - if (!(TrapFrame->EFlags & EFLAGS_TF)) - { - /* Restore user FS */ - Ke386SetFs(KGDT_R3_TEB | RPL_MASK); - - /* Remove interrupt flag */ - TrapFrame->EFlags &= ~EFLAGS_INTERRUPT_MASK; - __writeeflags(TrapFrame->EFlags); - - /* Exit through SYSEXIT */ - KiSystemCallSysExitReturn(TrapFrame); - } - - /* Exit through IRETD, either due to debugging or due to lack of SYSEXIT */ - KiSystemCallTrapReturn(TrapFrame); - } - - /* Return from interrupt */ - KiTrapReturn(TrapFrame); -} +extern PFAST_SYSTEM_CALL_EXIT KiFastCallExitHandler; // // Virtual 8086 Mode Optimized Trap Exit // VOID FORCEINLINE +DECLSPEC_NORETURN KiExitV86Trap(IN PKTRAP_FRAME TrapFrame) { PKTHREAD Thread; @@ -517,6 +221,9 @@ KiExitV86Trap(IN PKTRAP_FRAME TrapFrame) Thread = KeGetCurrentThread(); while (TRUE) { + /* Return if this isn't V86 mode anymore */ + if (!(TrapFrame->EFlags & EFLAGS_V86_MASK)) KiEoiHelper(TrapFrame);; + /* Turn off the alerted state for kernel mode */ Thread->Alerted[KernelMode] = FALSE; @@ -533,9 +240,6 @@ KiExitV86Trap(IN PKTRAP_FRAME TrapFrame) /* Restore IRQL and disable interrupts once again */ KfLowerIrql(OldIrql); _disable(); - - /* Return if this isn't V86 mode anymore */ - if (__builtin_expect(TrapFrame->EFlags & EFLAGS_V86_MASK, 0)) return; } /* If we got here, we're still in a valid V8086 context, so quit it */ @@ -547,7 +251,7 @@ KiExitV86Trap(IN PKTRAP_FRAME TrapFrame) } /* Return from interrupt */ - KiTrapReturn(TrapFrame); + KiTrapReturnNoSegments(TrapFrame); } // diff --git a/reactos/ntoskrnl/ke/i386/cpu.c b/reactos/ntoskrnl/ke/i386/cpu.c index 21d49c90123..49055b7ca21 100644 --- a/reactos/ntoskrnl/ke/i386/cpu.c +++ b/reactos/ntoskrnl/ke/i386/cpu.c @@ -995,56 +995,6 @@ KiLoadFastSyscallMachineSpecificRegisters(IN ULONG_PTR Context) return 0; } -VOID -NTAPI -KiDisableFastSyscallReturn(VOID) -{ - /* Was it applied? */ - if (KiSystemCallExitAdjusted) - { - /* Restore the original value */ - KiSystemCallExitBranch[1] = KiSystemCallExitBranch[1] - KiSystemCallExitAdjusted; - - /* It's not adjusted anymore */ - KiSystemCallExitAdjusted = FALSE; - } -} - -VOID -NTAPI -KiEnableFastSyscallReturn(VOID) -{ - /* Check if the patch has already been done */ - if ((KiSystemCallExitAdjusted == KiSystemCallExitAdjust) && - (KiFastCallCopyDoneOnce)) - { - return; - } - - /* Make sure the offset is within the distance of a Jxx SHORT */ - if ((KiSystemCallExitBranch[1] - KiSystemCallExitAdjust) < 0x80) - { - /* Remove any existing code patch */ - KiDisableFastSyscallReturn(); - - /* We should have a JNZ there */ - ASSERT(KiSystemCallExitBranch[0] == 0x75); - - /* Do the patch */ - KiSystemCallExitAdjusted = KiSystemCallExitAdjust; - KiSystemCallExitBranch[1] -= KiSystemCallExitAdjusted; - - /* Remember that we've done it */ - KiFastCallCopyDoneOnce = TRUE; - } - else - { - /* This shouldn't happen unless we've messed the macros up */ - DPRINT1("Your compiled kernel is broken!\n"); - DbgBreakPoint(); - } -} - VOID NTAPI KiRestoreFastSyscallReturnState(VOID) @@ -1055,28 +1005,19 @@ KiRestoreFastSyscallReturnState(VOID) /* Check if it has been disabled */ if (!KiFastSystemCallDisable) { - /* KiSystemCallExit2 should come BEFORE KiSystemCallExit */ - ASSERT(KiSystemCallExit2 < KiSystemCallExit); - - /* It's enabled, so we'll have to do a code patch */ - KiSystemCallExitAdjust = KiSystemCallExit - KiSystemCallExit2; + /* Do an IPI to enable it */ + KeIpiGenericCall(KiLoadFastSyscallMachineSpecificRegisters, 0); + + /* It's enabled, so use the proper exit stub */ + KiFastCallExitHandler = KiSystemCallSysExitReturn; } else { /* Disable fast system call */ KeFeatureBits &= ~KF_FAST_SYSCALL; + KiFastCallExitHandler = KiSystemCallTrapReturn; } } - - /* Now check if all CPUs support fast system call, and the registry allows it */ - if (KeFeatureBits & KF_FAST_SYSCALL) - { - /* Do an IPI to enable it */ - KeIpiGenericCall(KiLoadFastSyscallMachineSpecificRegisters, 0); - } - - /* Perform the code patch that is required */ - KiEnableFastSyscallReturn(); } ULONG_PTR diff --git a/reactos/ntoskrnl/ke/i386/trap.s b/reactos/ntoskrnl/ke/i386/trap.s index 5f24877eeac..adfcd322dd9 100644 --- a/reactos/ntoskrnl/ke/i386/trap.s +++ b/reactos/ntoskrnl/ke/i386/trap.s @@ -124,13 +124,13 @@ EXTERN @KiSystemServiceHandler@8:PROC PUBLIC _KiSystemService _KiSystemService: KiEnterTrap (KI_PUSH_FAKE_ERROR_CODE OR KI_NONVOLATILES_ONLY OR KI_DONT_SAVE_SEGS) - jmp @KiSystemServiceHandler@8 + KiCallHandler @KiSystemServiceHandler@8 EXTERN @KiFastCallEntryHandler@8:PROC PUBLIC _KiFastCallEntry _KiFastCallEntry: KiEnterTrap (KI_FAST_SYSTEM_CALL OR KI_NONVOLATILES_ONLY OR KI_DONT_SAVE_SEGS) - jmp @KiFastCallEntryHandler@8 + KiCallHandler @KiFastCallEntryHandler@8 PUBLIC _KiStartUnexpectedRange@0 _KiStartUnexpectedRange@0: @@ -143,4 +143,15 @@ PUBLIC _KiEndUnexpectedRange@0 _KiEndUnexpectedRange@0: jmp _KiUnexpectedInterruptTail + +/* EXIT CODE *****************************************************************/ + +KiTrapExitStub KiSystemCallReturn, (KI_RESTORE_EAX OR KI_RESTORE_EFLAGS OR KI_EXIT_JMP) +KiTrapExitStub KiSystemCallSysExitReturn, (KI_RESTORE_EAX OR KI_RESTORE_FS OR KI_RESTORE_EFLAGS OR KI_EXIT_SYSCALL) +KiTrapExitStub KiSystemCallTrapReturn, (KI_RESTORE_EAX OR KI_RESTORE_FS OR KI_EXIT_IRET) + +KiTrapExitStub KiEditedTrapReturn, (KI_RESTORE_VOLATILES OR KI_RESTORE_EFLAGS OR KI_EDITED_FRAME OR KI_EXIT_RET) +KiTrapExitStub KiTrapReturn, (KI_RESTORE_VOLATILES OR KI_RESTORE_SEGMENTS OR KI_EXIT_IRET) +KiTrapExitStub KiTrapReturnNoSegments, (KI_RESTORE_VOLATILES OR KI_EXIT_IRET) + END diff --git a/reactos/ntoskrnl/ke/i386/traphdlr.c b/reactos/ntoskrnl/ke/i386/traphdlr.c index f85eb7f878c..f9a954ec298 100644 --- a/reactos/ntoskrnl/ke/i386/traphdlr.c +++ b/reactos/ntoskrnl/ke/i386/traphdlr.c @@ -45,6 +45,11 @@ UCHAR KiTrapIoTable[] = 0x6F, /* OUTS */ }; +PFAST_SYSTEM_CALL_EXIT KiFastCallExitHandler; + + +/* TRAP EXIT CODE *************************************************************/ + BOOLEAN FORCEINLINE KiVdmTrap(IN PKTRAP_FRAME TrapFrame) @@ -62,12 +67,18 @@ KiV86Trap(IN PKTRAP_FRAME TrapFrame) return ((TrapFrame->EFlags & EFLAGS_V86_MASK) != 0); } -/* TRAP EXIT CODE *************************************************************/ +BOOLEAN +FORCEINLINE +KiIsFrameEdited(IN PKTRAP_FRAME TrapFrame) +{ + /* An edited frame changes esp. It is marked by clearing the bits + defined by FRAME_EDITED in the SegCs field of the trap frame */ + return ((TrapFrame->SegCs & FRAME_EDITED) == 0); +} VOID -FASTCALL -DECLSPEC_NORETURN -KiEoiHelper(IN PKTRAP_FRAME TrapFrame) +FORCEINLINE +KiCommonExit(IN PKTRAP_FRAME TrapFrame, const ULONG Flags) { /* Disable interrupts until we return */ _disable(); @@ -75,8 +86,41 @@ KiEoiHelper(IN PKTRAP_FRAME TrapFrame) /* Check for APC delivery */ KiCheckForApcDelivery(TrapFrame); - /* Now exit the trap for real */ - KiExitTrap(TrapFrame, KTE_SKIP_PM_BIT); + /* Debugging checks */ + KiExitTrapDebugChecks(TrapFrame, Flags); + + /* Restore the SEH handler chain */ + KeGetPcr()->NtTib.ExceptionList = TrapFrame->ExceptionList; + + /* Check if there are active debug registers */ + if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0)) + { + /* Not handled yet */ + DbgPrint("Need Hardware Breakpoint Support!\n"); + DbgBreakPoint(); + while (TRUE); + } +} + +VOID +FASTCALL +DECLSPEC_NORETURN +KiEoiHelper(IN PKTRAP_FRAME TrapFrame) +{ + /* Common trap exit code */ + KiCommonExit(TrapFrame, 0); + + /* Check if this was a V8086 trap */ + if (TrapFrame->EFlags & EFLAGS_V86_MASK) KiTrapReturnNoSegments(TrapFrame); + + /* Check for user mode exit */ + if (TrapFrame->SegCs & MODE_MASK) KiTrapReturn(TrapFrame); + + /* Check for edited frame */ + if (KiIsFrameEdited(TrapFrame)) KiEditedTrapReturn(TrapFrame); + + /* Exit the trap to kernel mode */ + KiTrapReturnNoSegments(TrapFrame); } VOID @@ -85,17 +129,36 @@ DECLSPEC_NORETURN KiServiceExit(IN PKTRAP_FRAME TrapFrame, IN NTSTATUS Status) { - /* Disable interrupts until we return */ - _disable(); - - /* Check for APC delivery */ - KiCheckForApcDelivery(TrapFrame); + ASSERT((TrapFrame->EFlags & EFLAGS_V86_MASK) == 0); + ASSERT(!KiIsFrameEdited(TrapFrame)); /* Copy the status into EAX */ TrapFrame->Eax = Status; - /* Now exit the trap for real */ - KiExitTrap(TrapFrame, KTE_SKIP_SEG_BIT | KTE_SKIP_VOL_BIT); + /* Common trap exit code */ + KiCommonExit(TrapFrame, 0); + + /* Restore previous mode */ + KeGetCurrentThread()->PreviousMode = TrapFrame->PreviousPreviousMode; + + /* Check for user mode exit */ + if (TrapFrame->SegCs & MODE_MASK) + { + /* Check if we were single stepping */ + if (TrapFrame->EFlags & EFLAGS_TF) + { + /* Must use the IRET handler */ + KiSystemCallTrapReturn(TrapFrame); + } + else + { + /* We can use the sysexit handler */ + KiFastCallExitHandler(TrapFrame); + } + } + + /* Exit to kernel mode */ + KiSystemCallReturn(TrapFrame); } VOID @@ -103,16 +166,26 @@ FASTCALL DECLSPEC_NORETURN KiServiceExit2(IN PKTRAP_FRAME TrapFrame) { - /* Disable interrupts until we return */ - _disable(); + /* Common trap exit code */ + KiCommonExit(TrapFrame, 0); - /* Check for APC delivery */ - KiCheckForApcDelivery(TrapFrame); + /* Restore previous mode */ + KeGetCurrentThread()->PreviousMode = TrapFrame->PreviousPreviousMode; - /* Now exit the trap for real */ - KiExitTrap(TrapFrame, 0); + /* Check if this was a V8086 trap */ + if (TrapFrame->EFlags & EFLAGS_V86_MASK) KiTrapReturnNoSegments(TrapFrame); + + /* Check for user mode exit */ + if (TrapFrame->SegCs & MODE_MASK) KiTrapReturn(TrapFrame); + + /* Check for edited frame */ + if (KiIsFrameEdited(TrapFrame)) KiEditedTrapReturn(TrapFrame); + + /* Exit the trap to kernel mode */ + KiTrapReturnNoSegments(TrapFrame); } + /* TRAP HANDLERS **************************************************************/ VOID @@ -582,10 +655,7 @@ KiTrap06Handler(IN PKTRAP_FRAME TrapFrame) _disable(); /* Do a quick V86 exit if possible */ - if (__builtin_expect(TrapFrame->EFlags & EFLAGS_V86_MASK, 1)) KiExitV86Trap(TrapFrame); - - /* Exit trap the slow way */ - KiEoiHelper(TrapFrame); + KiExitV86Trap(TrapFrame); } /* Save trap frame */ @@ -842,10 +912,7 @@ KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame) _disable(); /* Do a quick V86 exit if possible */ - if (__builtin_expect(TrapFrame->EFlags & EFLAGS_V86_MASK, 1)) KiExitV86Trap(TrapFrame); - - /* Exit trap the slow way */ - KiEoiHelper(TrapFrame); + KiExitV86Trap(TrapFrame); } /* Save trap frame */ @@ -909,7 +976,7 @@ KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame) (((Instructions[i + 2] & 0x38) == 0x10) || // LLDT (Instructions[i + 2] == 0x18))) || // LTR ((Instructions[i + 1] == 0x01) && // LGDT or LIDT or LMSW - (((Instructions[i + 2] & 0x38) == 0x10) || // LLGT + (((Instructions[i + 2] & 0x38) == 0x10) || // LGDT (Instructions[i + 2] == 0x18) || // LIDT (Instructions[i + 2] == 0x30))) || // LMSW (Instructions[i + 1] == 0x08) || // INVD @@ -921,6 +988,7 @@ KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame) (Instructions[i + 1] == 0x24) || // MOV YYY, DR (Instructions[i + 1] == 0x30) || // WRMSR (Instructions[i + 1] == 0x33)) // RDPMC + // INVLPG, INVLPGA, SYSRET { /* These are all privileged */ Privileged = TRUE; @@ -993,7 +1061,7 @@ KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame) * a POP , which could cause an invalid segment if someone had messed * with the segment values. * - * Another case is a bogus SS, which would hit a GPF when doing the ired. + * Another case is a bogus SS, which would hit a GPF when doing the iret. * This could only be done through a buggy or malicious driver, or perhaps * the kernel debugger. * @@ -1067,9 +1135,14 @@ KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame) /* Fix it */ TrapFrame->SegEs = (KGDT_R3_DATA | RPL_MASK); } - - /* Do a direct trap exit: restore volatiles only */ - KiExitTrap(TrapFrame, KTE_SKIP_PM_BIT | KTE_SKIP_SEG_BIT); + else + { + /* Whatever it is, we can't handle it */ + KiSystemFatalException(EXCEPTION_GP_FAULT, TrapFrame); + } + + /* Return to where we came from */ + KiTrapReturn(TrapFrame); } VOID @@ -1377,55 +1450,89 @@ KiDebugServiceHandler(IN PKTRAP_FRAME TrapFrame) } VOID -FASTCALL +FORCEINLINE DECLSPEC_NORETURN -KiSystemCall(IN ULONG SystemCallNumber, +KiSystemCall(IN PKTRAP_FRAME TrapFrame, IN PVOID Arguments) { PKTHREAD Thread; - PKTRAP_FRAME TrapFrame; PKSERVICE_TABLE_DESCRIPTOR DescriptorTable; ULONG Id, Offset, StackBytes, Result; PVOID Handler; + ULONG SystemCallNumber = TrapFrame->Eax; - /* Loop because we might need to try this twice in case of a GUI call */ - while (TRUE) + /* Get the current thread */ + Thread = KeGetCurrentThread(); + + /* Set debug header */ + KiFillTrapFrameDebug(TrapFrame); + + /* Chain trap frames */ + TrapFrame->Edx = (ULONG_PTR)Thread->TrapFrame; + + /* No error code */ + TrapFrame->ErrCode = 0; + + /* Save previous mode */ + TrapFrame->PreviousPreviousMode = Thread->PreviousMode; + + /* Save the SEH chain and terminate it for now */ + TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList; + KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END; + + /* Clear DR7 and check for debugging */ + TrapFrame->Dr7 = 0; + if (__builtin_expect(Thread->DispatcherHeader.DebugActive & 0xFF, 0)) { - /* Decode the system call number */ - Offset = (SystemCallNumber >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK; - Id = SystemCallNumber & SERVICE_NUMBER_MASK; + UNIMPLEMENTED; + while (TRUE); + } + + /* Set thread fields */ + Thread->TrapFrame = TrapFrame; + Thread->PreviousMode = KiUserTrap(TrapFrame); + + /* Enable interrupts */ + _enable(); + + /* Decode the system call number */ + Offset = (SystemCallNumber >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK; + Id = SystemCallNumber & SERVICE_NUMBER_MASK; - /* Get current thread, trap frame, and descriptor table */ - Thread = KeGetCurrentThread(); - TrapFrame = Thread->TrapFrame; - DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset); + /* Get descriptor table */ + DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset); - /* Validate the system call number */ - if (__builtin_expect(Id >= DescriptorTable->Limit, 0)) + /* Validate the system call number */ + if (__builtin_expect(Id >= DescriptorTable->Limit, 0)) + { + /* Check if this is a GUI call */ + if (!(Offset & SERVICE_TABLE_TEST)) { - /* Check if this is a GUI call */ - if (__builtin_expect(!(Offset & SERVICE_TABLE_TEST), 0)) - { - /* Fail the call */ - Result = STATUS_INVALID_SYSTEM_SERVICE; - goto ExitCall; - } - - /* Convert us to a GUI thread -- must wrap in ASM to get new EBP */ - Result = KiConvertToGuiThread(); - if (__builtin_expect(!NT_SUCCESS(Result), 0)) - { - /* Figure out how we should fail to the user */ - UNIMPLEMENTED; - while (TRUE); - } - - /* Try the call again */ - continue; + /* Fail the call */ + Result = STATUS_INVALID_SYSTEM_SERVICE; + goto ExitCall; } + + /* Convert us to a GUI thread -- must wrap in ASM to get new EBP */ + Result = KiConvertToGuiThread(); + if (!NT_SUCCESS(Result)) + { + /* Set the last error and fail */ + //SetLastWin32Error(RtlNtStatusToDosError(Result)); + goto ExitCall; + } + + /* Reload trap frame and descriptor table pointer from new stack */ + TrapFrame = *(volatile PVOID*)&Thread->TrapFrame; + DescriptorTable = (PVOID)(*(volatile ULONG_PTR*)&Thread->ServiceTable + Offset); - /* If we made it here, the call is good */ - break; + /* Validate the system call number again */ + if (Id >= DescriptorTable->Limit) + { + /* Fail the call */ + Result = STATUS_INVALID_SYSTEM_SERVICE; + goto ExitCall; + } } /* Check if this is a GUI call */ @@ -1468,45 +1575,13 @@ ExitCall: } VOID -FORCEINLINE +FASTCALL DECLSPEC_NORETURN -KiSystemCallHandler(IN PKTRAP_FRAME TrapFrame, - IN ULONG ServiceNumber, - IN PVOID Arguments, - IN PKTHREAD Thread, - IN KPROCESSOR_MODE PreviousMode, - IN KPROCESSOR_MODE PreviousPreviousMode, - IN USHORT SegFs) +KiSystemServiceHandler(IN PKTRAP_FRAME TrapFrame, + IN PVOID Arguments) { - /* No error code */ - TrapFrame->ErrCode = 0; - - /* Save previous mode and FS segment */ - TrapFrame->PreviousPreviousMode = PreviousPreviousMode; - TrapFrame->SegFs = SegFs; - - /* Save the SEH chain and terminate it for now */ - TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList; - KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END; - - /* Clear DR7 and check for debugging */ - TrapFrame->Dr7 = 0; - if (__builtin_expect(Thread->DispatcherHeader.DebugActive & 0xFF, 0)) - { - UNIMPLEMENTED; - while (TRUE); - } - - /* Set thread fields */ - Thread->TrapFrame = TrapFrame; - Thread->PreviousMode = PreviousMode; - - /* Set debug header */ - KiFillTrapFrameDebug(TrapFrame); - - /* Enable interrupts and make the call */ - _enable(); - KiSystemCall(ServiceNumber, Arguments); + /* Call the shared handler (inline) */ + KiSystemCall(TrapFrame, Arguments); } VOID @@ -1515,54 +1590,20 @@ DECLSPEC_NORETURN KiFastCallEntryHandler(IN PKTRAP_FRAME TrapFrame, IN PVOID Arguments) { - PKTHREAD Thread; - /* Set up a fake INT Stack and enable interrupts */ TrapFrame->HardwareSegSs = KGDT_R3_DATA | RPL_MASK; TrapFrame->HardwareEsp = (ULONG_PTR)Arguments; TrapFrame->EFlags = __readeflags() | EFLAGS_INTERRUPT_MASK; TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK; TrapFrame->Eip = SharedUserData->SystemCallReturn; + TrapFrame->SegFs = KGDT_R3_TEB | RPL_MASK; __writeeflags(0x2); - /* Get the current thread */ - Thread = KeGetCurrentThread(); - /* Arguments are actually 2 frames down (because of the double indirection) */ Arguments = (PVOID)(TrapFrame->HardwareEsp + 8); /* Call the shared handler (inline) */ - KiSystemCallHandler(TrapFrame, - TrapFrame->Eax, - Arguments, - Thread, - UserMode, - Thread->PreviousMode, - KGDT_R3_TEB | RPL_MASK); -} - -VOID -FASTCALL -DECLSPEC_NORETURN -KiSystemServiceHandler(IN PKTRAP_FRAME TrapFrame, - IN PVOID Arguments) -{ - PKTHREAD Thread; - - /* Get the current thread */ - Thread = KeGetCurrentThread(); - - /* Chain trap frames */ - TrapFrame->Edx = (ULONG_PTR)Thread->TrapFrame; - - /* Call the shared handler (inline) */ - KiSystemCallHandler(TrapFrame, - TrapFrame->Eax, - Arguments, - Thread, - KiUserTrap(TrapFrame), - Thread->PreviousMode, - TrapFrame->SegFs); + KiSystemCall(TrapFrame, Arguments); } /* From 1dd7c3a8e0897313f96e663af95d558b8b5312fb Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Wed, 17 Mar 2010 16:17:16 +0000 Subject: [PATCH 59/61] [NTOS] I forgot to set the exit function for systems without sysenter/sysexit support. Should fix sysreg. svn path=/trunk/; revision=46250 --- reactos/ntoskrnl/ke/i386/cpu.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/reactos/ntoskrnl/ke/i386/cpu.c b/reactos/ntoskrnl/ke/i386/cpu.c index 49055b7ca21..9434259f104 100644 --- a/reactos/ntoskrnl/ke/i386/cpu.c +++ b/reactos/ntoskrnl/ke/i386/cpu.c @@ -1018,6 +1018,11 @@ KiRestoreFastSyscallReturnState(VOID) KiFastCallExitHandler = KiSystemCallTrapReturn; } } + else + { + /* Use the IRET handler */ + KiFastCallExitHandler = KiSystemCallTrapReturn; + } } ULONG_PTR From f891c7f43b5ed8b389d46ee665079dd3875a3e13 Mon Sep 17 00:00:00 2001 From: Christoph von Wittich Date: Wed, 17 Mar 2010 16:20:55 +0000 Subject: [PATCH 60/61] [USER32] reduce diff to wine svn path=/trunk/; revision=46251 --- reactos/dll/win32/user32/windows/menu.c | 591 +++++++++++------------- 1 file changed, 269 insertions(+), 322 deletions(-) diff --git a/reactos/dll/win32/user32/windows/menu.c b/reactos/dll/win32/user32/windows/menu.c index c90dbd6fbcc..58c4a95243e 100644 --- a/reactos/dll/win32/user32/windows/menu.c +++ b/reactos/dll/win32/user32/windows/menu.c @@ -268,6 +268,157 @@ MenuCleanupAllRosMenuItemInfo(PROSMENUITEMINFO ItemInfo) HeapFree(GetProcessHeap(), 0, ItemInfo); } +/*********************************************************************** + * MenuInitSysMenuPopup + * + * Grey the appropriate items in System menu. + */ +void FASTCALL MenuInitSysMenuPopup(HMENU hmenu, DWORD style, DWORD clsStyle, LONG HitTest ) +{ + BOOL gray; + UINT DefItem; + #if 0 + MENUITEMINFOW mii; + #endif + + gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE)); + EnableMenuItem( hmenu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) ); + gray = ((style & WS_MAXIMIZE) != 0); + EnableMenuItem( hmenu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) ); + gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE); + EnableMenuItem( hmenu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) ); + gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE); + EnableMenuItem( hmenu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) ); + gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE)); + EnableMenuItem( hmenu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) ); + gray = (clsStyle & CS_NOCLOSE) != 0; + + /* The menu item must keep its state if it's disabled */ + if(gray) + EnableMenuItem( hmenu, SC_CLOSE, MF_GRAYED); + + /* Set default menu item */ + if(style & WS_MINIMIZE) DefItem = SC_RESTORE; + else if(HitTest == HTCAPTION) DefItem = ((style & (WS_MAXIMIZE | WS_MINIMIZE)) ? SC_RESTORE : SC_MAXIMIZE); + else DefItem = SC_CLOSE; +#if 0 + mii.cbSize = sizeof(MENUITEMINFOW); + mii.fMask |= MIIM_STATE; + if((DefItem != SC_CLOSE) && GetMenuItemInfoW(hmenu, DefItem, FALSE, &mii) && + (mii.fState & (MFS_GRAYED | MFS_DISABLED))) DefItem = SC_CLOSE; +#endif + SetMenuDefaultItem(hmenu, DefItem, MF_BYCOMMAND); +} + +/****************************************************************************** + * + * UINT MenuGetStartOfNextColumn( + * PROSMENUINFO MenuInfo) + * + *****************************************************************************/ +static UINT MenuGetStartOfNextColumn( + PROSMENUINFO MenuInfo) +{ + PROSMENUITEMINFO MenuItems; + UINT i; + + i = MenuInfo->FocusedItem; + if ( i == NO_SELECTED_ITEM ) + return i; + + if (MenuGetAllRosMenuItemInfo(MenuInfo->Self, &MenuItems) <= 0) + return NO_SELECTED_ITEM; + + for (i++ ; i < MenuInfo->MenuItemCount; i++) + if (0 != (MenuItems[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK))) + return i; + + return NO_SELECTED_ITEM; +} + +/****************************************************************************** + * + * UINT MenuGetStartOfPrevColumn( + * PROSMENUINFO MenuInfo) + * + *****************************************************************************/ + +static UINT FASTCALL MenuGetStartOfPrevColumn( + PROSMENUINFO MenuInfo) +{ + PROSMENUITEMINFO MenuItems; + UINT i; + + if (!MenuInfo->FocusedItem || MenuInfo->FocusedItem == NO_SELECTED_ITEM) + return NO_SELECTED_ITEM; + + if (MenuGetAllRosMenuItemInfo(MenuInfo->Self, &MenuItems) <= 0) + return NO_SELECTED_ITEM; + + /* Find the start of the column */ + for (i = MenuInfo->FocusedItem; + 0 != i && 0 == (MenuItems[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK)); + --i) + { + ; /* empty */ + } + + if (i == 0) + { + MenuCleanupAllRosMenuItemInfo(MenuItems); + return NO_SELECTED_ITEM; + } + + for (--i; 0 != i; --i) + if (MenuItems[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK)) + break; + + MenuCleanupAllRosMenuItemInfo(MenuItems); + TRACE("ret %d.\n", i ); + + return i; +} + +/*********************************************************************** + * MenuFindSubMenu + * + * Find a Sub menu. Return the position of the submenu, and modifies + * *hmenu in case it is found in another sub-menu. + * If the submenu cannot be found, NO_SELECTED_ITEM is returned. + */ +static UINT FASTCALL MenuFindSubMenu(HMENU *hmenu, HMENU hSubTarget ) +{ + ROSMENUINFO menu; + UINT i; + ROSMENUITEMINFO item; + if (((*hmenu)==(HMENU)0xffff) || + (!MenuGetRosMenuInfo(&menu, *hmenu))) + return NO_SELECTED_ITEM; + + MenuInitRosMenuItemInfo(&item); + for (i = 0; i < menu.MenuItemCount; i++) { + if (! MenuGetRosMenuItemInfo(menu.Self, i, &item)) + { + MenuCleanupRosMenuItemInfo(&item); + return NO_SELECTED_ITEM; + } + if (!(item.fType & MF_POPUP)) continue; + if (item.hSubMenu == hSubTarget) { + MenuCleanupRosMenuItemInfo(&item); + return i; + } + else { + HMENU hsubmenu = item.hSubMenu; + UINT pos = MenuFindSubMenu(&hsubmenu, hSubTarget ); + if (pos != NO_SELECTED_ITEM) { + *hmenu = hsubmenu; + return pos; + } + } + } + MenuCleanupRosMenuItemInfo(&item); + return NO_SELECTED_ITEM; +} /*********************************************************************** * MenuLoadBitmaps @@ -349,49 +500,6 @@ MenuDrawPopupGlyph(HDC dc, LPRECT r, INT_PTR popupMagic, BOOL inactive, BOOL hil DeleteObject(hFont); } -/*********************************************************************** - * MenuFindSubMenu - * - * Find a Sub menu. Return the position of the submenu, and modifies - * *hmenu in case it is found in another sub-menu. - * If the submenu cannot be found, NO_SELECTED_ITEM is returned. - */ -static UINT FASTCALL MenuFindSubMenu(HMENU *hmenu, HMENU hSubTarget ) -{ - ROSMENUINFO menu; - UINT i; - ROSMENUITEMINFO item; - - if (((*hmenu)==(HMENU)0xffff) || - (!MenuGetRosMenuInfo(&menu, *hmenu))) - return NO_SELECTED_ITEM; - - MenuInitRosMenuItemInfo(&item); - for (i = 0; i < menu.MenuItemCount; i++) - { - if (! MenuGetRosMenuItemInfo(menu.Self, i, &item)) - { - MenuCleanupRosMenuItemInfo(&item); - return NO_SELECTED_ITEM; - } - if (!(item.fType & MF_POPUP)) continue; - if (item.hSubMenu == hSubTarget) { - MenuCleanupRosMenuItemInfo(&item); - return i; - } - else { - HMENU hsubmenu = item.hSubMenu; - UINT pos = MenuFindSubMenu(&hsubmenu, hSubTarget ); - if (pos != NO_SELECTED_ITEM) { - *hmenu = hsubmenu; - return pos; - } - } - } - MenuCleanupRosMenuItemInfo(&item); - return NO_SELECTED_ITEM; -} - /*********************************************************************** * MenuFindItemByKey * @@ -2120,66 +2228,6 @@ DrawMenuBarTemp(HWND Wnd, HDC DC, LPRECT Rect, HMENU Menu, HFONT Font) return MenuInfo.Height; } -/*********************************************************************** - * MenuInitSysMenuPopup - * - * Grey the appropriate items in System menu. - */ -void FASTCALL -MenuInitSysMenuPopup(HMENU Menu, DWORD Style, DWORD ClsStyle, LONG HitTest ) -{ - BOOL Gray; - UINT DefItem; - #if 0 - MENUITEMINFOW mii; - #endif - - Gray = 0 == (Style & WS_THICKFRAME) || 0 != (Style & (WS_MAXIMIZE | WS_MINIMIZE)); - EnableMenuItem(Menu, SC_SIZE, (Gray ? MF_GRAYED : MF_ENABLED)); - Gray = 0 != (Style & WS_MAXIMIZE); - EnableMenuItem(Menu, SC_MOVE, (Gray ? MF_GRAYED : MF_ENABLED)); - Gray = 0 == (Style & WS_MINIMIZEBOX) || 0 != (Style & WS_MINIMIZE); - EnableMenuItem(Menu, SC_MINIMIZE, (Gray ? MF_GRAYED : MF_ENABLED)); - Gray = 0 == (Style & WS_MAXIMIZEBOX) || 0 != (Style & WS_MAXIMIZE); - EnableMenuItem(Menu, SC_MAXIMIZE, (Gray ? MF_GRAYED : MF_ENABLED)); - Gray = 0 == (Style & (WS_MAXIMIZE | WS_MINIMIZE)); - EnableMenuItem(Menu, SC_RESTORE, (Gray ? MF_GRAYED : MF_ENABLED)); - Gray = 0 != (ClsStyle & CS_NOCLOSE); - - /* The menu item must keep its state if it's disabled */ - if (Gray) - { - EnableMenuItem(Menu, SC_CLOSE, MF_GRAYED); - } - - /* Set default menu item */ - if(Style & WS_MINIMIZE) - { - DefItem = SC_RESTORE; - } - else - { - if(HitTest == HTCAPTION) - { - DefItem = ((Style & (WS_MAXIMIZE | WS_MINIMIZE)) ? SC_RESTORE : SC_MAXIMIZE); - } - else - { - DefItem = SC_CLOSE; - } - } - #if 0 - mii.cbSize = sizeof(MENUITEMINFOW); - mii.fMask |= MIIM_STATE; - if((DefItem != SC_CLOSE) && GetMenuItemInfoW(Menu, DefItem, FALSE, &mii) && - (mii.fState & (MFS_GRAYED | MFS_DISABLED))) - { - DefItem = SC_CLOSE; - } - #endif - SetMenuDefaultItem(Menu, DefItem, MF_BYCOMMAND); -} - /*********************************************************************** * MenuShowSubPopup * @@ -2676,86 +2724,6 @@ MenuMouseMove(MTRACKER *Mt, HMENU PtMenu, UINT Flags) return TRUE; } -/****************************************************************************** - * - * UINT MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo) - */ -static UINT MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo) -{ - UINT i; - PROSMENUITEMINFO MenuItems; - - i = MenuInfo->FocusedItem; - if (NO_SELECTED_ITEM == i) - { - return i; - } - - if (MenuGetAllRosMenuItemInfo(MenuInfo->Self, &MenuItems) <= 0) - { - return NO_SELECTED_ITEM; - } - - for (i++ ; i < MenuInfo->MenuItemCount; i++) - { - if (0 != (MenuItems[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK))) - { - return i; - } - } - - return NO_SELECTED_ITEM; -} - -/****************************************************************************** - * - * UINT MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo) - */ -static UINT FASTCALL -MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo) -{ - UINT i; - PROSMENUITEMINFO MenuItems; - - if (0 == MenuInfo->FocusedItem || NO_SELECTED_ITEM == MenuInfo->FocusedItem) - { - return NO_SELECTED_ITEM; - } - - if (MenuGetAllRosMenuItemInfo(MenuInfo->Self, &MenuItems) <= 0) - { - return NO_SELECTED_ITEM; - } - - /* Find the start of the column */ - - for (i = MenuInfo->FocusedItem; - 0 != i && 0 == (MenuItems[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK)); - --i) - { - ; /* empty */ - } - - if (0 == i) - { - MenuCleanupAllRosMenuItemInfo(MenuItems); - return NO_SELECTED_ITEM; - } - - for (--i; 0 != i; --i) - { - if (MenuItems[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK)) - { - break; - } - } - - MenuCleanupAllRosMenuItemInfo(MenuItems); - TRACE("ret %d.\n", i ); - - return i; -} - /*********************************************************************** * MenuGetSubPopup * @@ -3252,138 +3220,138 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, switch(msg.message) { - /* no WM_NC... messages in captured state */ + /* no WM_NC... messages in captured state */ - case WM_RBUTTONDBLCLK: - case WM_RBUTTONDOWN: - if (!(wFlags & TPM_RIGHTBUTTON)) break; - /* fall through */ - case WM_LBUTTONDBLCLK: - case WM_LBUTTONDOWN: - /* If the message belongs to the menu, removes it from the queue */ - /* Else, end menu tracking */ - fRemove = MenuButtonDown(&mt, hmenu, wFlags); - fEndMenu = !fRemove; - break; + case WM_RBUTTONDBLCLK: + case WM_RBUTTONDOWN: + if (!(wFlags & TPM_RIGHTBUTTON)) break; + /* fall through */ + case WM_LBUTTONDBLCLK: + case WM_LBUTTONDOWN: + /* If the message belongs to the menu, removes it from the queue */ + /* Else, end menu tracking */ + fRemove = MenuButtonDown(&mt, hmenu, wFlags); + fEndMenu = !fRemove; + break; - case WM_RBUTTONUP: - if (!(wFlags & TPM_RIGHTBUTTON)) break; - /* fall through */ - case WM_LBUTTONUP: - /* Check if a menu was selected by the mouse */ - if (hmenu) - { - executedMenuId = MenuButtonUp( &mt, hmenu, wFlags); + case WM_RBUTTONUP: + if (!(wFlags & TPM_RIGHTBUTTON)) break; + /* fall through */ + case WM_LBUTTONUP: + /* Check if a menu was selected by the mouse */ + if (hmenu) + { + executedMenuId = MenuButtonUp( &mt, hmenu, wFlags); /* End the loop if executedMenuId is an item ID */ /* or if the job was done (executedMenuId = 0). */ - fEndMenu = fRemove = (executedMenuId != -1); - } - else - { + fEndMenu = fRemove = (executedMenuId != -1); + } /* No menu was selected by the mouse */ /* if the function was called by TrackPopupMenu, continue with the menu tracking. If not, stop it */ - fEndMenu = ((wFlags & TPM_POPUPMENU) ? FALSE : TRUE); - } - break; + else + fEndMenu = ((wFlags & TPM_POPUPMENU) ? FALSE : TRUE); - case WM_MOUSEMOVE: - if (hmenu) - fEndMenu |= !MenuMouseMove(&mt, hmenu, wFlags); - break; + break; - } /* switch(Msg.message) - mouse */ - } - else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST)) - { - fRemove = TRUE; /* Keyboard messages are always removed */ - switch(msg.message) + case WM_MOUSEMOVE: + /* the selected menu item must be changed every time */ + /* the mouse moves. */ + + if (hmenu) + fEndMenu |= !MenuMouseMove( &mt, hmenu, wFlags ); + break; + + } /* switch(msg.message) - mouse */ + } + else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST)) + { + fRemove = TRUE; /* Keyboard messages are always removed */ + switch(msg.message) { - case WM_SYSKEYDOWN: - case WM_KEYDOWN: + case WM_KEYDOWN: + case WM_SYSKEYDOWN: switch(msg.wParam) - { + { case VK_MENU: - fEndMenu = TRUE; - break; + case VK_F10: + fEndMenu = TRUE; + break; + case VK_HOME: case VK_END: - if (MenuGetRosMenuInfo(&MenuInfo, mt.CurrentMenu)) + if (MenuGetRosMenuInfo(&MenuInfo, mt.CurrentMenu)) { - MenuSelectItem(mt.OwnerWnd, &MenuInfo, NO_SELECTED_ITEM, - FALSE, 0 ); - MenuMoveSelection(mt.OwnerWnd, &MenuInfo, - VK_HOME == msg.wParam ? ITEM_NEXT : ITEM_PREV); + MenuSelectItem(mt.OwnerWnd, &MenuInfo, + NO_SELECTED_ITEM, FALSE, 0 ); + MenuMoveSelection(mt.OwnerWnd, &MenuInfo, + VK_HOME == msg.wParam ? ITEM_NEXT : ITEM_PREV); } - break; + break; case VK_UP: case VK_DOWN: /* If on menu bar, pull-down the menu */ - if (MenuGetRosMenuInfo(&MenuInfo, mt.CurrentMenu)) + if (MenuGetRosMenuInfo(&MenuInfo, mt.CurrentMenu)) { - if (!(MenuInfo.Flags & MF_POPUP)) + if (!(MenuInfo.Flags & MF_POPUP)) { - if (MenuGetRosMenuInfo(&MenuInfo, mt.TopMenu)) - { - mt.CurrentMenu = MenuShowSubPopup(mt.OwnerWnd, &MenuInfo, - TRUE, wFlags); - } - } - else /* otherwise try to move selection */ - { - MenuMoveSelection(mt.OwnerWnd, &MenuInfo, - VK_DOWN == msg.wParam ? ITEM_NEXT : ITEM_PREV); + if (MenuGetRosMenuInfo(&MenuInfo, mt.TopMenu)) + mt.CurrentMenu = MenuShowSubPopup(mt.OwnerWnd, &MenuInfo, TRUE, wFlags); } + else /* otherwise try to move selection */ + MenuMoveSelection(mt.OwnerWnd, &MenuInfo, + (msg.wParam == VK_UP)? ITEM_PREV : ITEM_NEXT ); } - break; + break; case VK_LEFT: - MenuKeyLeft(&mt, wFlags); - break; + MenuKeyLeft( &mt, wFlags ); + break; case VK_RIGHT: - MenuKeyRight(&mt, wFlags); - break; + MenuKeyRight( &mt, wFlags ); + break; case VK_ESCAPE: - fEndMenu = MenuKeyEscape(&mt, wFlags); - break; + fEndMenu = MenuKeyEscape(&mt, wFlags); + break; case VK_F1: - { + { HELPINFO hi; hi.cbSize = sizeof(HELPINFO); hi.iContextType = HELPINFO_MENUITEM; if (MenuGetRosMenuInfo(&MenuInfo, mt.CurrentMenu)) - { - if (MenuInfo.FocusedItem == NO_SELECTED_ITEM) hi.iCtrlId = 0; + { + if (MenuInfo.FocusedItem == NO_SELECTED_ITEM) + hi.iCtrlId = 0; else - { + { MenuInitRosMenuItemInfo(&ItemInfo); if (MenuGetRosMenuItemInfo(MenuInfo.Self, MenuInfo.FocusedItem, &ItemInfo)) - { + { hi.iCtrlId = ItemInfo.wID; - } + } else - { + { hi.iCtrlId = 0; - } + } MenuCleanupRosMenuItemInfo(&ItemInfo); - } - } + } + } hi.hItemHandle = hmenu; hi.dwContextId = MenuInfo.dwContextHelpID; hi.MousePos = msg.pt; - SendMessageW(hwnd, WM_HELP, 0, (LPARAM) &hi); + SendMessageW(hwnd, WM_HELP, 0, (LPARAM)&hi); break; - } + } default: - break; - } + break; + } break; /* WM_KEYDOWN */ case WM_CHAR: @@ -3638,6 +3606,43 @@ track_menu: } +/********************************************************************** + * TrackPopupMenuEx (USER32.@) + */ +BOOL WINAPI TrackPopupMenuEx( HMENU Menu, UINT Flags, int x, int y, + HWND Wnd, LPTPMPARAMS Tpm) +{ + /* Not fully implemented */ + return TrackPopupMenu(Menu, Flags, x, y, 0, Wnd, + NULL != Tpm ? &Tpm->rcExclude : NULL); +} + +/********************************************************************** + * TrackPopupMenu (USER32.@) + */ +BOOL WINAPI TrackPopupMenu( HMENU Menu, UINT Flags, int x, int y, + int Reserved, HWND Wnd, CONST RECT *Rect) +{ + BOOL ret = FALSE; + + if (!IsMenu(Menu)) + { + SetLastError( ERROR_INVALID_MENU_HANDLE ); + return FALSE; + } + + MenuInitTracking(Wnd, Menu, TRUE, Flags); + + /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */ + if (!(Flags & TPM_NONOTIFY)) + SendMessageW(Wnd, WM_INITMENUPOPUP, (WPARAM) Menu, 0); + + if (MenuShowPopup(Wnd, Menu, 0, Flags, x, y, 0, 0 )) + ret = MenuTrackMenu(Menu, Flags | TPM_POPUPMENU, 0, 0, Wnd, Rect); + MenuExitTracking(Wnd); + return ret; +} + /* * From MSDN: * The MFT_BITMAP, MFT_SEPARATOR, and MFT_STRING values cannot be combined @@ -4992,64 +4997,6 @@ SetSystemMenu ( return NtUserSetSystemMenu(hwnd, hMenu); } - -/* - * @implemented - */ -BOOL -WINAPI -TrackPopupMenu( - HMENU Menu, - UINT Flags, - int x, - int y, - int Reserved, - HWND Wnd, - CONST RECT *Rect) -{ - BOOL ret = FALSE; - - if (!IsMenu(Menu)) - { - SetLastError( ERROR_INVALID_MENU_HANDLE ); - return FALSE; - } - - MenuInitTracking(Wnd, Menu, TRUE, Flags); - - /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */ - if (0 == (Flags & TPM_NONOTIFY)) - { - SendMessageW(Wnd, WM_INITMENUPOPUP, (WPARAM) Menu, 0); - } - - if (MenuShowPopup(Wnd, Menu, 0, Flags, x, y, 0, 0 )) - { - ret = MenuTrackMenu(Menu, Flags | TPM_POPUPMENU, 0, 0, Wnd, Rect); - } - MenuExitTracking(Wnd); - return ret; -} - - -/* - * @unimplemented - */ -BOOL -WINAPI -TrackPopupMenuEx( - HMENU Menu, - UINT Flags, - int x, - int y, - HWND Wnd, - LPTPMPARAMS Tpm) -{ - /* Not fully implemented */ - return TrackPopupMenu(Menu, Flags, x, y, 0, Wnd, - NULL != Tpm ? &Tpm->rcExclude : NULL); -} - // // Example for the Win32/User32 rewrite. // Def = TrackPopupMenuEx@24=NtUserTrackPopupMenuEx@24 From 814940c42b29a6c054ecc75343f9eafc466ae608 Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Wed, 17 Mar 2010 21:26:04 +0000 Subject: [PATCH 61/61] [NTOS] Add DPRINTs to tell if SYSENTER is detected. Requested by Christoph for testing the test machine. svn path=/trunk/; revision=46253 --- reactos/ntoskrnl/ke/i386/cpu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/reactos/ntoskrnl/ke/i386/cpu.c b/reactos/ntoskrnl/ke/i386/cpu.c index 9434259f104..e05a8960470 100644 --- a/reactos/ntoskrnl/ke/i386/cpu.c +++ b/reactos/ntoskrnl/ke/i386/cpu.c @@ -1010,18 +1010,21 @@ KiRestoreFastSyscallReturnState(VOID) /* It's enabled, so use the proper exit stub */ KiFastCallExitHandler = KiSystemCallSysExitReturn; + DPRINT1("Support for SYSENTER detected.\n"); } else { /* Disable fast system call */ KeFeatureBits &= ~KF_FAST_SYSCALL; KiFastCallExitHandler = KiSystemCallTrapReturn; + DPRINT1("Support for SYSENTER disabled.\n"); } } else { /* Use the IRET handler */ KiFastCallExitHandler = KiSystemCallTrapReturn; + DPRINT1("No support for SYSENTER detected.\n"); } }