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)
精彩评论