从Delphi中的Macapi.IOKit导入IORegistryEntrySearchCFProperty for OSX64

问题描述 投票:3回答:1

我在OSX32中成功使用了此导入定义:

uses
  MacApi.ObjectiveC,
  MacApi.Foundation,
  Macapi.CoreFoundation,
  Macapi.Mach,
  Macapi.IOKit;

type
  io_iterator_t = io_object_t;
  io_name_t = array[0..127] of AnsiChar;

function IORegistryEntrySearchCFProperty(entry: io_registry_entry_t;
  plane: io_name_t; key: CFStringRef; allocator: CFAllocatorRef;
  options: IOOptionBits): CFTypeRef; cdecl;
  external libIOKit name _PU + 'IORegistryEntrySearchCFProperty';

function IOServiceGetMatchingServices(masterPort: mach_port_t;
  matching: CFDictionaryRef; var existing: io_iterator_t): kern_return_t; cdecl;
  external libIOKit name _PU + 'IOServiceGetMatchingServices';

function IOIteratorNext(name: io_iterator_t): io_object_t; cdecl;
  external libIOKit name _PU + 'IOIteratorNext';

const
  kIOSerialBSDServiceValue = 'IOSerialBSDClient';
  kIOSerialBSDTypeKey      = 'IOSerialBSDClientType';
  kIOSerialBSDModemType    = 'IOModemSerialStream';
  kIOUSBDeviceClassName    = 'IOUSBDevice';
  kIOCalloutDeviceKey      = 'IOCalloutDevice';
  kIOTTYDeviceKey          = 'IOTTYDevice';
  kIOServicePlane          = 'IOService';
  kUSBInterfaceNumber      = 'bInterfaceNumber';
  kUSBVendorID             = 'idVendor';
  kUSBProductID            = 'idProduct';

  kIORegistryIterateRecursively = $00000001;
  kIORegistryIterateParents       = $00000002;

由于迁移到OSX64,我在函数IORegistryEntrySearchCFProperty中收到读取访问冲突。

从我的角度来看,IORegistryEntrySearchCFProperty的参数没有从32位更改为64位。

API函数用于读取USB设备的供应商ID和产品ID:

function TSerialInterface.SearchUSBSerialDevice(const Service: string; VendorID, ProductID: cardinal): integer;
var
  MatchingDictionary: CFMutableDictionaryRef;
  Iter: io_iterator_t;
  USBRef: io_service_t;
  ret: kern_return_t;
  ResAsCFString: CFTypeRef;
  aBsdPath: PAnsiChar;
  Bsd: array[0..1024] of AnsiChar;
  sBsd: string;
  VID, PID: Int32;
begin
  result := 0;
  MatchingDictionary := IOServiceMatching(kIOSerialBSDServiceValue);
  ret := IOServiceGetMatchingServices(kIOMasterPortDefault,
    CFDictionaryRef(MatchingDictionary), Iter);
  if (ret = KERN_SUCCESS) and (Iter <> 0) then
  begin
    try
      repeat
        USBRef := IOIteratorNext(Iter);
        if USBRef <> 0 then
        begin
          // USB device found
          Bsd[0] := #0;
          VID := 0;
          PID := 0;
          ResAsCFString := IORegistryEntryCreateCFProperty(USBRef,
            CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0);
          if assigned(ResAsCFString) then
          begin
            aBsdPath := CFStringGetCStringPtr(ResAsCFString,
              kCFStringEncodingASCII);
            if assigned(aBsdPath) then
              sBsd := string(aBsdPath)
            else if CFStringGetCString(ResAsCFString, @Bsd[0], sizeof(Bsd),
                kCFStringEncodingASCII) then
              sBsd := string(Bsd)
            else
              sBsd := ''; // Invalid device path
          end;
          ResAsCFString := IORegistryEntrySearchCFProperty(USBRef,
            kIOServicePlane, CFSTR(kUSBVendorID), kCFAllocatorDefault,
            kIORegistryIterateRecursively + kIORegistryIterateParents);
          if assigned(ResAsCFString) then
            if not CFNumberGetValue(ResAsCFString, kCFNumberIntType, @VID) then
              VID := 0;
          ResAsCFString := IORegistryEntrySearchCFProperty(USBRef,
            kIOServicePlane, CFSTR(kUSBProductID), kCFAllocatorDefault,
            kIORegistryIterateRecursively + kIORegistryIterateParents);
          if assigned(ResAsCFString) then
            if not CFNumberGetValue(ResAsCFString, kCFNumberIntType, @PID) then
              PID := 0;
          Log.d(name + ': USBDevice "' + sBsd + '" VID/PID: ' + IntToHex(VID) + '/' + IntToHex(PID));
        end;
      until USBRef = 0;
    finally
      IOObjectRelease(Iter);
    end;
 end; 

我也在XCode中使用C实现了上述功能,并且可以毫无问题地运行此代码。

在异常情况下(EAccessViolation:地址为00007FFF3A929716的访问冲突,访问地址000000000000000000)我在Delphi IDE中看到以下调用堆栈:

*System._DbgExcNotify(int, void*, System.SmallString<(unsigned char)255>*, void*, void*)(0,0x00000001039035e0,0x00000001012fa22e,0x00007fff3a929716,0x0000000000000000)
System.NotifyReRaise(System.TObject*, void*)(0x00000001039035e0,0x00007fff3a929716)
System._RaiseAtExcept(System.TObject*, void*)(0x00000001039035e0,0x00007fff3a929716)
System.Internal.Excutils.SignalConverter(NativeUInt, NativeUInt, NativeUInt)(140734176073494,0,11)
:000000010003CDE0 System::Internal::Excutils::GetExceptionObject(NativeUInt, NativeUInt, unsigned long)
:00007FFF3D27B2A0 IORegistryEntrySearchCFProperty
Serialinterface.TSerialInterface.SearchComPortForUSB(System.UnicodeString, unsigned int, unsigned int)(0x000000020978e5e0,'USBser',2283,65287)* 

为了进行更深入的分析,我在这里添加了调用IORegistryEntrySearchCFProperty的小型测试过程的生成的汇编代码。

Unit3.pas中的对象Pascal:

procedure Test
var
  USBRef: io_service_t;
  key: CFStringRef;
  allocator: CFAllocatorRef;
  ResAsCFString: CFTypeRef;
begin
  USBRef := 0;
  key := CFSTR(kUSBVendorID);
  allocator := kCFAllocatorDefault;
  ResAsCFString := IORegistryEntrySearchCFProperty(USBRef,
    kIOServicePlane, key, allocator, 0);   
end;

[Delphi调试器CPU视图显示了反汇编的x64代码:

Unit3.pas.38: USBRef := 0;
000000010079CC43 C745FC00000000   mov dword ptr [rbp - 0x4], 0x0
Unit3.pas.39: key := CFSTR(kUSBVendorID);
000000010079CC4A 488D355B881000   lea rsi, [rip + 0x10885b]; __unnamed_1 + 12
000000010079CC51 488D7DD8         lea rdi, [rbp - 0x28]
000000010079CC55 E8E69987FF       call 0x100016640; System.UTF8Encode(System.UnicodeString) at System.pas:39603
000000010079CC5A EB00             jmp 0x10079cc5c; <+44> at Unit3.pas:39
000000010079CC5C 488B7DD8         mov rdi, qword ptr [rbp - 0x28]
000000010079CC60 E85B9B87FF       call 0x1000167c0; System._LStrToPChar(System.AnsiStringT<(unsigned short)0>) at System.pas:28783
000000010079CC65 48898538FFFFFF   mov qword ptr [rbp - 0xc8], rax
000000010079CC6C EB00             jmp 0x10079cc6e; <+62> at Unit3.pas:39
000000010079CC6E 488BBD38FFFFFF   mov rdi, qword ptr [rbp - 0xc8]
000000010079CC75 E8767789FF       call 0x1000343f0; Macapi::Corefoundation::__CFStringMakeConstantString(char*)
000000010079CC7A 48898530FFFFFF   mov qword ptr [rbp - 0xd0], rax
000000010079CC81 EB00             jmp 0x10079cc83; <+83> at Unit3.pas:39
000000010079CC83 488B8530FFFFFF   mov rax, qword ptr [rbp - 0xd0]
000000010079CC8A 488945F0         mov qword ptr [rbp - 0x10], rax
Unit3.pas.40: allocator := kCFAllocatorDefault;
000000010079CC8E E8AD7A89FF       call 0x100034740; Macapi.Corefoundation.kCFAllocatorDefault() at CFBaseImpl.inc:65
000000010079CC93 48898528FFFFFF   mov qword ptr [rbp - 0xd8], rax
000000010079CC9A EB00             jmp 0x10079cc9c; <+108> at Unit3.pas:40
000000010079CC9C 488B8528FFFFFF   mov rax, qword ptr [rbp - 0xd8]
000000010079CCA3 488945E8         mov qword ptr [rbp - 0x18], rax
Unit3.pas.41: ResAsCFString := IORegistryEntrySearchCFProperty(USBRef,
000000010079CCA7 8B7DFC           mov edi, dword ptr [rbp - 0x4]
000000010079CCAA 0F28057F881000   movaps xmm0, xmmword ptr [rip + 0x10887f]; __unnamed_2 + 112
000000010079CCB1 0F2945C0         movaps xmmword ptr [rbp - 0x40], xmm0
000000010079CCB5 0F280564881000   movaps xmm0, xmmword ptr [rip + 0x108864]; __unnamed_2 + 96
000000010079CCBC 0F2945B0         movaps xmmword ptr [rbp - 0x50], xmm0
000000010079CCC0 0F280549881000   movaps xmm0, xmmword ptr [rip + 0x108849]; __unnamed_2 + 80
000000010079CCC7 0F2945A0         movaps xmmword ptr [rbp - 0x60], xmm0
000000010079CCCB 0F28052E881000   movaps xmm0, xmmword ptr [rip + 0x10882e]; __unnamed_2 + 64
000000010079CCD2 0F294590         movaps xmmword ptr [rbp - 0x70], xmm0
000000010079CCD6 0F280513881000   movaps xmm0, xmmword ptr [rip + 0x108813]; __unnamed_2 + 48
000000010079CCDD 0F294580         movaps xmmword ptr [rbp - 0x80], xmm0
000000010079CCE1 0F2805F8871000   movaps xmm0, xmmword ptr [rip + 0x1087f8]; __unnamed_2 + 32
000000010079CCE8 0F298570FFFFFF   movaps xmmword ptr [rbp - 0x90], xmm0
000000010079CCEF 0F2805DA871000   movaps xmm0, xmmword ptr [rip + 0x1087da]; __unnamed_2 + 16
000000010079CCF6 0F298560FFFFFF   movaps xmmword ptr [rbp - 0xa0], xmm0
000000010079CCFD 0F2805BC871000   movaps xmm0, xmmword ptr [rip + 0x1087bc]; __unnamed_2
000000010079CD04 0F298550FFFFFF   movaps xmmword ptr [rbp - 0xb0], xmm0
000000010079CD0B 488B75F0         mov rsi, qword ptr [rbp - 0x10]
000000010079CD0F 488B55E8         mov rdx, qword ptr [rbp - 0x18]
000000010079CD13 4889E1           mov rcx, rsp
000000010079CD16 0F2845C0         movaps xmm0, xmmword ptr [rbp - 0x40]
000000010079CD1A 0F114170         movups xmmword ptr [rcx + 0x70], xmm0
000000010079CD1E 0F2845B0         movaps xmm0, xmmword ptr [rbp - 0x50]
000000010079CD22 0F114160         movups xmmword ptr [rcx + 0x60], xmm0
000000010079CD26 0F2845A0         movaps xmm0, xmmword ptr [rbp - 0x60]
000000010079CD2A 0F114150         movups xmmword ptr [rcx + 0x50], xmm0
000000010079CD2E 0F284590         movaps xmm0, xmmword ptr [rbp - 0x70]
000000010079CD32 0F114140         movups xmmword ptr [rcx + 0x40], xmm0
000000010079CD36 0F288550FFFFFF   movaps xmm0, xmmword ptr [rbp - 0xb0]
000000010079CD3D 0F288D60FFFFFF   movaps xmm1, xmmword ptr [rbp - 0xa0]
000000010079CD44 0F289570FFFFFF   movaps xmm2, xmmword ptr [rbp - 0x90]
000000010079CD4B 0F285D80         movaps xmm3, xmmword ptr [rbp - 0x80]
000000010079CD4F 0F115930         movups xmmword ptr [rcx + 0x30], xmm3
000000010079CD53 0F115120         movups xmmword ptr [rcx + 0x20], xmm2
000000010079CD57 0F114910         movups xmmword ptr [rcx + 0x10], xmm1
000000010079CD5B 0F1101           movups xmmword ptr [rcx], xmm0
000000010079CD5E 31C9             xor ecx, ecx
> Register content here
>   RBP: 00007FFEEFBFEA80
>   RSP: 00007FFEEFBFEA00 
> Memory content here
>   00007FFEEFBFEA00 49 4F 53 65 72 76 69 63  IOServic
>   00007FFEEFBFEA08 65 00 00 00 00 00 00 00  e.......
000000010079CD60 E82BFEFFFF       call 0x10079cb90; Macapi::Iokit2::IORegistryEntrySearchCFProperty(unsigned int, System::StaticArray<char, 128>, __CFString*, __CFAllocator*, unsigned int)
> Access violation at address 00007FFF2ADD716, accessing address 0
000000010079CD65 48898520FFFFFF   mov qword ptr [rbp - 0xe0], rax
000000010079CD6C EB00             jmp 0x10079cd6e; <+318> at Unit3.pas:41
000000010079CD6E 488B8520FFFFFF   mov rax, qword ptr [rbp - 0xe0]
000000010079CD75 488945E0         mov qword ptr [rbp - 0x20], rax
000000010079CD79 EB37             jmp 0x10079cdb2; <+386> at Unit3.pas:41
000000010079CD7B 89D1             mov ecx, edx
000000010079CD7D 48898540FFFFFF   mov qword ptr [rbp - 0xc0], rax
000000010079CD84 898D48FFFFFF     mov dword ptr [rbp - 0xb8], ecx
000000010079CD8A 488D7DD8         lea rdi, [rbp - 0x28]
000000010079CD8E E81D9F87FF       call 0x100016cb0; System._LStrClr(void*) at System.pas:25402
000000010079CD93 8B8D48FFFFFF     mov ecx, dword ptr [rbp - 0xb8]
000000010079CD99 488BBD40FFFFFF   mov rdi, qword ptr [rbp - 0xc0]
000000010079CDA0 48898518FFFFFF   mov qword ptr [rbp - 0xe8], rax
000000010079CDA7 898D14FFFFFF     mov dword ptr [rbp - 0xec], ecx
000000010079CDAD E8863B0100       call 0x1007b0938; symbol stub for: _Unwind_Resume
000000010079CDB2 488D45D8         lea rax, [rbp - 0x28]
Unit3.pas.47: end;
000000010079CDB6 4889C7           mov rdi, rax
000000010079CDB9 E8F29E87FF       call 0x100016cb0; System._LStrClr(void*) at System.pas:25402
000000010079CDBE 48898508FFFFFF   mov qword ptr [rbp - 0xf8], rax
000000010079CDC5 4881C480010000   add rsp, 0x180
000000010079CDCC 5D               pop rbp
000000010079CDCD C3               ret 

我是否已显示所有相关寄存器? (不幸的是,我距离了解此x64代码的细节还很遥远)。

与以下用XCode编写的C代码相比:

void Test(void)
{
    io_service_t usbRef = 0;
    CFStringRef key = CFSTR("idVendor");
    CFAllocatorRef allocator = kCFAllocatorDefault;
    CFTypeRef cf_vendor;

    cf_vendor = IORegistryEntrySearchCFProperty(usbRef, kIOServicePlane, key, allocator, 0);
}

生成此x64汇编代码:

    0x100001c40 <+0>:  pushq  %rbp
    0x100001c41 <+1>:  movq   %rsp, %rbp
    0x100001c44 <+4>:  subq   $0x20, %rsp
    0x100001c48 <+8>:  xorl   %r8d, %r8d
    0x100001c4b <+11>: movq   0x3c6(%rip), %rax         ; (void *)0x00007fff2fc755f0: kCFAllocatorDefault
    0x100001c52 <+18>: leaq   0x4f7(%rip), %rcx         ; @"idVendor"
    0x100001c59 <+25>: movl   $0x0, -0x4(%rbp)
    0x100001c60 <+32>: movq   %rcx, -0x10(%rbp)
    0x100001c64 <+36>: movq   (%rax), %rax
    0x100001c67 <+39>: movq   %rax, -0x18(%rbp)
->  0x100001c6b <+43>: movl   -0x4(%rbp), %edi
    0x100001c6e <+46>: movq   -0x10(%rbp), %rdx
    0x100001c72 <+50>: movq   -0x18(%rbp), %rcx
    0x100001c76 <+54>: leaq   0x263(%rip), %rsi         ; "IOService"
    0x100001c7d <+61>: callq  0x100001d12               ; symbol stub for: IORegistryEntrySearchCFProperty
    0x100001c82 <+66>: movq   %rax, -0x20(%rbp)
    0x100001c86 <+70>: addq   $0x20, %rsp
    0x100001c8a <+74>: popq   %rbp
    0x100001c8b <+75>: retq  

与按预期工作的Pascal测试过程的Delphi 32位编译器生成的x86代码相比:

Unit3.pas.38: USBRef := 0;
004BB6E1 33C0             xor eax,eax
004BB6E3 8945FC           mov [ebp-$04],eax
Unit3.pas.39: key := CFSTR(kUSBVendorID);
004BB6E6 6810000000       push $00000010
004BB6EB 55               push ebp
004BB6EC 68EDFEEFBE       push $beeffeed
004BB6F1 83C4F4           add esp,-$0c
004BB6F4 83C4FC           add esp,-$04
004BB6F7 8D55E8           lea edx,[ebp-$18]
004BB6FA 8D83A0B74B00     lea eax,[ebx+Test + $DC]
004BB700 E8276EB6FF       call UTF8Encode
004BB705 83C404           add esp,$04
004BB708 8B45E8           mov eax,[ebp-$18]
004BB70B 83C4FC           add esp,-$04
004BB70E E85904B6FF       call @LStrToPChar
004BB713 83C404           add esp,$04
004BB716 50               push eax
004BB717 E8A0AD4400       call $009064bc
004BB71C 83C41C           add esp,$1c
004BB71F FE4424F4         inc byte ptr [esp-$0c]
004BB723 8945EC           mov [ebp-$14],eax
004BB726 8B45EC           mov eax,[ebp-$14]
004BB729 8945F8           mov [ebp-$08],eax
Unit3.pas.40: allocator := kCFAllocatorDefault;
004BB72C 83C4F4           add esp,-$0c
004BB72F E8602EB7FF       call kCFAllocatorDefault
004BB734 83C40C           add esp,$0c
004BB737 8945F4           mov [ebp-$0c],eax
Unit3.pas.41: ResAsCFString := IORegistryEntrySearchCFProperty(USBRef,
004BB73A 6820000000       push $00000020
004BB73F 55               push ebp
004BB740 68EDFEEFBE       push $beeffeed
004BB745 83C4F4           add esp,-$0c
004BB748 6A00             push $00
004BB74A 8B45F4           mov eax,[ebp-$0c]
004BB74D 50               push eax
004BB74E 8B45F8           mov eax,[ebp-$08]
004BB751 50               push eax
004BB752 8D83B4B74B00     lea eax,[ebx+Test + $F0]
> Register content here
>  EAX: 004BB7B4
>Memory content here:
>  004BB7B4 49 4F 53 65 72 76 69 63  IOServic
>  004BB7BC 65 00 00 00 00 00 00 00  e.......
004BB758 50               push eax
004BB759 8B45FC           mov eax,[ebp-$04]
004BB75C 50               push eax
004BB75D E8BEA84400       call $00906020
004BB762 83C42C           add esp,$2c
004BB765 FE4424F4         inc byte ptr [esp-$0c]
004BB769 8945F0           mov [ebp-$10],eax
Unit3.pas.47: end;
004BB76C 688FB74B00       push $004bb78f
004BB771 011C24           add [esp],ebx
004BB774 8D45E8           lea eax,[ebp-$18]
004BB777 83C4F8           add esp,-$08
004BB77A E86DF7B5FF       call @LStrClr
004BB77F 83C408           add esp,$08
004BB782 C3               ret 

也许有人可以给我一个小费,这是我必须注意的。

macos delphi firemonkey 32bit-64bit iokit
1个回答
0
投票

问题出在io_name_t类型的声明中。对于过程声明中的Delphi MacOS64,AnsiChar数组不再与PAnsiChar相同。现在可以使用以下解决方案:

type
  io_name_t = PAnsiChar;

function IORegistryEntrySearchCFProperty(entry: io_registry_entry_t;
  plane: io_name_t; key: CFStringRef; allocator: CFAllocatorRef;
  options: IOOptionBits): CFTypeRef; cdecl;
  external libIOKit name _PU + 'IORegistryEntrySearchCFProperty';
© www.soinside.com 2019 - 2024. All rights reserved.