zoukankan      html  css  js  c++  java
  • CSharp中的PInvoke

     
    可以调用C/C++中的一些函数非常实用
     

    Csharp中的数据类型

     
    后面使用的时候可能会用到
     

    PInvoke学习

    简单例子

     
    C++中我们可以使用 MessageBox() 函数来弹个窗,那么我们怎么在CSharp中调用这个函数呢
     
    这下面是代码
     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Text;
    
    namespace ConsoleApp6
    {
        class Program
        {
            [DllImport("user32.dll")]
            public static extern int MessageBox(int hWnd, String text, String caption, uint type);
    
            static void Main(string[] args)
            {
                MessageBox(0,"Mikasa","Hello",0);
            }
        }  
    }
    

     

     
    我们去微软的文档中看看这个函数的声明
     

     
    首先这个是位于 User32.dll 因此我们会有一行代码是使用 DllImport 导入
     
    函数定义如下
     

    int MessageBox(
      HWND    hWnd,
      LPCTSTR lpText,
      LPCTSTR lpCaption,
      UINT    uType
    );
    

     
    首先返回值是 int,因此我们写成int,LPCTSTR是个字符串因此我们写成C#中的字符串,UINT在Csharp存在,HWND我们写成int(这个不知道为啥,按理说HWND是一个句柄,应该用CSharp中对应的IntPtr表示0.0)
     
    参考至 https://www.pinvoke.net/search.aspx?search=MessageBox&namespace=user32
     
     

     
    这个网站我们可以查到很多的函数、结构体等
     

    Csharp添加用户

    旧代码

     
    以前使用 DirectoryEntry 来添加/删除用户的,代码如下
     
    参考至: https://docs.microsoft.com/zh-cn/troubleshoot/dotnet/csharp/add-user-local-system
     

    /*
     Study By https://docs.microsoft.com/zh-cn/troubleshoot/dotnet/csharp/add-user-local-system
     */
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.DirectoryServices;
    
    namespace NetUser
    {
        class Program
        {
            public static void AddUser(string username,string password)
            {
                try
                {
                    
                    DirectoryEntry AD = new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer");
                    DirectoryEntry NewUser = AD.Children.Add(username, "user");//Add User
                    NewUser.Invoke("SetPassword", new object[] { password });//Set Password
                    NewUser.Invoke("Put", new object[] { "Description", "Just For Record" });
                    NewUser.CommitChanges();
                    DirectoryEntry grp;
                    grp = AD.Children.Find("Administrators", "group");
                    if (grp != null) { grp.Invoke("Add", new object[] { NewUser.Path.ToString() }); }
                    Console.WriteLine("Account Create Successfully"); ;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
            public static void HeloMsg()
            {
                Console.WriteLine("Usage:NetUser.exe -a Saber Saber  //AddUser");
                Console.WriteLine("Usage:NetUser.exe -d Saber   // DelUser");
            }
            public static void DelUser(string username)
            {
                try
                {
                    DirectoryEntry AD = new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer");
                    DirectoryEntries ADD = AD.Children;
                    DirectoryEntry DelUser = ADD.Find(username,"user");
                    ADD.Remove(DelUser);
                    //AD.Children.Remove();
                    Console.WriteLine("Delete Success!");
                }
                catch(Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
            static void Main(string[] args)
            {
                if (args.Contains("-a"))
                {
                    AddUser(args[1],args[2]);
                }
                else if (args.Contains("-d"))
                {
                    DelUser(args[1]);
                }
                else
                {
                    HeloMsg();
                }
               
            }
        }
    }
    
    

     

     
    在360/火绒全开的时候也是可以绕过的
     

    新代码

     
    之前学习过使用Windows的API添加用户,参考文章 https://www.cnblogs.com/17bdw/p/6790197.html
     
    这里面我们试试能不能将他们改为CSharp的
     
    Native.cs
     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Text;
    
    namespace NetUserSomeThing
    {
        class Native
        {
            //定义USER_INFO_1结构体
            public  struct USER_INFO_1
            {
                [MarshalAs(UnmanagedType.LPWStr)]//设置为LPWStr类型
                public string usri1_name;
                public string usri1_password;
                public uint usri1_password_age;
                public uint usri1_priv;
                public string usri1_home_dir;
                public string usri1_comment;
                public uint usri1_flags;
                public string usri1_script_path;
            }
            [DllImport("netapi32.dll")]
            public static extern int NetUserAdd(string servername,uint level,ref USER_INFO_1 userinfo,string parm_err);
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
            public struct LOCALGROUP_MEMBERS_INFO_3
            {
                public string lgrmi3_domainandname;
            }
            [DllImport("netapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern int NetLocalGroupAddMembers(string servername,string groupname,uint level,ref LOCALGROUP_MEMBERS_INFO_3 buf,uint totalentries);
        }
    }
    

     
    Program.cs
     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Text;
    
    namespace NetUserSomeThing
    {
        class Native
        {
            //定义USER_INFO_1结构体
            public  struct USER_INFO_1
            {
                [MarshalAs(UnmanagedType.LPWStr)]//设置为LPWStr类型
                public string usri1_name;
                public string usri1_password;
                public uint usri1_password_age;
                public uint usri1_priv;
                public string usri1_home_dir;
                public string usri1_comment;
                public uint usri1_flags;
                public string usri1_script_path;
            }
            [DllImport("netapi32.dll")]
            public static extern int NetUserAdd(string servername,uint level,ref USER_INFO_1 userinfo,string parm_err);
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
            public struct LOCALGROUP_MEMBERS_INFO_3
            {
                public string lgrmi3_domainandname;
            }
            [DllImport("netapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern int NetLocalGroupAddMembers(string servername,string groupname,uint level,ref LOCALGROUP_MEMBERS_INFO_3 buf,uint totalentries);
        }
    }
    

     

     
    这次使用 PInvoke 的方法调用了C++的非托管代码实现使用Windows的API添加用户,说实话.NET框架真的有趣,C++也可以托管C#的代码(CS中的execute-Assem就是这个原理),下次有时间把这个完善一下,做一个只靠着WindowsApi实现 net user命令的工具,试着加载到CS岂不美哉

  • 相关阅读:
    VS2010 VC Project的default Include设置
    Linux 下的编辑/编译器
    用命令实现Win7远程桌面关机和重启
    怎样快速刪除Word中超链接?
    chrome浏览器世界之窗浏览器的收藏夹在哪?
    代码量查找工具[最好用的]
    C项目实践--网络协议和套接字编程
    memmove 和 memcopy
    bzoj2456: mode
    bzoj1205: [HNOI2005]星际贸易
  • 原文地址:https://www.cnblogs.com/Mikasa-Ackerman/p/CSharp-zhong-dePInvoke.html
Copyright © 2011-2022 走看看