C# 使用pinvoke和低级变量的Powershell
我正在尝试在PowerShell中创建一个脚本,从位于磁盘某处的.msi包中提取[ProductCode]。我发现我需要使用下面两种方法:和。基于此,我编写了下一个代码片段:C# 使用pinvoke和低级变量的Powershell,c#,powershell,winapi,pinvoke,C#,Powershell,Winapi,Pinvoke,我正在尝试在PowerShell中创建一个脚本,从位于磁盘某处的.msi包中提取[ProductCode]。我发现我需要使用下面两种方法:和。基于此,我编写了下一个代码片段: $signature_GetProperty = @' [DllImport("msi.dll", CharSet=CharSet.Unicode)] public static extern int MsiGetProperty( int hInstall, string szName, [Out] StringBuil
$signature_GetProperty = @'
[DllImport("msi.dll", CharSet=CharSet.Unicode)]
public static extern int MsiGetProperty(
int hInstall,
string szName,
[Out] StringBuilder szValueBuf,
ref int pchValueBuf);
'@
$signature_OpenPackage = @'
[DllImport("msi.dll", CharSet = CharSet.Unicode, PreserveSig = true, SetLastError = true, ExactSpelling = true)]
public static extern UInt32 MsiOpenPackageEx(
string szPackagePath,
UInt32 dwOptions,
void **hProduct);
'@
$OpenPackageType = Add-Type -MemberDefinition $signature_OpenPackage -Name "WinMsiOpenPackageEX" -Namespace Win32Functions -PassThru
$OpenPackageType::MsiOpenPackageEx($path, 1, STRUGGLING HERE)
$GetInfoType = Add-Type -MemberDefinition $signature_GetProperty -Name "WinGetProperty" -Namespace Win32GetProductCodeMSI -Using System.Text -PassThru
$GetInfoType::MsiGetProperty(AND HERE, "ProductCode",
我正在努力解决如何声明和使用定义为参数MsiGetProperty和MsiOpenPackageEx的变量
例如,OpenPackage中的最后一个参数是void**hProduct。我应该如何在.ps1脚本中声明它,以便以后在MsiGetProperty函数中使用。ref int pchValueBuf也是如此
对于这样一个蹩脚的问题,我很抱歉,但我非常感谢您对此类问题的任何帮助、澄清或文章。以下是我们内部使用的一个片段:
Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
using System.Text;
public static class Msi
{
public static string GetProductVersion(string fileName)
{
IntPtr hInstall = IntPtr.Zero;
try
{
uint num = MsiOpenPackage(fileName, ref hInstall);
if ((ulong)num != 0)
{
throw new Exception("Cannot open database: " + num);
}
int pcchValueBuf = 255;
StringBuilder szValueBuf = new StringBuilder(255);
num = MsiGetProperty(hInstall, "ProductVersion", szValueBuf, ref pcchValueBuf);
if ((ulong)num != 0)
{
throw new Exception("Failed to Get Property ProductVersion: " + num);
}
return szValueBuf.ToString();
}
finally
{
if(hInstall != IntPtr.Zero)
{
MsiCloseHandle(hInstall);
}
}
}
[DllImport("msi.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
private static extern int MsiCloseHandle(IntPtr hAny);
[DllImport("msi.dll", CharSet = CharSet.Unicode, EntryPoint = "MsiOpenPackageW", ExactSpelling = true, SetLastError = true)]
private static extern uint MsiOpenPackage(string szDatabasePath, ref IntPtr hProduct);
[DllImport("msi.dll", CharSet = CharSet.Unicode, EntryPoint = "MsiGetPropertyW", ExactSpelling = true, SetLastError = true)]
private static extern uint MsiGetProperty(IntPtr hInstall, string szName, [Out] StringBuilder szValueBuf, ref int pchValueBuf);
}
"@
[Msi]::GetProductVersion("R:\PathTo.msi")
这不是一个蹩脚的问题:-)您应该能够分别使用
[ref]$ptr
和[ref]$int
,其中$ptr
是[intptr]的已创建副本::零
和$int
是已实例化的整数。您可能需要将out
关键字添加到void**hProduct
parameter@MathiasR.Jessen首先,谢谢你的建议,它让我走上了正确的方向。但现在我面对的是一件让我震惊的事情。[链接]这是最后一个有错误的代码,我不知道如何修复。很抱歉打扰你和我太坚持了。C#中的无效指针需要标记为不安全,我能想到的唯一方法是在dllimport的旁边定义另一个C#方法,然后包装对MsiOpenPackageEx的调用-然后从PowerShellYeah调用C#方法,我将OpenPackage标记为不安全,并添加了-CompilerParameters$unsafe
。这显然是不够的。我想我理解你的建议,只是我现在没有那么熟练。无论如何,真的非常感谢你的帮助,我会试着把我的想法用在它上面,也许试着实施你的建议。再次感谢您的时间。我认为您应该能够将pchValueBuf
定义为out IntPtr
,而不是void**
。