我知道我可以像这样正确使用WinApi函数DsGetDcName:

DOMAIN_CONTROLLER_INFO* dcInfo = nullptr;

unsigned long res = ::DsGetDcName(nullptr,
                        nullptr,
                        nullptr,
                        nullptr,
                            0,  &dcInfo);

我知道这是不自然的,但是我想了解为什么人们也不能这样写:
    void* dcInfo = nullptr;
unsigned long res = ::DsGetDcName(nullptr,
                        nullptr,
                        nullptr,
                        nullptr,
                        0,  (DOMAIN_CONTROLLER_INFO**) dcInfo);

if (res)
{
       wchar_t* name;
       name = static_cast<DOMAIN_CONTROLLER_INFO*> (dcInfo)->DomainControllerName;
}

第二个版本使用void*作为指针类型,这就是为什么我在运行它(调用::DsGetDcName)时遇到访问权限冲突的原因。但是我不明白为什么呢?为void*指定dcInfo而不是DOMAIN_CONTROLLER_INFO* dcInfo类型时,这与内存对齐方式有关吗?

解决方案

我发现了问题,实际上我可以使用复杂的unsafe void *版本,只是我没有将正确的指针地址传递给该函数。这里是:
void* dcInfo = nullptr;
unsigned long res = ::DsGetDcName(nullptr,
                        nullptr,
                        nullptr,
                        nullptr,
                        0,  (DOMAIN_CONTROLLER_INFO**) &dcInfo);

注意,我传递了(DOMAIN_CONTROLLER_INFO**) &dcInfo而不是(DOMAIN_CONTROLLER_INFO**) dcInfo。之前,我只是停下脚步,因为我告诉编译器我知道我在做什么,但是将一个指针值而不是所需指针的地址传递给该函数(是的,该指针值为nullptr):-) )

这是使用正确版本(版本1)的又一个原因。在第二种情况下,缺点还在于您必须再次强制转换如下结果:
wchar_t* name;
name = static_cast<DOMAIN_CONTROLLER_INFO*>(dcInfo)->DomainControllerName; // Get DC

最佳答案

您将需要查看程序集。起作用的两个选项(#2和#3)都使用LEA指令。这会将数据结构的地址加载到EAX中(在这种情况下为null)。失败的示例将加载该地址的值为空。如您所知,您不能取消引用null。

// #1 - Fails
::DsGetDcName(nullptr, nullptr, nullptr, nullptr, 0, (DOMAIN_CONTROLLER_INFO**)void_ptr);
01101A63  mov         esi,esp
01101A65  mov         eax,dword ptr [void_ptr]
01101A68  push        eax
01101A69  push        0
01101A6B  push        0
01101A6D  push        0
01101A6F  push        0
01101A71  push        0
01101A73  call        dword ptr [__imp__DsGetDcNameW@24 (1108350h)]
01101A79  cmp         esi,esp
01101A7B  call        @ILT+310(__RTC_CheckEsp) (110113Bh)

// #2 - Works
::DsGetDcName(nullptr, nullptr, nullptr, nullptr, 0, (DOMAIN_CONTROLLER_INFO**)&void_ptr);
00EE1A63  mov         esi,esp
00EE1A65  lea         eax,[void_ptr]
00EE1A68  push        eax
00EE1A69  push        0
00EE1A6B  push        0
00EE1A6D  push        0
00EE1A6F  push        0
00EE1A71  push        0
00EE1A73  call        dword ptr [__imp__DsGetDcNameW@24 (0EE8350h)]
00EE1A79  cmp         esi,esp
00EE1A7B  call        @ILT+310(__RTC_CheckEsp) (0EE113Bh)

// #3 - Works
::DsGetDcName(nullptr, nullptr, nullptr, nullptr, 0, &dc_ptr);
013D1A5C  mov         esi,esp
013D1A5E  lea         eax,[dc_ptr]
013D1A61  push        eax
013D1A62  push        0
013D1A64  push        0
013D1A66  push        0
013D1A68  push        0
013D1A6A  push        0
013D1A6C  call        dword ptr [__imp__DsGetDcNameW@24 (13D8350h)]
013D1A72  cmp         esi,esp
013D1A74  call        @ILT+310(__RTC_CheckEsp) (13D113Bh)

10-06 03:42