1. Особенности использования winapi не совсем по тематике форума. Надо гуглить самому.
Первая попавшаяся ссылка в гугулеhttps://stackoverflow.com/questions/48250004/how-to-get-a-serial-number-of-a-windows-disk

2. Биндинги к winapi в блэкбоке устаревшие и/или не полные. Всякую экзотику надо самому расковыривать из заголовков для сишки.
Иногда константы в заголовках очень запутано объявляются. Можно наgodboltпобыстрому посмотреть что там на выходе.
Для надёжности лучше использовать компиляторx86 msvc(32 бит).
## Код:
```
#include <windows.h>

void y(void) {
  int x = IOCTL_STORAGE_QUERY_PROPERTY;
}
```
## Код:
```
push    ebp
        mov     ebp, esp
        push    ecx
        mov     DWORD PTR _x$[ebp], 2954240             ; 002d1400H
        mov     esp, ebp
        pop     ebp
        ret     0
```
2954240 - интересующее нас число.

3. Пример программы.
Не уверен, правда, серийный номер чего оно выдаёт. Но какой-то выдаёт.
Обращаю внимание что используются структуры переменной размерности, возможно именно поэтому их нету в биндингах.
## Код:
```
MODULE TestDisk;

   IMPORT SYSTEM, WinApi, StdLog;

   PROCEDURE Do*;
      CONST
         IOCTL_STORAGE_QUERY_PROPERTY = 2954240;
         StorageDeviceProperty = 0;
         PropertyStandardQuery = 0;

      TYPE
         STORAGE_PROPERTY_QUERY = RECORD [untagged]
            PropertyID, QueryType: INTEGER;
            AdditionalParameters: ARRAY 4 OF BYTE; (*variadic*)
         END;

         STORAGE_DEVICE_DESCRIPTOR = RECORD [untagged]
            Version, Size: INTEGER;
            DeviceType, DeviceTypeModifier: BYTE;
            RemovableMedia, CommandQueueing: BYTE;
            VendorIDOffset, ProductIDOffset, ProductRevisionOffset, SerialNumberOffset: INTEGER;
            BusType: INTEGER;
            RawPropertiesLength: INTEGER;
            RawDeviceProperties: ARRAY 4096 OF BYTE; (*variadic*)
         END;

      VAR
         handle: WinApi.HANDLE;
         spq: STORAGE_PROPERTY_QUERY;
         buf: STORAGE_DEVICE_DESCRIPTOR;
         str: WinApi.PtrSTR;
         ok: WinApi.BOOL;
         i, n: INTEGER;
   BEGIN
      handle := WinApi.CreateFileW ("\\.\C:", {}, WinApi.FILE_SHARE_WRITE, NIL, WinApi.OPEN_EXISTING, {}, 0);
      IF handle # WinApi.INVALID_HANDLE_VALUE THEN
         spq.PropertyID := StorageDeviceProperty;
         spq.QueryType := PropertyStandardQuery;
         FOR i := 0 TO LEN(spq.AdditionalParameters) - 1 DO (*clear just in case*)
            spq.AdditionalParameters[i] := 0;
         END;
         IF WinApi.DeviceIoControl(handle, IOCTL_STORAGE_QUERY_PROPERTY, SYSTEM.ADR(spq), SIZE(STORAGE_PROPERTY_QUERY), SYSTEM.ADR(buf), SIZE(STORAGE_DEVICE_DESCRIPTOR), n, NIL) = WinApi.TRUE THEN
            IF buf.Version >= 40 THEN
               IF buf.Size <= SIZE(STORAGE_DEVICE_DESCRIPTOR) THEN
                  IF buf.SerialNumberOffset > 0 THEN
                     str := SYSTEM.VAL(WinApi.PtrSTR, SYSTEM.ADR(buf) + buf.SerialNumberOffset)
                  ELSE str := "<NOT AVAILABLE>"
                  END;
                  StdLog.String("Serial: "); StdLog.String(str$); StdLog.Ln
               ELSE StdLog.String("buffer too small"); StdLog.Ln
               END
            ELSE StdLog.String("unsupported version"); StdLog.Ln
            END
         ELSE StdLog.String("fail to get device properties"); StdLog.Ln
         END;
         ok := WinApi.CloseHandle(handle)
      ELSE StdLog.String("fail to open device"); StdLog.Ln
      END
   END Do;

END TestDisk.

^Q DevCompiler.CompileAndUnload
^Q TestDisk.Do
```


PS: Динамические строки и структуры, которые не сохраняются где-то внутри winapi, вполне можно передавать через обычный POINTER. А кучу (heap) процесса лучше не использовать - она используется самим блэкбоксом и однажды может стать плохо и не понятно отчего, по возможности лучше использовать статические объекты на стеке.