从托管 C# 代码调用非托管 C++ 代码以生成离线域加入 blob
Calling unmanaged c++ code from managed C# code to generate offline domain join blob
我正在编写一段生成 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);
}
}
当我运行应用程序时,它总是returns87(在控制台上显示),快速搜索后发现是一条错误消息:参数无效。
我在这里做错了什么?我的 PInvoke 类型是否不是与母语对应的正确类型 API?
它可能是您的文本文件的编码 - 如果您将其保存为 ANSI 并以 Unicode 格式使用,它可能无法工作。
使用与上述代码相对应的语句:
IntPtr pProvisionTextData = Marshal.StringToHGlobalAnsi(blob);
和
[DllImport("user32", CharSet=CharSet::Ansi)]
希望对您有所帮助。
最后 3 个参数被声明为 out,这意味着您不能初始化它们,而是传递正确的指针以便函数可以为您分配内容。
此外,根据我阅读函数文档的理解,二进制一和字符串一是互斥的,所以假设你想取回二进制一,那么你可以定义 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,我认为这在我的上下文中是正常的)。
请注意,该文档没有说明任何关于取消分配函数分配的内容(如果它分配了一些东西?有一些罕见的 Windows API 使用他们拥有的静态缓冲区)。我认为您应该在完成所有工作后在 binData 上调用 NetApiBufferFree,但这只是一个猜测。
我正在编写一段生成 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);
}
}
当我运行应用程序时,它总是returns87(在控制台上显示),快速搜索后发现是一条错误消息:参数无效。
我在这里做错了什么?我的 PInvoke 类型是否不是与母语对应的正确类型 API?
它可能是您的文本文件的编码 - 如果您将其保存为 ANSI 并以 Unicode 格式使用,它可能无法工作。
使用与上述代码相对应的语句:
IntPtr pProvisionTextData = Marshal.StringToHGlobalAnsi(blob);
和
[DllImport("user32", CharSet=CharSet::Ansi)]
希望对您有所帮助。
最后 3 个参数被声明为 out,这意味着您不能初始化它们,而是传递正确的指针以便函数可以为您分配内容。
此外,根据我阅读函数文档的理解,二进制一和字符串一是互斥的,所以假设你想取回二进制一,那么你可以定义 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,我认为这在我的上下文中是正常的)。
请注意,该文档没有说明任何关于取消分配函数分配的内容(如果它分配了一些东西?有一些罕见的 Windows API 使用他们拥有的静态缓冲区)。我认为您应该在完成所有工作后在 binData 上调用 NetApiBufferFree,但这只是一个猜测。