C#,Powershell,未记录的WinApi函数GetFontResourceInfoW
我有一个AutoIt脚本,它使用一个未记录的gdi32函数(GetFontResourceInfoW)(AutoIt:_WinAPI_GetFontResourceInfo) 它返回字体文件的名称(.fon、.ttf、.ttc等。是否已安装) 剧本写得很好。我现在想在Powershell中重新编码。 功能原型(来自)为: 我尝试了以下操作,但它没有返回fontnameC#,Powershell,未记录的WinApi函数GetFontResourceInfoW,c#,powershell,winapi,C#,Powershell,Winapi,我有一个AutoIt脚本,它使用一个未记录的gdi32函数(GetFontResourceInfoW)(AutoIt:_WinAPI_GetFontResourceInfo) 它返回字体文件的名称(.fon、.ttf、.ttc等。是否已安装) 剧本写得很好。我现在想在Powershell中重新编码。 功能原型(来自)为: 我尝试了以下操作,但它没有返回fontname $code=@' using System; using System.Collections.Generic; using S
$code=@'
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
public static class FontUtil{
[DllImport("gdi32.dll")]
public static extern bool GetFontResourceInfoW(string lpszFilename, ref UInt32 cbBuffer, out IntPtr lpBuffer, UInt32 dwQueryType);
}
'@
Add-Type $code
[string]$fn = 'c:\windows\fonts\arial.ttf'
[Uint32]$b = 260
[IntPtr]$LocalStructPtr = Runtime.InteropServices.Marshal]::AllocHGlobal(260)
$ret=[fontutil]::GetFontResourceInfoW($fn, [ref] $b, [ref] $LocalStructPtr,[UInt32]1)
[Runtime.InteropServices.Marshal]::PtrToStringAuto($LocalStructPtr,$b)
[Runtime.InteropServices.Marshal]::FreeHGlobal($LocalStructPtr)
我认为paramaters或互操作封送有问题
有什么想法吗
out IntPtr lpBuffer
这是不正确的声明。应该是:
IntPtr lpBuffer
然后函数调用变为:
$ret=[fontutil]::GetFontResourceInfoW($fn, [ref] $b, $LocalStructPtr,[UInt32]1)
您传递的是指针变量的地址,而不是指针变量的值。这是调用AllocHGlobal
时分配的内存地址
还要注意的是,您的缓冲区可以容纳130个字符,而不是260个字符,因为UTF-16代码单元的宽度是两个字节。这可能很好,但可能不是您所期望的。对于封送字符串,
StringBuilder
比手动分配缓冲区方便得多:
$code=@'
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.ComponentModel;
using System.Runtime.InteropServices;
public static class FontUtils {
const int QFR_DESCRIPTION = 1;
[DllImport("gdi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern bool GetFontResourceInfoW(
string lpszFilename,
[In, Out] ref int cbBuffer,
[Out] StringBuilder lpBuffer,
int dwQueryType
);
public static string GetFontDescription(string fileName) {
int bufferSize = 0;
StringBuilder sb = new StringBuilder();
if (!GetFontResourceInfoW(fileName, ref bufferSize, sb, QFR_DESCRIPTION)) {
throw new Win32Exception();
}
sb.Capacity = bufferSize / sizeof(char);
if (!GetFontResourceInfoW(fileName, ref bufferSize, sb, QFR_DESCRIPTION)) {
throw new Win32Exception();
}
return sb.ToString();
}
}
'@
Add-Type $code
[FontUtils]::GetFontDescription('c:\windows\fonts\arial.ttf')
当然,在PowerShell中编写C#代码也是完全可能的(封送拆收器不依赖于语言),我只是认为这是一种更清晰的关注点分离
$code=@'
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.ComponentModel;
using System.Runtime.InteropServices;
public static class FontUtils {
const int QFR_DESCRIPTION = 1;
[DllImport("gdi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern bool GetFontResourceInfoW(
string lpszFilename,
[In, Out] ref int cbBuffer,
[Out] StringBuilder lpBuffer,
int dwQueryType
);
public static string GetFontDescription(string fileName) {
int bufferSize = 0;
StringBuilder sb = new StringBuilder();
if (!GetFontResourceInfoW(fileName, ref bufferSize, sb, QFR_DESCRIPTION)) {
throw new Win32Exception();
}
sb.Capacity = bufferSize / sizeof(char);
if (!GetFontResourceInfoW(fileName, ref bufferSize, sb, QFR_DESCRIPTION)) {
throw new Win32Exception();
}
return sb.ToString();
}
}
'@
Add-Type $code
[FontUtils]::GetFontDescription('c:\windows\fonts\arial.ttf')