最近要实现一个替换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图标替换,不局限以上方法
指针在C#最通用的当然是IntPtr,但是,某些情况使用IntPtr反而不方便,像int *使用ref int可能更方便一些。回到你的问题,char *作为输入变量名的时候,可以用string,作为输出变量名的时候,可以用[MarshalAs(UnmanagedType.LPStr)] StringBuilder
现在问题是我该如何调用这个函数。
目前建了一个C#项目,引用了C++编译的dll。
string icoPath = @"D:\PlatForm\SL\APP.ico";
string exePath = @"D:\BCompare.exe";
IconConvert.ChangeExeIcon(icoPath, exePath);
错误是:与“IconHelper.IconConvert.ChangeExeIcon(char*, char*)”最匹配的重载方法具有一些无效参数
@贝荷伊米: 你的C++程序是如何编译的呢?C#要想调用C++,有以下几种方法:
1.C++代码采用C风格dll export
2.C++是一个标准COM,则可直接引用,VS会自动生成CCW
最后给几个链接:
@jello chen: 问题补充里面提供了C++程序源码和测试程序的源码。C++编译的dll直接引用到C#项目中,直接调用时参数有点拿不准。
@贝荷伊米: 公司环境访问不了云盘的,可以的话,传到博客园呗
@jello chen: 找了半天没发现上传附件的地方。百度了一下说是要开通博客才可以。正在申请开通中,暂时传不了
@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
@贝荷伊米: IconConvert的实现怎么扔到头文件里面了啊
@jello chen: 因为不会C++。不知道放哪里。您看看该放哪儿。cpp里面吧,就因为编译通过了,感觉也像有问题
@贝荷伊米: OK了,只是你那个ChangeExeIcon的方法无法实现改icon
@jello chen: 怎么弄的,不能改就不能改好了。能运行走就算了
@贝荷伊米:
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; };
@贝荷伊米:
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; }
@贝荷伊米:
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: 用图标提取工具提取修改过的exe程序图标,显示虽然没变,但是在视图为小图标的模式下是改变了的。应该是图标有几种规格,只修改到小图标了
@jello chen: 参考文章http://blog.csdn.net/chenlycly/article/details/45418447
@贝荷伊米: 不错,赞一个
@贝荷伊米: 建议写个博文记录一下,哈哈
UpdateResource(IntPtr hUpdate, string lpType, string lpName, ushort wLanguage, IntPtr lpData, uint cbData);
string icoPath = @"D:\PlatForm\SL\APP.ico";
string exePath = @"D:\BCompare.exe";
IconConvert.ChangeExeIcon(icoPath, exePath);
错误 1 与“IconHelper.IconConvert.ChangeExeIcon(char*, char*)”最匹配的重载方法具有一些无效参数
就是这个参数该怎么转换
@贝荷伊米: IconHelper.IconConvert.ChangeExeIcon(string, string)
把你方法里的char*改成string试试
@刘宏玺: 这个方法是C++里面提供的,问题上有C++源码
bool static ChangeExeIcon(LPWSTR IconFile, LPWSTR ExeFile)
@贝荷伊米: 你在提供下资源呗@"D:\PlatForm\SL\APP.ico";
"D:\BCompare.exe";
@刘宏玺: http://pan.baidu.com/s/1eQPQFwY
其实随便一个ico图标就行,exe也随便找个就可以
@贝荷伊米: 你把C#的项目属性改成x86
dll直接复制到bin文件夹
[DllImport("IconConverter.dll")]
private static extern bool ChangeExeIcon(string icoPath, string exePath);
@刘宏玺:首先,因为引用了IconConverter.dll,所以生成的时候IconConverter.dll会被拷贝到bin下。
运行时会报错误:
无法在 DLL“IconConverter.dll”中找到名为“ChangeExeIcon”的入口点。
C++代码放的地方不对么?