The Linux Page

WNetAddConnection2 function, how to

Introduction

I just faught for a few hours trying to get the WNetAddConnection2() to work in my program and found out two things that I did not see explained anywhere in the documentation...

Folder that Works

I'm not too sure whether that's a new thing at the company I worked in to implement this function or whether that's every time, although I've seen other posts on the Internet with the same sort of path so I would imagine that this is a "normal" Microsoft network feature.

The fact is that to connect you have to use the name of the server followed by some path ended with a dollar sign. However, the path is NOT the path to the shared folder, it is the path to a disk on the remote device. Yet, you don't have to specify a disk per se, instead you may just specify IPC which if I understand properly gives you access to all the shared folders from that remote location.

The path I used was something like this:

\\192.168.0.123\IPC$

None of the Microsoft documentation about the WNetAddConnection2() function explained that!? (not too surprised though, just annoying because you're pretty much on your own to find the exact syntax.) I've seen someone say that they used IC$ instead. I could also use a drive such as D$ and it would work.

Once connected with that path you can then read all the shared folder on that other computer.

There is a sample code:

NETRESOUIRCE nr;
memset(&nr, 0, sizeof(nr));
nr.dwType = RESOURCETYPE_DISK;
nr.lpRemoteName = _T("\\\\192.168.0.123\\IPC$");
DWORD r = WNetAddConnection2(
               &nr,
               _T("password"),
               _T("username"),
               CONNECT_TEMPORARY);

If r is NO_ERROR (0), then you are connected for some time and you can use directory and file names that start with the Remove Name as in:

\\192.168.0.123\IPC$\shared\folder

Note that for a temporary connection you probably don't want to use a local drive letter. Plus, that could conflict with other applications (or your own if run twice in parallel.) Also in my case that did not work.

How Fast does it Timeout?

No clue! But in my application I have to run the WNetAddConnect2() call each time I want to access that remote location, otherwise it fails saying that it cannot logon (after a few seconds... like it didn't know it doesn't have the username and password instantaneously?!)

This was a struggle because my first implementation would call the WNetAddConnection2() function, wait for the user to click a button, and then proceed with loading files from that remote location. By that time the files are not accessible and I was getting an error (either 3, ERROR_PATH_NOT_FOUND, or 1326 (0x52E), ERROR_LOGON_FAILURE.)

So now I do a first WNetAddConnection2() to verify that it works and if so, then I set a flag to true. Later I can use that flag to know whether the connection should be attempted or not.

Logged On User

To make sure that it works I also put a log on user call. This uses the LogonUser() function as follow:

HANDLE token;
LogonUser(
    _T("NETWORK SERVER"),
    _T("NT AUTHORITY"),
    NULL,
    LOGON32_LOGON_NEW_CREDENTIALS,
    LOGON32_PROVIDER_WINNT50,
    &token);
ImpersonateLoggedOnUser(token);

I'm not totally sure that this was required in my case, but I've seen it as a culprit in many cases for a connection failure because the current user would not have the right to connect as is.

Quick Ping

Also to avoid trying to connect to a device that doesn't even exists (especially because you cannot define the timeout of that WNetAddConnection2() function call, at least it isn't obvious... probably can with 2 or 3 other calls?) I put a C/C++ Ping right before that. That function we can set it up to time out in increment of 1 millisecond starting at 1 millisecond.

DWORD r = IcmpSendEcho2(
    icmp2,         // use IcmpCreateFile() to create an icmp2 handle
    NULL,
    NULL,
    NULL,
    0xC044007B,    // IP address, see IN_ADDR
    request_data,  // any data, probably needs to be about 16 bytes
    request_size,
    NULL,
    reply_data,    // replies: sizeof(ICMP_ECHO_REPLY) + request_size * 2 or 3 + 8
    reply_size,
    1000           // Time out (1 second here)
);

If that call return a non-zero value that means the ping went round trip (did not timeout before a ping returned), the returned ping echo reply will then include a status that must be zero (0) to be valid. If so, the ping did a round trip and thus the remote system is available.

if(((PICMP_ECHO_REPLY) reply_data)->Status == 0) success = true;

This API for Ping does the same thing as the ping tool you find in the WIndows or Linux command line.