C#, Powershell, undocumeted WinApi function GetFontResourceInfoW C#, Powershell, undocumeted WinApi function GetFontResourceInfoW powershell powershell

C#, Powershell, undocumeted WinApi function GetFontResourceInfoW


out IntPtr lpBuffer

This is declared incorrectly. It should be:

IntPtr lpBuffer

Then the function call becomes:

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

You were passing the address of the pointer variable, but instead you pass that pointer variable's value. That's the address of the memory you allocated when you called AllocHGlobal.

Note also that your buffer has room for 130 characters rather than 260, because a UTF-16 code unit is two bytes wide. That's probably fine, but it might not be what you are expecting.


For marshaling strings, StringBuilder is a lot more convenient than mucking around with manually allocated buffers:

$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')

Of course, it's perfectly possible to write the C# code in PowerShell as well (the marshaler isn't language dependent), I just think this is a cleaner separation of concerns.