From: Mohamad Al-Jaf mohamadaljaf@gmail.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53747 --- .../main.c | 113 +++++++++++++++++- .../private.h | 38 ++++++ .../tests/smbios.c | 4 +- 3 files changed, 151 insertions(+), 4 deletions(-)
diff --git a/dlls/windows.system.profile.systemmanufacturers/main.c b/dlls/windows.system.profile.systemmanufacturers/main.c index 35b4529ad7a..c4fa36f5216 100644 --- a/dlls/windows.system.profile.systemmanufacturers/main.c +++ b/dlls/windows.system.profile.systemmanufacturers/main.c @@ -128,10 +128,119 @@ static const struct IActivationFactoryVtbl factory_vtbl =
DEFINE_IINSPECTABLE( statics, ISmbiosInformationStatics, struct smbios_statics, IActivationFactory_iface )
+static const struct smbios_header *find_smbios_entry( enum smbios_type type, const char *buf, UINT len ) +{ + const struct smbios_prologue *prologue; + const struct smbios_header *hdr; + const char *ptr, *start; + + if (len < sizeof(struct smbios_prologue)) return NULL; + prologue = (const struct smbios_prologue *)buf; + if (prologue->length > len - sizeof(*prologue) || prologue->length < sizeof(*hdr)) return NULL; + + start = (const char *)(prologue + 1); + hdr = (const struct smbios_header *)start; + + for (;;) + { + if ((const char *)hdr - start >= prologue->length - sizeof(*hdr)) return NULL; + + if (!hdr->length) + { + WARN( "invalid entry\n" ); + return NULL; + } + + if (hdr->type == type) + { + if ((const char *)hdr - start + hdr->length > prologue->length) return NULL; + break; + } + else /* skip other entries and their strings */ + { + for (ptr = (const char *)hdr + hdr->length; ptr - buf < len && *ptr; ptr++) + { + for (; ptr - buf < len; ptr++) if (!*ptr) break; + } + if (ptr == (const char *)hdr + hdr->length) ptr++; + hdr = (const struct smbios_header *)(ptr + 1); + } + } + + return hdr; +} + +static inline WCHAR *heap_strdupAW( const char *src ) +{ + WCHAR *dst; + int len; + if (!src) return NULL; + len = MultiByteToWideChar( CP_ACP, 0, src, -1, NULL, 0 ); + if ((dst = HeapAlloc( GetProcessHeap(), 0, len * sizeof(*dst) ))) MultiByteToWideChar( CP_ACP, 0, src, -1, dst, len ); + return dst; +} + +static WCHAR *get_smbios_string( BYTE id, const char *buf, UINT offset, UINT buflen ) +{ + const char *ptr = buf + offset; + UINT i = 0; + + if (!id || offset >= buflen) return NULL; + for (ptr = buf + offset; ptr - buf < buflen && *ptr; ptr++) + { + if (++i == id) return heap_strdupAW( ptr ); + for (; ptr - buf < buflen; ptr++) if (!*ptr) break; + } + return NULL; +} + +static WCHAR *get_bios_system_serial( const char *buf, UINT len ) +{ + const struct smbios_system *system; + const struct smbios_header *hdr; + UINT offset; + + if (!(hdr = find_smbios_entry( SMBIOS_TYPE_SYSTEM, buf, len ))) return NULL; + system = (const struct smbios_system *)hdr; + offset = (const char *)system - buf + system->hdr.length; + + return get_smbios_string( system->serial, buf, offset, len ); +} + static HRESULT WINAPI statics_get_SerialNumber( ISmbiosInformationStatics *iface, HSTRING *value ) { - FIXME( "iface %p, value %p stub!\n", iface, value ); - return E_NOTIMPL; + WCHAR *serial; + HSTRING ret; + HRESULT hr; + char *buf; + UINT len; + + TRACE( "iface %p, value %p.\n", iface, value ); + + len = GetSystemFirmwareTable( RSMB, 0, NULL, 0 ); + if (!(buf = HeapAlloc( GetProcessHeap(), 0, len ))) + { + ERR( "Failed to allocate firmware table buffer.\n" ); + hr = E_OUTOFMEMORY; + goto error; + } + len = GetSystemFirmwareTable( RSMB, 0, buf, len ); + + serial = get_bios_system_serial( buf, len ); + if (!serial) + { + WARN( "Failed to get serial number, returning 0.\n" ); + serial = heap_strdupAW("0"); + } + + if (FAILED( hr = WindowsCreateString( serial, wcslen(serial), &ret ) )) goto done; + hr = WindowsDuplicateString( ret, value ); + WindowsDeleteString(ret); +done: + HeapFree( GetProcessHeap(), 0, serial ); +error: + HeapFree( GetProcessHeap(), 0, buf ); + return hr; }
static const struct ISmbiosInformationStaticsVtbl statics_vtbl = diff --git a/dlls/windows.system.profile.systemmanufacturers/private.h b/dlls/windows.system.profile.systemmanufacturers/private.h index 42c19710dcb..f6a5420a3cf 100644 --- a/dlls/windows.system.profile.systemmanufacturers/private.h +++ b/dlls/windows.system.profile.systemmanufacturers/private.h @@ -30,6 +30,44 @@ #define WIDL_using_Windows_System_Profile_SystemManufacturers #include "windows.system.profile.systemmanufacturers.h"
+struct smbios_prologue +{ + BYTE calling_method; + BYTE major_version; + BYTE minor_version; + BYTE revision; + DWORD length; +}; + +enum smbios_type +{ + SMBIOS_TYPE_BIOS, + SMBIOS_TYPE_SYSTEM, + SMBIOS_TYPE_BASEBOARD, +}; + +struct smbios_header +{ + BYTE type; + BYTE length; + WORD handle; +}; + +struct smbios_system +{ + struct smbios_header hdr; + BYTE vendor; + BYTE product; + BYTE version; + BYTE serial; + BYTE uuid[16]; + BYTE wake_up_type; + BYTE sku_number; + BYTE family; +}; + +#define RSMB (('R' << 24) | ('S' << 16) | ('M' << 8) | 'B') + #define DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from, iface_mem, expr ) \ static inline impl_type *impl_from( iface_type *iface ) \ { \ diff --git a/dlls/windows.system.profile.systemmanufacturers/tests/smbios.c b/dlls/windows.system.profile.systemmanufacturers/tests/smbios.c index 4b9f51a8fa1..c1baf71631e 100644 --- a/dlls/windows.system.profile.systemmanufacturers/tests/smbios.c +++ b/dlls/windows.system.profile.systemmanufacturers/tests/smbios.c @@ -73,11 +73,11 @@ static void test_Smbios_Statics(void) ok( hr == S_OK, "got hr %#lx.\n", hr );
hr = ISmbiosInformationStatics_get_SerialNumber( smbios_statics, &serial ); - todo_wine ok( hr == S_OK || broken(hr == E_UNEXPECTED), "got hr %#lx.\n", hr ); + ok( hr == S_OK || broken(hr == E_UNEXPECTED), "got hr %#lx.\n", hr ); if (hr == S_OK) { buf = WindowsGetStringRawBuffer( serial, &len ); - todo_wine ok( buf != NULL && len > 0, "WindowsGetStringRawBuffer returned buf %p, len %u\n", buf, len ); + ok( buf != NULL && len > 0, "WindowsGetStringRawBuffer returned buf %p, len %u\n", buf, len ); WindowsDeleteString(serial); }