c# - 在 C# 中使用 UpdateResource?

标签 c# .net resources icons

我正在尝试以编程方式更改外部可执行文件的图标。我用谷歌搜索并发现了很多关于使用 C++ 的问题的信息。基本上,我需要使用 BeginUpdateResource、UpdateResource 和 EndUpdateResource。问题是 - 我不知道在 C# 中将什么传递给 UpdateResource。

这是我目前的代码:

class IconChanger
{
    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr BeginUpdateResource(string pFileName,
        [MarshalAs(UnmanagedType.Bool)]bool bDeleteExistingResources);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool UpdateResource(IntPtr hUpdate, string lpType, string lpName, ushort wLanguage,
        IntPtr lpData, uint cbData);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);

    public enum ICResult
    {
        Success,
        FailBegin,
        FailUpdate,
        FailEnd
    }

    public ICResult ChangeIcon(string exeFilePath, byte[] iconData)
    {
        // Load executable
        IntPtr handleExe = BeginUpdateResource(exeFilePath, false);

        if (handleExe == null)
            return ICResult.FailBegin;

        // Get language identifier
        CultureInfo currentCulture = CultureInfo.CurrentCulture;
        int pid = ((ushort)currentCulture.LCID) & 0x3ff;
        int sid = ((ushort)currentCulture.LCID) >> 10;
        ushort languageID = (ushort)((((ushort)pid) << 10) | ((ushort)sid));

        // Get pointer to data
        GCHandle iconHandle = GCHandle.Alloc(iconData, GCHandleType.Pinned);

        // Replace the icon
        if (UpdateResource(handleExe, "#3", "#1", languageID, iconHandle.AddrOfPinnedObject(), (uint)iconData.Length))
        {
            if (EndUpdateResource(handleExe, false))
                return ICResult.Success;
            else
                return ICResult.FailEnd;
        }
        else
            return ICResult.FailUpdate;
    }
}

关于 lpType - 在 C++ 中,您传递 RT_ICON(或 RT_GROUP_ICON)。我应该在 C# 中传递什么值? lpName 参数也有同样的问题。 我不确定语言标识符(我在 Internet 上找到它),因为我无法对其进行测试。 我也不确定我是否提供了适当的图标数据。目前,iconData 包含来自 .ico 文件的字节。

谁能指出我正确的方向?

非常感谢。

最佳答案

只是一些提示,这很难做到正确。通过对 lpType 参数说谎来传递 RT_ICON。将其从字符串更改为 IntPtr 并传递 (IntPtr)3。

lpData 参数非常棘手。您需要按照资源编译器 (rc.exe) 编译数据的方式传递数据。我不知道它是否破坏了 .ico 文件的原始数据。唯一合理的尝试是使用 FileStream 将 .ico 文件中的数据读入字节 [],您似乎已经在这样做了。我认为该函数的真正设计目的是将资源从一个二进制图像复制到另一个二进制图像。您的方法奏效的可能性不为零。

您还忽略了另一个潜在问题,程序图标的资源 ID 不一定是 1。通常不是,100 往往是一个流行的选择,但任何事情都可以。需要 EnumResourceNames 才能使其可靠。规则是编号最小的 ID 设置文件的图标。我实际上不确定这是否真的意味着资源编译器将最小的数字放在第一位,而 API 可能不会这样做。

一个非常小的故障模式是 UpdateResource 只能更新编号的资源项,而不能更新命名的资源项。使用名称而不是数字并不少见,但绝大多数图像都使用数字作为图标。

当然,这在没有 UAC list 的情况下工作的可能性为零。您正在破解您通常没有写入权限的文件。

关于c# - 在 C# 中使用 UpdateResource?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4127785/

相关文章:

c# - "There were not enough free threads in the ThreadPool to complete the operation."

c# - C#错误CS1061 'object'不包含 'parameters'的定义

c# - 当 this == null 和 obj == null 时调用 IEquatable<T>.Equals(T obj) 的结果?

.net - 将 WCF .NET 3.5 发布到 IIS 6 (Windows Server 2003)

c# - 用于发送邮件的通知服务实现

c++ - SDL 和 Visual Studio 2010 资源

.net - 如何将完全定义的控件引用为 WPF 中的资源?

c# - 在 C# WinForm 中嵌入 Mappoint 2010 控件在 Win7(64 位)中创建注册表错误

android & libgdx - 如何对桌面和 android 项目只使用一次资源?

java - 将用 Java 编写的枚举转换为 C#