Вопрос преобразования C ++ - PullRequest
       3

Вопрос преобразования C ++

6 голосов
/ 18 августа 2011

Я знаю, что могу использовать правильно функцию 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?

РЕШЕНИЕ

НахожуИз проблемы я могу использовать версию свернутый небезопасный 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 ]

2 голосов
/ 19 августа 2011

Потому что функция принимает двунаправленный указатель. Это что-то вроде:

void AllocateMemory(int** pTarget)
{
    *pTarget = new int[10];

    (*pTarget)[0] =  110;
}

И вы бы назвали это как:

int main()
{
    int* pAllocHere;
    AllocateMemory(&pAllocHere);

    int nValue;
    nValue= pAllocHere[0]; // 110

    return 0;
}

Который выделит память для переданного вами int-указателя, и вы должны передать адрес указателя , а не просто int** приведенный тип int*.

Это не из-за функции DsGetDcName, а из-за языка Си / Си ++. Функция не знает требуемого размера и выделяет его для вас. Существует много функций Windows, требующих двух вызовов функций: один для определения размера (в основном DWORD dwNeeded), а другой - для фактического выполнения работы. Эта функция выделяет вам память за один вызов и требует, чтобы вы вызывали NetApiBufferFree позже.

В C ++ вы можете использовать int*& и изменить подпись:

void AllocateMemory(int*& pTarget);

и звоните как:

int* pAllocHere;
AllocateMemory(pAllocHere);

Но Windows API должен использовать язык C.

1 голос
/ 19 августа 2011

Вам нужно будет посмотреть на сборку.Работающие две опции (# 2 и # 3) используют инструкцию LEA.Это загружает адрес структуры данных в EAX, который в данном случае является нулевым.Неудачный пример загружает значение того адреса, который является нулем.Как вы знаете, вы не можете разыменовать 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)  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...