我正在编写一个生成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相对应的正确类型吗?
答案 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)]
希望它有所帮助。