Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ conversion question

Tags:

c++

pointers

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
like image 771
Ghita Avatar asked Aug 18 '11 19:08

Ghita


1 Answers

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.

like image 161
Ajay Avatar answered Oct 18 '22 04:10

Ajay