开发者

C++ conversion question

I know that I can use correctly the WinApi function DsGetDcName like this:

DOMAIN_CONTROLLER_INFO* dcInfo = nullptr;

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

It is unnatural, I know, but I want to understand why one cannot write it also like this:

    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;
}

The second version uses void* as a pointer type, and this is why I get an acces violation when running it (at call to the ::DsGetDcName). But I don't understand why is this? Does it have to do with the way the memory is aligned when specifying void* for dcInfo as opposed to type DOMAIN_CONTROLLER_INFO* dcInfo ?

SOLUTION

I find out the problem, I can use actually the convoluted unsafe void* version, I just didn't passed the right pointer address to that function. Here it is:

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

Notice that I pass (DOMAIN_CONTROLLER_INFO**) &dcInfo instead of (DOMAIN_CONTROLLER_INFO**) dcInfo. I was just shutting myself in the foot before because I told the compiler I know what I'm doing but passed to the function a pointer value instead of the address of the pointer needed (and yes, that pointer value was nullptr ) :-))

This is one more reason to use the right version (version 1). In this second case also the disadvantage is that you have to cast again the result like this:

wchar_t* name;
name = static_cast<DOMAIN_CONTROLLER_INFO*>(dcInfo)->DomainControllerName; // Get DC


Because the function takes double-indirected pointer. It is something like:

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

    (*pTarget)[0] =  110;
}

And you would call it like:

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

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

    return 0;
}

Which would allocate memory to the int-pointer you passed, and you must pass the address of a pointer, and not just a int** type-casted int*.

This is not because of DsGetDcName function, but by C/C++ language. The function doesn't know required size, and it it allocates it for you. There are many Windows functions that demand two function calls - one to determine the size (mostly DWORD dwNeeded), and one to actually do the job. This function allocates memory for you in one call, and requires you to call NetApiBufferFree later.

In C++ you can use int*& and change the signature:

void AllocateMemory(int*& pTarget);

and call like:

int* pAllocHere;
AllocateMemory(pAllocHere);

But Windows API must use C language.


You would need to look at the assembly. The two options that work (#2 & #3) both use the LEA instruction. This loads the address of the data structure into EAX, which in the case is null. The failing example loads the value of the that address which is null. As you know you cannot dereference 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)  
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜