WNetAddConnection2 returns Error 1200 - Local name is valid

1.8k views Asked by At

I'm trying to connect a share (let's say \server\folder) to my local device X:

[DllImport("Mpr.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        private static extern int WNetAddConnection2(
            [In] NetResource lpNetResource,
            string lpPassword,
            string lpUsername,
            int flags
        );

public static bool Connect(string remoteName, string localName, bool persistent) {
            if (!IsLocalPathValid(localName)) return false;
            var r = new NetResource
            {
                dwScope = ResourceScope.RESOURCE_GLOBALNET,
                dwType = ResourceType.RESOURCETYPE_ANY,
                dwDisplayType = ResourceDisplayType.RESOURCEDISPLAYTYPE_SHARE,
                dwUsage = ResourceUsage.RESOURCEUSAGE_CONNECTABLE,
                lpRemoteName = remoteName,
                lpLocalName = localName
            };
            return WNetAddConnection2(r, null, null, persistent ? 1 : 0) == 0;
        }

[StructLayout(LayoutKind.Sequential)]
    public class NetResource {
        public ResourceScope dwScope;
        public ResourceType dwType;
        public ResourceDisplayType dwDisplayType;
        public ResourceUsage dwUsage;
        public string lpLocalName;
        public string lpRemoteName;
        public string lpComment;
        public string lpProvider;
    }

When calling

Connect(@"\\server\folder", "X:", true);

the function just returns false - the Error says 1200 (BAD_DEVICE). The NetResource looks like this:

lpRemoteName = "\\\\server\\folder"; 
lpProvider = null;
lpLocalName = "X:";
lpComment = null;
dwUsage = Connectable; 
dwType = Any; 
dwScope = GlobalNet; 
dwDisplayType = Share;

I already checked with several snippets (PInvoke) put i can't see any difference. Maybe you can solve this mystery...

EDIT1

Variables when trying to map the drive

2

There are 2 answers

0
Hans Passant On BEST ANSWER
[StructLayout(LayoutKind.Sequential)]

That is where the problem started, the attribute does not specify the CharSet property. The default is CharSet.Ansi, a bewildering choice that requires a trip in a time machine to make sense of, taking you back to 1998. So the code passes a struct with strings that get translated to 8-bit characters to a function that is explicitly uses the Unicode flavor of the function. Inevitably the implementation sees garbage.

You can force the marshaling of each individual string member with [MarshalAs]. But it is just simpler and logical to make the character types match. Fix:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
1
Th1sD0t On

I finally did it.

I solved the issue by adding

[MarshalAs(UnmanagedType.LPWStr)] 

Attribute to every string field inside my NetResource class. Unfortunately I don't know why this is solving the issue...