C# - NetUseAdd 来自 Windows Server 2008 和 IIS7 上的 NetApi32.dll

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1102538/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 08:18:27  来源:igfitidea点击:

C# - NetUseAdd from NetApi32.dll on Windows Server 2008 and IIS7

c#winapiiis-7interop

提问by Hyman Ryan

I am attemping to use NetUseAdd to add a share that is needed by an application. My code looks like this.

我正在尝试使用 NetUseAdd 添加应用程序所需的共享。我的代码看起来像这样。

[DllImport("NetApi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern uint NetUseAdd(
     string UncServerName,
     uint Level,
     IntPtr Buf,
     out uint ParmError);

...

...

USE_INFO_2 info = new USE_INFO_2();
info.ui2_local = null;
info.ui2_asg_type = 0xFFFFFFFF;
info.ui2_remote = remoteUNC;
info.ui2_username = username;
info.ui2_password = Marshal.StringToHGlobalAuto(password);
info.ui2_domainname = domainName;

IntPtr buf = Marshal.AllocHGlobal(Marshal.SizeOf(info));

try
{
    Marshal.StructureToPtr(info, buf, true);

    uint paramErrorIndex;
    uint returnCode = NetUseAdd(null, 2, buf, out paramErrorIndex);

    if (returnCode != 0)
    {
        throw new Win32Exception((int)returnCode);
    }
}
finally
{
    Marshal.FreeHGlobal(buf);
}

This works fine on our server 2003 boxes. But in attempting to move over to Server 2008 and IIS7 this doesnt work any more. Through liberal logging i have found that it hangs on the line Marshal.StructureToPtr(info, buf, true);

这在我们的 server 2003 机器上运行良好。但是在尝试转移到 Server 2008 和 IIS7 时,这不再起作用。通过自由伐木,我发现它挂在了线上Marshal.StructureToPtr(info, buf, true);

I have absolutely no idea why this is can anyone shed any light on it for tell me where i might look for more information?

我完全不知道这是为什么,谁能解释一下,告诉我在哪里可以找到更多信息?

采纳答案by Karl Strings

The reason is:

原因是:

You pulled the p/invoke signature off pinvoke.net and you didn't verify it. The fool who initially wrote this p/invoke sample code had no idea what he was doing and created one that "works" on 32-bit systems but does not work on 64-bit systems. He somehow turned a very simple p/invoke signature into some amazingly complicated mess and it spread like wildfire on the net.

您从 pinvoke.net 中提取了 p/invoke 签名,但没有对其进行验证。最初编写此 p/invoke 示例代码的傻瓜不知道他在做什么,并创建了一个在 32 位系统上“有效”但在 64 位系统上无效的代码。他不知何故将一个非常简单的 p/invoke 签名变成了一些令人惊讶的复杂混乱,并像野火一样在网络上蔓延。

The correct signature is:

正确的签名是:

    [DllImport( "NetApi32.dll", SetLastError = true, CharSet = CharSet.Unicode )]
    public static extern uint NetUseAdd(
         string UncServerName,
         UInt32 Level,
         ref USE_INFO_2 Buf,
         out UInt32 ParmError
        );

    [StructLayout( LayoutKind.Sequential, CharSet = CharSet.Unicode )]
    public struct USE_INFO_2
    {
        public string ui2_local;
        public string ui2_remote;
        public string ui2_password;
        public UInt32 ui2_status;
        public UInt32 ui2_asg_type;
        public UInt32 ui2_refcount;
        public UInt32 ui2_usecount;
        public string ui2_username;
        public string ui2_domainname;
    }

And your code should read:

你的代码应该是:

USE_INFO_2 info = new USE_INFO_2();   
info.ui2_local = null;   
info.ui2_asg_type = 0xFFFFFFFF;   
info.ui2_remote = remoteUNC;   
info.ui2_username = username;   
info.ui2_password = password;
info.ui2_domainname = domainName;      

uint paramErrorIndex;   
uint returnCode = NetUseAdd(null, 2, ref info, out paramErrorIndex);   

if (returnCode != 0)   
{   
    throw new Win32Exception((int)returnCode);   
}

Hope this was of some help. I just spent half a day knee deep remote debugging someone elses trash code trying to figure out what was going on and it was this.

希望这会有所帮助。我只是花了半天时间深入远程调试别人的垃圾代码,试图弄清楚发生了什么,就是这样。

回答by Joshua

What kind of layout do you have for your struct? I believe the USE_INFO_2needs to be [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)].

你的结构有什么样的布局?我相信USE_INFO_2需要是 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]。

Also, have you tried just passing the structure by ref rather than needing to Marshal.StructureToPtr?

另外,您是否尝试过仅通过 ref 传递结构而不需要 Marshal.StructureToPtr?

回答by Roberto B

Good work! All I got nothing to see in my windows explorer. A few days later, ShellNotification came into my mind. This I had previously used for file icon association. And as I remembered there was also a trigger for NetShare add. Yes, right!

干得好!我在 Windows 资源管理器中什么也看不到。几天后,ShellNotification 出现在我的脑海中。这是我以前用于文件图标关联的。我记得还有一个 NetShare 添加的触发器。是的,没错!

Afther a NetShareAdd you have to perform a SHChangeNotify from the shell32.dll.

在 NetShareAdd 之后,您必须从 shell32.dll 执行 SHChangeNotify。

ShellNotification.NotifyCreateDrive(info.ui2_local);

And this is the class i used for it:

这是我用于它的类:

public class ShellNotification
{     
    [DllImport("shell32.dll")]
    private static extern void SHChangeNotify(
        UInt32 wEventId,
        UInt32 uFlags,
        IntPtr dwItem1,
        IntPtr dwItem2);

    // Notify shell of change of file associations.
    public static void NotifyOfChange()
    {
        SHChangeNotify(
            (uint)ShellChangeNotificationEvents.SHCNE_ASSOCCHANGED,
            (uint)(ShellChangeNotificationFlags.SHCNF_IDLIST | ShellChangeNotificationFlags.SHCNF_FLUSHNOWAIT),
            IntPtr.Zero,
            IntPtr.Zero);
    }

    internal static void NotifyCreateDrive(string path) //path = "M:"
    {
        IntPtr strPtr = Marshal.StringToHGlobalUni(path);

        //A folder on the local computer is being shared via the network. SHCNF_IDLIST or SHCNF_PATHW must be specified in uFlags. dwItem1 contains the folder that is being shared. dwItem2 is not used and should be NULL.
        SHChangeNotify(
           (uint)ShellChangeNotificationEvents.SHCNE_NETSHARE,
           (uint)(ShellChangeNotificationFlags.SHCNF_IDLIST | ShellChangeNotificationFlags.SHCNF_PATHW),
           strPtr,
           IntPtr.Zero);

        //also, you need to make sure to free the unmanaged memory:
        Marshal.FreeHGlobal(strPtr);
    }

    [Flags]
    private enum ShellChangeNotificationEvents : uint
    {
        //The name of a nonfolder item has changed. SHCNF_IDLIST or  SHCNF_PATH must be specified in uFlags. dwItem1 contains the  previous PIDL or name of the item. dwItem2 contains the new PIDL or name of the item. 
        SHCNE_RENAMEITEM = 0x00000001,
        //A nonfolder item has been created. SHCNF_IDLIST or SHCNF_PATH must be specified in uFlags. dwItem1 contains the item that was created. dwItem2 is not used and should be NULL.
        SHCNE_CREATE = 0x00000002,
        //A nonfolder item has been deleted. SHCNF_IDLIST or SHCNF_PATH must be specified in uFlags. dwItem1 contains the item that was deleted. dwItem2 is not used and should be NULL.
        SHCNE_DELETE = 0x00000004,
        //A folder has been created. SHCNF_IDLIST or SHCNF_PATH must be specified in uFlags. dwItem1 contains the folder that was created. dwItem2 is not used and should be NULL.
        SHCNE_MKDIR = 0x00000008,
        //A folder has been removed. SHCNF_IDLIST or SHCNF_PATH must be specified in uFlags. dwItem1 contains the folder that was removed. dwItem2 is not used and should be NULL.
        SHCNE_RMDIR = 0x00000010,
        //Storage media has been inserted into a drive. SHCNF_IDLIST or SHCNF_PATH must be specified in uFlags. dwItem1 contains the root of the drive that contains the new media. dwItem2 is not used and should be NULL.
        SHCNE_MEDIAINSERTED = 0x00000020,
        //Storage media has been removed from a drive. SHCNF_IDLIST or SHCNF_PATH must be specified in uFlags. dwItem1 contains the root of the drive from which the media was removed. dwItem2 is not used and should be NULL.
        SHCNE_MEDIAREMOVED = 0x00000040,
        //A drive has been removed. SHCNF_IDLIST or SHCNF_PATH must be specified in uFlags. dwItem1 contains the root of the drive that was removed. dwItem2 is not used and should be NULL.
        SHCNE_DRIVEREMOVED = 0x00000080,
        //A drive has been added. SHCNF_IDLIST or SHCNF_PATH must be specified in uFlags. dwItem1 contains the root of the drive that was added. dwItem2 is not used and should be NULL.
        SHCNE_DRIVEADD = 0x00000100,
        //A folder on the local computer is being shared via the network. SHCNF_IDLIST or SHCNF_PATH must be specified in uFlags. dwItem1 contains the folder that is being shared. dwItem2 is not used and should be NULL.
        SHCNE_NETSHARE = 0x00000200,
        //A folder on the local computer is no longer being shared via the network. SHCNF_IDLIST or SHCNF_PATH must be specified in uFlags. dwItem1 contains the folder that is no longer being shared. dwItem2 is not used and should be NULL.
        SHCNE_NETUNSHARE = 0x00000400,
        //The attributes of an item or folder have changed. SHCNF_IDLIST or SHCNF_PATH must be specified in uFlags. dwItem1 contains the item or folder that has changed. dwItem2 is not used and should be NULL.
        SHCNE_ATTRIBUTES = 0x00000800,
        //The contents of an existing folder have changed, but the folder still exists and has not been renamed. SHCNF_IDLIST or SHCNF_PATH must be specified in uFlags. dwItem1 contains the folder that has changed. dwItem2 is not used and should be NULL. If a folder has been created, deleted, or renamed, use SHCNE_MKDIR, SHCNE_RMDIR, or SHCNE_RENAMEFOLDER, respectively, instead.
        SHCNE_UPDATEDIR = 0x00001000,
        //An existing nonfolder item has changed, but the item still exists and has not been renamed. SHCNF_IDLIST or SHCNF_PATH must be specified in uFlags. dwItem1 contains the item that has changed. dwItem2 is not used and should be NULL. If a nonfolder item has been created, deleted, or renamed, use SHCNE_CREATE, SHCNE_DELETE, or SHCNE_RENAMEITEM, respectively, instead.
        SHCNE_UPDATEITEM = 0x00002000,
        //The computer has disconnected from a server. SHCNF_IDLIST or SHCNF_PATH must be specified in uFlags. dwItem1 contains the server from which the computer was disconnected. dwItem2 is not used and should be NULL.
        SHCNE_SERVERDISCONNECT = 0x00004000,
        //An image in the system image list has changed. SHCNF_DWORD must be specified in uFlags. dwItem1 contains the index in the system image list that has changed. dwItem2 is not used and should be NULL.
        SHCNE_UPDATEIMAGE = 0x00008000,
        //A drive has been added and the Shell should create a new window for the drive. SHCNF_IDLIST or SHCNF_PATH must be specified in uFlags. dwItem1 contains the root of the drive that was added. dwItem2 is not used and should be NULL.
        SHCNE_DRIVEADDGUI = 0x00010000,
        //The name of a folder has changed. SHCNF_IDLIST or SHCNF_PATH must be specified in uFlags. dwItem1 contains the previous pointer to an item identifier list (PIDL) or name of the folder. dwItem2 contains the new PIDL or name of the folder.
        SHCNE_RENAMEFOLDER = 0x00020000,
        //The amount of free space on a drive has changed. SHCNF_IDLIST or SHCNF_PATH must be specified in uFlags. dwItem1 contains the root of the drive on which the free space changed. dwItem2 is not used and should be NULL.
        SHCNE_FREESPACE = 0x00040000,
        //Not currently used.
        SHCNE_EXTENDED_EVENT = 0x04000000,
        //A file type association has changed. SHCNF_IDLIST must be specified in the uFlags parameter. dwItem1 and dwItem2 are not used and must be NULL.
        SHCNE_ASSOCCHANGED = 0x08000000,
        //Specifies a combination of all of the disk event identifiers.
        SHCNE_DISKEVENTS = 0x0002381F,
        //Specifies a combination of all of the global event identifiers. 
        SHCNE_GLOBALEVENTS = 0x0C0581E0,
        //All events have occurred.
        SHCNE_ALLEVENTS = 0x7FFFFFFF,
        //The specified event occurred as a result of a system interrupt. As this value modifies other event values, it cannot be used alone.
        SHCNE_INTERRUPT = 0x80000000
    }

    private enum ShellChangeNotificationFlags
    {
        //dwItem1 and dwItem2 are the addresses of ITEMIDLIST structures that represent the item(s) affected by the change. Each ITEMIDLIST must be relative to the desktop folder. 
        SHCNF_IDLIST = 0x0000,
        //dwItem1 and dwItem2 are the addresses of null-terminated strings of maximum length MAX_PATH that contain the full path names of the items affected by the change.
        SHCNF_PATHA = 0x0001,
        //dwItem1 and dwItem2 are the addresses of null-terminated strings that represent the friendly names of the printer(s) affected by the change.
        SHCNF_PRINTERA = 0x0002,
        //The dwItem1 and dwItem2 parameters are DWORD values.
        SHCNF_DWORD = 0x0003,
        //like SHCNF_PATHA but unicode string
        SHCNF_PATHW = 0x0005,
        //like SHCNF_PRINTERA but unicode string
        SHCNF_PRINTERW = 0x0006,
        //?
        SHCNF_TYPE = 0x00FF,
        //The function should not return until the notification has been delivered to all affected components. As this flag modifies other data-type flags, it cannot by used by itself.
        SHCNF_FLUSH = 0x1000,
        //The function should begin delivering notifications to all affected components but should return as soon as the notification process has begun. As this flag modifies other data-type flags, it cannot by used  by itself.
   }
}

I hope to have others handed a welcome addition.

我希望有其他人提出欢迎补充。