6

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

Th1sD0t
  • 1,089
  • 3
  • 11
  • 37
  • Does the map drive work if you don't give a local name ? i.e., make `localName` an empty string. This may give some clue whether there is any other problem. Error code 1200 means that there is something not right with your "X:\" -- is there any extra space (please see - https://stackoverflow.com/questions/31137879/excel-to-sharepoint-mapnetworkdrive-error) – Subbu Jul 31 '17 at 02:24
  • Unfortunately not - the Error 1200 persists, even without a local drive specified (empty string). See my Edit1 for further NetResource details. (I had to clear the server name out, sorry. – Th1sD0t Jul 31 '17 at 04:45

2 Answers2

5
[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)]
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
1

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...

Th1sD0t
  • 1,089
  • 3
  • 11
  • 37
  • With 'LPWStr' your specifying that it's a pointer to a null-terminated array of Unicode characters. If you don't specify it explicitly, it may be defaulting to some other value. More details on this here: [Default marshalling for strings](https://learn.microsoft.com/en-us/dotnet/framework/interop/default-marshalling-for-strings). – nwsmith Apr 04 '23 at 11:13