首页 新闻 会员 周边

C# exe程序图标替换问题

1
悬赏园豆:200 [已解决问题] 解决于 2016-03-15 09:10

最近要实现一个替换exe图标的功能,如qq.exe图标替换成酷狗的ico。
C#提取exe图标可用 
public static Icon ExtractAssociatedIcon(string filePath);
替换图标大概知道要用如下方法

方式一:
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr BeginUpdateResource(string pFileName, [MarshalAs(UnmanagedType.Bool)]bool bDeleteExistingResources);

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

[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);
问题:UpdateResource的参数不知道怎么传?

方式二:用C++代码编译dll,C#中引用使用,C++代码如下(网上抄的):

// IconConverter.h

#pragma once

#include <stdio.h>
#include <windows.h>
#include <tchar.h>

struct ICONDIRENTRY
{
    BYTE bWidth;
    BYTE bHeight;
    BYTE bColorCount;
    BYTE bReserved;
    WORD wPlanes;
    WORD wBitCount;
    DWORD dwBytesInRes;
    DWORD dwImageOffset;
};

struct ICONDIR
{
    WORD idReserved;
    WORD idType;
    WORD idCount;
    //ICONDIRENTRY idEntries;
};

struct GRPICONDIRENTRY
{
    BYTE bWidth;
    BYTE bHeight;
    BYTE bColorCount;
    BYTE bReserved;
    WORD wPlanes;
    WORD wBitCount;
    DWORD dwBytesInRes;
    WORD nID;
};
struct GRPICONDIR
{
    WORD idReserved;
    WORD idType;
    WORD idCount;
    GRPICONDIRENTRY idEntries;
};

using namespace System;

namespace IconHelper {

    public ref class IconConvert
    {
        // TODO: 在此处添加此类的方法。
        //////////////////////////////////////////////
        //函数说明:修改EXE图标
        //
        //参 数:IconFile 图标文件
        // ExeFile 被修改的EXE文件
        //
        //返回值: 成功为True,否则False
        /////////////////////////////////////////////
        public :
        bool static ChangeExeIcon(LPWSTR IconFile, LPWSTR ExeFile)
        {
            ICONDIR stID;
            ICONDIRENTRY stIDE;
            GRPICONDIR stGID;
            HANDLE hFile;
            DWORD nSize, nGSize, dwReserved;
            HANDLE hUpdate;
            PBYTE pIcon, pGrpIcon;
            BOOL ret;
            hFile = CreateFile(IconFile, GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
            if (hFile == INVALID_HANDLE_VALUE)
            {
                return false;
            }
            ZeroMemory(&stID, sizeof(ICONDIR));
            ret = ReadFile(hFile, &stID, sizeof(ICONDIR), &dwReserved, NULL);
            ZeroMemory(&stIDE, sizeof(ICONDIRENTRY));
            ret = ReadFile(hFile, &stIDE, sizeof(ICONDIRENTRY), &dwReserved, NULL);
            nSize = stIDE.dwBytesInRes;
            pIcon = (PBYTE)malloc(nSize);
            SetFilePointer(hFile, stIDE.dwImageOffset, NULL, FILE_BEGIN);
            ret = ReadFile(hFile, (LPVOID)pIcon, nSize, &dwReserved, NULL);
            if (!ret)
            {
                CloseHandle(hFile);
                return false;
            }
            ZeroMemory(&stGID, sizeof(GRPICONDIR));
            stGID.idCount = stID.idCount;
            stGID.idReserved = 0;
            stGID.idType = 1;
            CopyMemory(&stGID.idEntries, &stIDE, 12);
            stGID.idEntries.nID = 0;
            nGSize = sizeof(GRPICONDIR);
            pGrpIcon = (PBYTE)malloc(nGSize);
            CopyMemory(pGrpIcon, &stGID, nGSize);

            hUpdate = BeginUpdateResource(ExeFile, false);
            ret = UpdateResource(hUpdate, RT_GROUP_ICON, MAKEINTRESOURCE(1), 0, (LPVOID)pGrpIcon, nGSize);
            ret = UpdateResource(hUpdate, RT_ICON, MAKEINTRESOURCE(1), 0, (LPVOID)pIcon, nSize);
            EndUpdateResource(hUpdate, false);
            if (!ret)
            {
                CloseHandle(hFile);
                return false;
            }
            CloseHandle(hFile);
            return true;
        }
    };
}
问题:调用ChangeExeIcon方法需要传入参数类型为 char*,C#中如何表示?

其他语言实现参考:http://blog.csdn.net/aasmfox/article/details/24571111

问题补充:

源码:http://pan.baidu.com/s/1bosxbv5

也就是把这个简单程序调通

其中C#项目引用的dll源码:http://pan.baidu.com/s/1c0SC5B6

用到的资源:

http://pan.baidu.com/s/1eQPQFwY

 

C++源码放的位置可能有问题,放在头文件了。

目的:实现exe图标替换,不局限以上方法

贝荷伊米的主页 贝荷伊米 | 初学一级 | 园豆:6
提问于:2016-03-14 12:30
< >
分享
最佳答案
0

指针在C#最通用的当然是IntPtr,但是,某些情况使用IntPtr反而不方便,像int *使用ref int可能更方便一些。回到你的问题,char *作为输入变量名的时候,可以用string,作为输出变量名的时候,可以用[MarshalAs(UnmanagedType.LPStr)] StringBuilder

收获园豆:180
jello chen | 大侠五级 |园豆:7306 | 2016-03-14 12:58

现在问题是我该如何调用这个函数。

目前建了一个C#项目,引用了C++编译的dll。

string icoPath = @"D:\PlatForm\SL\APP.ico";
string exePath = @"D:\BCompare.exe";
IconConvert.ChangeExeIcon(icoPath, exePath);

错误是:与“IconHelper.IconConvert.ChangeExeIcon(char*, char*)”最匹配的重载方法具有一些无效参数

 

贝荷伊米 | 园豆:6 (初学一级) | 2016-03-14 13:56

@贝荷伊米: 你的C++程序是如何编译的呢?C#要想调用C++,有以下几种方法:

1.C++代码采用C风格dll export

2.C++是一个标准COM,则可直接引用,VS会自动生成CCW

3.C++启用CLR编译

最后给几个链接:

1.C# Interoperability

2.Mixed Assemblies

jello chen | 园豆:7306 (大侠五级) | 2016-03-14 14:32

@jello chen: 问题补充里面提供了C++程序源码和测试程序的源码。C++编译的dll直接引用到C#项目中,直接调用时参数有点拿不准。

贝荷伊米 | 园豆:6 (初学一级) | 2016-03-14 14:48

@贝荷伊米: 公司环境访问不了云盘的,可以的话,传到博客园呗

jello chen | 园豆:7306 (大侠五级) | 2016-03-14 14:58

@jello chen: 找了半天没发现上传附件的地方。百度了一下说是要开通博客才可以。正在申请开通中,暂时传不了

贝荷伊米 | 园豆:6 (初学一级) | 2016-03-14 15:12

@jello chen:

http://files.cnblogs.com/files/z-meng/WindowsApplication2.zip
http://files.cnblogs.com/files/z-meng/IconConverter.zip
http://files.cnblogs.com/files/z-meng/BCompare.zip

贝荷伊米 | 园豆:6 (初学一级) | 2016-03-14 16:07

@贝荷伊米: IconConvert的实现怎么扔到头文件里面了啊

jello chen | 园豆:7306 (大侠五级) | 2016-03-14 16:22

@jello chen: 因为不会C++。不知道放哪里。您看看该放哪儿。cpp里面吧,就因为编译通过了,感觉也像有问题

贝荷伊米 | 园豆:6 (初学一级) | 2016-03-14 16:33

@贝荷伊米: OK了,只是你那个ChangeExeIcon的方法无法实现改icon

jello chen | 园豆:7306 (大侠五级) | 2016-03-14 17:00

@jello chen: 怎么弄的,不能改就不能改好了。能运行走就算了

贝荷伊米 | 园豆:6 (初学一级) | 2016-03-14 17:05

@贝荷伊米: 

1.IconConverter.h

// IconConverter.h

#pragma once

#include <stdio.h>
#include <windows.h>
#include <tchar.h>

struct ICONDIRENTRY
{
    BYTE bWidth;
    BYTE bHeight;
    BYTE bColorCount;
    BYTE bReserved;
    WORD wPlanes;
    WORD wBitCount;
    DWORD dwBytesInRes;
    DWORD dwImageOffset;
};

struct ICONDIR
{
    WORD idReserved;
    WORD idType;
    WORD idCount;
    //ICONDIRENTRY idEntries;
};

struct GRPICONDIRENTRY
{
    BYTE bWidth;
    BYTE bHeight;
    BYTE bColorCount;
    BYTE bReserved;
    WORD wPlanes;
    WORD wBitCount;
    DWORD dwBytesInRes;
    WORD nID;
};

struct GRPICONDIR
{
    WORD idReserved;
    WORD idType;
    WORD idCount;
    GRPICONDIRENTRY idEntries;
};
jello chen | 园豆:7306 (大侠五级) | 2016-03-14 17:49

@贝荷伊米: 

2.IconConverter.cpp

// 这是主 DLL 文件。

#include "stdafx.h"

#include "IconConverter.h"

using namespace std;

// TODO: 在此处添加此类的方法。
//////////////////////////////////////////////
//函数说明:修改EXE图标
//
//参 数:IconFile 图标文件
// ExeFile 被修改的EXE文件
//
//返回值: 成功为True,否则False
/////////////////////////////////////////////
extern "C" _declspec(dllexport) bool _stdcall ChangeExeIcon(LPWSTR IconFile, LPWSTR ExeFile)
{
    ICONDIR stID;
    ICONDIRENTRY stIDE;
    GRPICONDIR stGID;
    HANDLE hFile;
    DWORD nSize, nGSize, dwReserved;
    HANDLE hUpdate;
    PBYTE pIcon, pGrpIcon;
    BOOL ret;
    hFile = CreateFile(IconFile, GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
    {
        return false;
    }
    ZeroMemory(&stID, sizeof(ICONDIR));
    ret = ReadFile(hFile, &stID, sizeof(ICONDIR), &dwReserved, NULL);
    ZeroMemory(&stIDE, sizeof(ICONDIRENTRY));
    ret = ReadFile(hFile, &stIDE, sizeof(ICONDIRENTRY), &dwReserved, NULL);
    nSize = stIDE.dwBytesInRes;
    pIcon = (PBYTE)malloc(nSize);
    SetFilePointer(hFile, stIDE.dwImageOffset, NULL, FILE_BEGIN);
    ret = ReadFile(hFile, (LPVOID)pIcon, nSize, &dwReserved, NULL);
    if (!ret)
    {
        CloseHandle(hFile);
        return false;
    }
    ZeroMemory(&stGID, sizeof(GRPICONDIR));
    stGID.idCount = stID.idCount;
    stGID.idReserved = 0;
    stGID.idType = 1;
    CopyMemory(&stGID.idEntries, &stIDE, 12);
    stGID.idEntries.nID = 0;
    nGSize = sizeof(GRPICONDIR);
    pGrpIcon = (PBYTE)malloc(nGSize);
    CopyMemory(pGrpIcon, &stGID, nGSize);

    hUpdate = BeginUpdateResource(ExeFile, false);
    ret = UpdateResource(hUpdate, RT_GROUP_ICON, MAKEINTRESOURCE(1), 0, (LPVOID)pGrpIcon, nGSize);
    ret = UpdateResource(hUpdate, RT_ICON, MAKEINTRESOURCE(1), 0, (LPVOID)pIcon, nSize);
    EndUpdateResource(hUpdate, false);
    if (!ret)
    {
        CloseHandle(hFile);
        return false;
    }
    CloseHandle(hFile);
    return true;
}
jello chen | 园豆:7306 (大侠五级) | 2016-03-14 17:50

@贝荷伊米: 

3.C#调用,这里用的最简单的控制台程序,其它也可以:

class Program
    {
        static void Main(string[] args)
        {
            string icoPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "APP.ico");
            string exePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "BCompare.exe");
            Console.WriteLine(ChangeExeIcon(icoPath, exePath));
            Console.ReadKey();
        }

        [DllImport(@"D:\Download\20160304\IconConverter\debug\IconConverter.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        public static extern bool ChangeExeIcon([MarshalAs(UnmanagedType.LPWStr)]string icoPath, [MarshalAs(UnmanagedType.LPWStr)]string exePath);
    }
jello chen | 园豆:7306 (大侠五级) | 2016-03-14 17:52

@贝荷伊米: 不能上传,只能贴给你了

jello chen | 园豆:7306 (大侠五级) | 2016-03-14 17:52

@jello chen: 用图标提取工具提取修改过的exe程序图标,显示虽然没变,但是在视图为小图标的模式下是改变了的。应该是图标有几种规格,只修改到小图标了

贝荷伊米 | 园豆:6 (初学一级) | 2016-03-15 09:44

@jello chen: 参考文章http://blog.csdn.net/chenlycly/article/details/45418447

贝荷伊米 | 园豆:6 (初学一级) | 2016-03-15 10:04

@贝荷伊米: 不错,赞一个

jello chen | 园豆:7306 (大侠五级) | 2016-03-15 11:07

@贝荷伊米: 建议写个博文记录一下,哈哈

jello chen | 园豆:7306 (大侠五级) | 2016-03-15 11:08
其他回答(1)
0

UpdateResource(IntPtr hUpdate, string lpType, string lpName, ushort wLanguage, IntPtr lpData, uint cbData);

hUpdate:指定更新文件句柄。此句柄由BeginUpdateResource函数返回。
lpType:指向说明将被更新的资源类型的字符串,它以NULL为终止符。这个参数可以是一个通过宏MAKENTRESOURCE传递的整数值,含义参见EnumResLangProc\lpType。
RT_ACCELERATOR -> 加速器表
RT_ANICURSOR -> 动态光标
RT_ANIICON -> 动态图标
RT_BITMAP -> 位图资源
RT_CURSOR -> 由硬件支持的光标资源
DI_DIALOG -> 对话框
RT_FONT -> 字体资源
RT_FONTDIR -> 字体目录资源
RT_GROUP_CURSOR -> 与硬件无关的光标资源
RT_GROUP_ICON -> 与硬件无关的目标资源
RT_HTML -> HTML文档
RT_ICON -> 由硬件支持的图标资源
RT_MENU -> 菜单资源
RT_MESSAGETABLE -> 消息表的入口
RT_PLUGPLAY -> 即插即用资源
RT_RCDATA -> 应用程序定义资源(原始数据自定义资源
RT_STRING -> 字符表入口
RT_VERSION -> 版本资源
RT_VXD -> VXD
lpName:指向说明待被更新的资源名称的字符串,它以NULL为终止符。这个参数可以是一个通过宏MAKEINTRESOURCE传递的整数值。
wLanguage:指定将被更新资源的语言标识。要了解基本的语言标识符以及由这些标识符组成的字语言标识符的列表,可参见宏MAKELANGID
lpData:指向被插入可执行文件的资源数据的指针。如果资源是预定义类型值之一,那么数据必须是有效且适当排列的。注意这是存储在可执行文件中原始的一进制数据,而不是由LoadlconLoadString或其他装载特殊资源函数提供的数据。所有包含字符串、文本的数据必须是Unicode格式;IpData不能指向ANSI数据。
如果lpData为NULL,所指定的资源将从可执行文件中被删除。
cbData:指定lpData中的资源数据数据大小,以字节计数。
 
 
char* 可以用string表示
收获园豆:20
刘宏玺 | 园豆:14020 (专家六级) | 2016-03-14 12:53

string icoPath = @"D:\PlatForm\SL\APP.ico";
string exePath = @"D:\BCompare.exe";
IconConvert.ChangeExeIcon(icoPath, exePath);

错误    1    与“IconHelper.IconConvert.ChangeExeIcon(char*, char*)”最匹配的重载方法具有一些无效参数

就是这个参数该怎么转换

支持(0) 反对(0) 贝荷伊米 | 园豆:6 (初学一级) | 2016-03-14 13:47

@贝荷伊米: IconHelper.IconConvert.ChangeExeIcon(string, string)

把你方法里的char*改成string试试

支持(0) 反对(0) 刘宏玺 | 园豆:14020 (专家六级) | 2016-03-14 13:54

@刘宏玺: 这个方法是C++里面提供的,问题上有C++源码

bool static ChangeExeIcon(LPWSTR IconFile, LPWSTR ExeFile)

支持(0) 反对(0) 贝荷伊米 | 园豆:6 (初学一级) | 2016-03-14 14:04

@贝荷伊米: 你在提供下资源呗@"D:\PlatForm\SL\APP.ico";
"D:\BCompare.exe";

支持(0) 反对(0) 刘宏玺 | 园豆:14020 (专家六级) | 2016-03-14 14:09

@刘宏玺: http://pan.baidu.com/s/1eQPQFwY

其实随便一个ico图标就行,exe也随便找个就可以

支持(0) 反对(0) 贝荷伊米 | 园豆:6 (初学一级) | 2016-03-14 14:13

@贝荷伊米: 你把C#的项目属性改成x86

dll直接复制到bin文件夹

[DllImport("IconConverter.dll")]
private static extern bool ChangeExeIcon(string icoPath, string exePath);

支持(0) 反对(0) 刘宏玺 | 园豆:14020 (专家六级) | 2016-03-14 15:28

@刘宏玺:首先,因为引用了IconConverter.dll,所以生成的时候IconConverter.dll会被拷贝到bin下。

运行时会报错误:

 无法在 DLL“IconConverter.dll”中找到名为“ChangeExeIcon”的入口点。

C++代码放的地方不对么?

支持(0) 反对(0) 贝荷伊米 | 园豆:6 (初学一级) | 2016-03-14 16:00
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册