2017-02-09 63 views
3

我有一個AutoIt腳本,它使用了未記錄的gdi32函數(GetFontResourceInfoW)(Autoit:_WinAPI_GetFontResourceInfo)。C#,Powershell,未編號的WinApi函數GetFontResourceInfoW

它返回一個字體文件的名稱(.fon,.ttf,.ttc等安裝或沒有) 該腳本工作完美。我想現在在Powershell中重新編碼它。 函數原型(從GetFontResourceInfo)是:

BOOL GetFontResourceInfo(LPCTSTR lpszFilename, // font file name 
         LPDWORD cbBuffer,  // size of buffer for resouce information 
         LPVOID lpBuffer,  // buffer for returned resouce information 
         DWORD dwQueryType, // resouce information query type 
         ); 

我嘗試以下,但它不返回的字體名稱。

[email protected]' 
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) 

我認爲參數或interop marshaling存在問題。

任何想法可能是錯的?

回答

0
out IntPtr lpBuffer 

這被錯誤地聲明。它應該是:

IntPtr lpBuffer 

然後調用函數變爲:

$ret=[fontutil]::GetFontResourceInfoW($fn, [ref] $b, $LocalStructPtr,[UInt32]1) 

你被傳遞指針變量的地址,而是你通過該指針變量的值。這是您撥打AllocHGlobal時分配的內存地址。

還要注意,由於UTF-16代碼單元是兩個字節寬,所以緩衝區可容納130個字符而不是260個字符。這可能很好,但它可能不是你所期待的。

0

封送字符串,StringBuilder是很多比手動分配的緩衝區左右擺弄更方便:

[email protected]' 
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#代碼以及(在封送不語言依賴),我只是認爲這是一個更清晰的關注點分離。