C ++ conversion request

I know that I can use the WinApi DsGetDcName function DsGetDcName as follows:

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

This is unnatural, I know, but I want to understand why it also cannot be written 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 the type of pointer, and that is why I get an access violation when it starts (when ::DsGetDcName ). But I do not understand why this is so? Is this dcInfo to how memory is aligned when specifying void* for dcInfo , and not of type DOMAIN_CONTROLLER_INFO* dcInfo ?

Decision

I will find out the problem, I can use a really confusing unsafe version of void *, I just did not pass the correct address of the pointer to this function. There he is:

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

Note that I'm skipping (DOMAIN_CONTROLLER_INFO**) &dcInfo instead of (DOMAIN_CONTROLLER_INFO**) dcInfo . I just shut myself up earlier because I told the compiler that I knew what I was doing, but I passed the pointer value to the function instead of the pointer (and yes, that pointer value was nullptr ) nullptr )

This is another reason to use the correct version (version 1). In this second case, the disadvantage is that you must execute the result again as follows:

 wchar_t* name; name = static_cast<DOMAIN_CONTROLLER_INFO*>(dcInfo)->DomainControllerName; // Get DC 
+6
source share
2 answers

You will need to look at the assembly. Two options that work (# 2 and # 3) use LEA instructions. This loads the data structure address into EAX, which in this case is NULL. In the case of an unsuccessful example, the value of this address, which is null, is loaded. As you know, you cannot dereference zero.

 // #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) 
+1
source

Because the function accepts a bi-directional pointer. This is something like:

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

And you would call it that:

 int main() { int* pAllocHere; AllocateMemory(&pAllocHere); int nValue; nValue= pAllocHere[0]; // 110 return 0; } 

To allocate memory for an int-pointer, you must pass the address of the pointer , not just int** type-casted int* .

This is not due to the DsGetDcName function, but the C / C ++ language. The function does not know the required size, and it allocates it for you. There are many Windows functions that require two function calls: one for sizing (basically DWORD dwNeeded ) and one for actually executing the job. This function allocates memory for you in one call and requires you to later NetApiBufferFree .

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

 void AllocateMemory(int*& pTarget); 

and call:

 int* pAllocHere; AllocateMemory(pAllocHere); 

But the Windows API must use C.

+2
source

Source: https://habr.com/ru/post/895358/


All Articles