从托管C#代码调用非托管c ++代码以生成脱机域加入blob

时间:2018-01-09 01:33:25

标签: c# c++ pinvoke native managed

我正在编写一个生成Offline Domain Join blob并保存以供将来使用的程序。可以使用命令提示符完成此操作。下面是一个示例命令,它将生成上述文件并将其保存在D盘上:

D:\djoin.exe /REUSE /PROVISION /DOMAIN MyDomain.MyCompany.com /MACHINE "user1-pc" /SAVEFILE blob.txt

更多信息:Offline Domain Join (Djoin.exe) Step-by-Step Guide

现在,我想在我的程序中添加一个方法(用C#编写)来为我执行此功能。

其中一个问题是,Microsoft提供的API是C ++ API。我尝试使用PInvoke在托管代码中使用API​​。以下是我写的代码。

using System;
using System.Runtime.InteropServices;

namespace TestBlob
{
    public class Program
    {
        static void Main(string[] args)
        {
            String domain = "MyDomain.MyCompany.com";
            String machineName = "user1-pc";
            String machineAccoutOU = null;
            String dcName = "MyDomain";
            uint options = 1;
            IntPtr provisionBinData = IntPtr.Zero;
            IntPtr provisionBinDataSize = IntPtr.Zero;
            string blob = string.Empty;
            IntPtr pProvisionTextData = Marshal.StringToHGlobalUni(blob);

            uint status = ODJNativeMethods.NetProvisionComputerAccount(domain, machineName, machineAccoutOU, dcName, options, ref provisionBinData, ref provisionBinDataSize, ref pProvisionTextData);

            Console.WriteLine(status);
            Console.WriteLine(Marshal.PtrToStringUni(pProvisionTextData));
            Console.Read();
        }
    }

    public static class NativeMethods
    {
        [DllImport("Netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern uint NetProvisionComputerAccount([In] String lpDomain,
                                                              [In] String lpMachineName,
                                                              [In] String lpMachineAccountOU,
                                                              [In] String lpDcName,
                                                              [In] uint dwOptions,
                                                              [In] [Out] ref IntPtr pProvisionBinData,
                                                              [In] [Out] ref IntPtr pdwProvisionBinDataSize,
                                                              [In] [Out] ref IntPtr pProvisionTextData);
    }
}

当我运行应用程序时,它总是返回87(在控制台上显示),在快速搜索之后结果是错误消息:参数无效。

我在这里做错了什么?我的PInvoke类型不是与本地语言API相对应的正确类型吗?

2 个答案:

答案 0 :(得分:0)

最后3个参数被声明为 out ,这意味着你不能初始化它们,但是传递正确的指针以便函数可以为你分配东西。

另外,根据我的理解,阅读函数doc,二进制文件和字符串一是相互排斥的,所以让我们说你想要取回二进制文件,然后就可以像这样定义API( [in]通常是隐含的):

    [DllImport("netapi32.dll", CharSet = CharSet.Unicode)]
    public static extern int NetProvisionComputerAccount(
        string lpDomain,
        string lpMachineName,
        string lpMachineAccountOU,
        string lpDcName,
        int dwOptions,
        out IntPtr pProvisionBinData,
        out int pdwProvisionBinDataSize,
        IntPtr pProvisionTextData);

请注意,该函数不使用SetLastError,因此请勿在声明中声明它。

以下是如何称呼它:

        string domain = "MyDomain.MyCompany.com";
        string machineName = "user1-pc";
        string machineAccoutOU = null;
        string dcName = "MyDomain";
        // I suggest you don't use hardcoded values to be nice with readers
        const int NETSETUP_PROVISION_DOWNLEVEL_PRIV_SUPPORT = 1;

        int status = NetProvisionComputerAccount(
            domain,
            machineName,
            machineAccoutOU,
            dcName,
            NETSETUP_PROVISION_DOWNLEVEL_PRIV_SUPPORT,
            out IntPtr binData, // let the system allocate the binary thing
            out int binDataSize, // this will be the size of the binary thing
            IntPtr.Zero); // we don't use this one here, pass null

我无法进一步测试(我得到错误1354,我认为在我的上下文中是正常的。)

请注意,doc没有说出解除分配函数分配的内容(如果它分配了什么?有一些罕见的Windows API使用它们拥有的静态缓冲区)。一旦所有工作完成,我认为你应该在binData上调用NetApiBufferFree,但这只是猜测。

答案 1 :(得分:-1)

它可能是您的文本文件的编码 - 如果您将其保存为ANSI并将其作为Unicode使用,则可能无效。

使用与上述代码相对应的这些陈述:

IntPtr pProvisionTextData = Marshal.StringToHGlobalAnsi(blob);

[DllImport("user32", CharSet=CharSet::Ansi)] 

希望它有所帮助。