【问题标题】:How do I load a resource string using an indirect string?如何使用间接字符串加载资源字符串?
【发布时间】:2017-07-08 20:12:26
【问题描述】:

我正在尝试转换HNetCfg.FwPolicy2 返回的防火墙规则的Grouping 属性中的间接字符串。在 PowerShell 中:

$fw = New-Object -ComObject 'HNetCfg.FwPolicy2'
$fw.Rules | Select-Object -ExpandProperty 'Grouping' | Select-Object -Unique

返回MSDN docs refer to as "indirect strings"

@mqutil.dll,-6102
@%windir%\system32\inetsrv\iisres.dll,-30503
@%windir%\system32\inetsrv\iisres.dll,-30501
@%ProgramFiles%\Hyper-V\SnapInAbout.dll,-211
@FirewallAPI.dll,-32752

如何将这些间接字符串转换为实际的组名在托管代码中

我正在尝试使用GetModuleHandle 加载模块/程序集,然后使用LoadString 加载字符串,但LoadString 不加载资源。这是我的代码:

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr GetModuleHandle(string lpModuleName);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern int LoadString(IntPtr hInstance, uint uID, StringBuilder lpBuffer, int nBufferMax);

[DllImport("kernel32.dll")]
private static extern uint GetLastError();

public static string GetGroupingFromResource(string resourceInfo)
{
    if (String.IsNullOrEmpty(resourceInfo))
    {
        return resourceInfo;
    }

    var matches = Regex.Match(resourceInfo, @"^@([^,]+),-(\d+)$");
    if (! matches.Success)
    {
        return resourceInfo;
    }

    var modulePath = matches.Groups[1].Value;
    UInt32 resourceID;
    if (!UInt32.TryParse(matches.Groups[2].Value, out resourceID))
    {
        return resourceInfo;
    }

    resourceID += 10000;

    Console.Out.WriteLine(string.Format("Assembly Path: {0}", modulePath));
    Console.Out.WriteLine(string.Format("Resource ID:   {0}", resourceID));

    modulePath = Environment.ExpandEnvironmentVariables(modulePath);

    var searchPaths = Environment.GetEnvironmentVariable("PATH").Split(';');
    if (! System.IO.Path.IsPathRooted(modulePath))
    {
        foreach (var searchPath in searchPaths)
        {
            var fullModulePath = System.IO.Path.Combine(searchPath, modulePath);
            if (System.IO.File.Exists(fullModulePath))
            {
                modulePath = fullModulePath;
                break;
            }
        }
    }

    Console.Out.WriteLine(string.Format("Module Path: {0}", modulePath));
    var moduleHandle = GetModuleHandle(modulePath);
    var lastError = GetLastError();
    Console.Out.WriteLine("Last Error: {0}", lastError);
    if (lastError != 0x0)
    {
        return null;
    }

    var grouping = new StringBuilder();
    LoadString(moduleHandle, resourceID, grouping, 255);
    lastError = GetLastError();
    Console.Out.WriteLine("Last Error: {0}", lastError);
    if (lastError != Win32ErrorCodes.Ok)
    {
        return null;
    }

    Console.Out.WriteLine(grouping.ToString());
    return grouping.ToString();

}

【问题讨论】:

  • 你需要使用SHLoadIndirectString
  • 在这样的 c++ 代码上WCHAR sz[1024];if (S_OK == SHLoadIndirectString(L"@FirewallAPI.dll,-32752", sz, RTL_NUMBER_OF(sz), 0)){..}
  • @RbMm 如果您将其添加为答案,我会接受。不过,不是 C++ 代码。

标签: c# .net winapi resourcebundle


【解决方案1】:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;

namespace ConsoleApp
{
    class Program
    {
        [DllImport("shlwapi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
        public static extern int SHLoadIndirectString(string pszSource, StringBuilder pszOutBuf, int cchOutBuf, IntPtr ppvReserved);

        static void Main(string[] args)
        {
            StringBuilder buffer = new StringBuilder(1024);

            string resourcePath = "@FirewallAPI.dll,-32752";

            int result = SHLoadIndirectString(resourcePath, buffer, buffer.Capacity, IntPtr.Zero);

            if (result == 0) Console.WriteLine(buffer.ToString()); // return "Network Discovery" on Windows 10 (1607)

            Console.ReadKey();
        }
    }
}

【讨论】:

    猜你喜欢
    • 2014-03-16
    • 2011-11-05
    • 2011-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多