用Vs编译Gh0st修改的工作量还是挺大的,毕竟从VC6.0移植到VS2010平台,已经是一个很大的跨越了,VS2010相对于VC6.0也改进了不止一点了。Gh0st3.6使用了第三方界面库CJ60Lib,目前这个库只支持到VC6.0,而其后的版本已经商业化,所以使用VS2010编译Gh0st的时候,需要重新编译CJ60Lib。VS2010的自带安装的Windows SDK已经到了7.1版,也不需要像VC6.0那样需要下载Windows SDK,并配置环境了。VC6.0支持的最高版本的Windows SDK 是Windows 2003的,而VS2010自带的7.1版已经到了Windows Server 2008 了,其中发生的变化也是很大的。下面具体来操作一次。
先列一下几个主要下文件路径。用的是Gh0s3.6原版,硬盘锁代码已经注释。
E:\Programming\VS2010\Gh0st3.6
E:\Programming\VS2010\Gh0st3.6\gh0st.dsw
E:\Programming\VS2010\Gh0st3.6\gh0st\CJ60Lib
E:\Programming\VS2010\Gh0st3.6\gh0st\CJ60Lib\CJ60Lib\CJ60Lib.dsw
E:\Programming\VS2010\Gh0st3.6\gh0st\CJ60Lib\Lib
一.编译CJ60Lib库
直接用VS2010打开CJ60Lib.dsw进行转换。一共有7个,有4个是已经不存在的项目了,直接删掉。
在灰色的项目上点右键–Remove,或直接按Del键删除。
1.1编译CJ60StaticLib
直接在CJ60StaticLib项目上点右键— Project Only —- Build Only CJ60StaticLib或者是 Rebuild Only CJ60StaticLib。以后说编译某个项目也是这样,不再重复说明了。
1.1.1
首先修改程序配置,让默认的字符都为ANSI字符,VS2010默认为宽字符Unicode版。
项目—右键—属性—C/C++—Language—WChar_t—No,如图所示:
修改编译后,对照错误,再来一个一个的修改。
1.1.2
1> stdafx.cpp
1> _WIN32_WINNT not defined. Defaulting to _WIN32_WINNT_MAXVER (see WinSDKVer.h)
1>e:\programming\vs2010\gh0st3.6\gh0st\cj60lib\cj60lib\stdafx.h(51): fatal error C1083: 无法打开包括文件:“..\src\afximpl.h”: No such file or directory
双击这个错误,定位到 stdafx.h 中的
#include <..\src\afximpl.h>
把这句话改成
#include <..\src\mfc\afximpl.h>
1.1.3
接着修改warning C4819警告
warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode格式以防止数据丢失
这个警告至需要双击打开该文件,然后保存就可以了。
1.1.4
gh0st3.6\gh0st\cj60lib\cj60lib\subclass.cpp(117): error C2065: “p”: 未声明的标识符
这是因为VS更符号C++标准,临时变量的作用域已经修正了,在Gh0st里,可以看到很多这样的代码。只要把在for或if里面定义的变量,放到for或if之前定义就好了。
这里的代码是:
for (CSubclassWnd* p = theHookMap.Lookup(m_hWnd); p; p=p->m_pNext)
修改为
CSubclassWnd* p = NULL;
for (p = theHookMap.Lookup(m_hWnd); p; p=p->m_pNext)
后面的i也是一样修改。
gh0st3.6\gh0st\cj60lib\cj60lib\coolmenu.cpp(803): error C2065: “i”: 未声明的标识符
for (i=0; i < nFound; i++) {
这里的i,是在前面的
for (UINT i=0; i< nItem; i++)
里面定义的,只要把for里面的i放到for之前定义就可以了,修改如下:
UINT i=0;
for (i=0; i< nItem; i++)
这样的错误修改,以后不再写出,因为实在是太多了,修改方法也很简单。
1.1.5
gh0st3.6\gh0st\cj60lib\cj60lib\coolmenu.cpp(76): error C4430: 缺少类型说明符 –假定为 int。注意: C++ 不支持默认 int
在VC6.0里,用修饰符申明的变量可以不现式的写出变量类型,默认类型为int。如这里的const CXGAP = 1; 等于 const int CXGAP = 1; 但是VS2010必须现式的指出,不能省略。所以修改方法就是现式的写上定义类型。
// constants used for drawing
const CXGAP = 1; // num pixels between button and text
const CXTEXTMARGIN = 2; // num pixels after hilite to start text
const CXBUTTONMARGIN = 2; // num pixels wider button is than bitmap
const CYBUTTONMARGIN = 2; // ditto for height
修改如下:
// constants used for drawing
const int CXGAP = 1; // num pixels between button and text
const int CXTEXTMARGIN = 2; // num pixels after hilite to start text
const int CXBUTTONMARGIN = 2; // num pixels wider button is than bitmap
const int CYBUTTONMARGIN = 2; // ditto for height
这个在Gh0st里有,以后这个错误也不在指出。
1.1.6
接下来要解决的就是一大堆的重定义错误了
1>c:\program files\microsoft sdks\windows\v7.0a\include\shlwapi.h(126): error C2011: “tagSFBS_FLAGS”:“enum”类型重定义
1> c:\program files\microsoft sdks\windows\v7.0a\include\shlwapi.h(126) : 参见“tagSFBS_FLAGS”的声明
1>c:\program files\microsoft sdks\windows\v7.0a\include\shlwapi.h(251): error C2084: 函数“HRESULT SHLocalStrDupW(LPCWSTR,LPWSTR *)”已有主体
1> c:\program files\microsoft sdks\windows\v7.0a\include\shlwapi.h(250) : 参见“SHLocalStrDupW”的前一个定义
1>c:\program files\microsoft sdks\windows\v7.0a\include\shlwapi.h(256): error C2084: 函数“HRESULT SHLocalStrDupA(LPCSTR,LPSTR *)”已有主体
1> c:\program files\microsoft sdks\windows\v7.0a\include\shlwapi.h(255) : 参见“SHLocalStrDupA”的前一个定义
1>c:\program files\microsoft sdks\windows\v7.0a\include\shlwapi.h(860): error C2365: “URL_SCHEME_INVALID”: 重定义;以前的定义是“枚举数”
1> c:\program files\microsoft sdks\windows\v7.0a\include\shlwapi.h(860) : 参见“URL_SCHEME_INVALID”的声明
1>c:\program files\microsoft sdks\windows\v7.0a\include\shlwapi.h(861): error C2365: “URL_SCHEME_UNKNOWN”: 重定义;以前的定义是“枚举数”
1> c:\program files\microsoft sdks\windows\v7.0a\include\shlwapi.h(861) : 参见“URL_SCHEME_UNKNOWN”的声明
1>c:\program files\microsoft sdks\windows\v7.0a\include\shlwapi.h(862): error C2365: “URL_SCHEME_FTP”: 重定义;以前的定义是“枚举数”
1> c:\program files\microsoft sdks\windows\v7.0a\include\shlwapi.h(862) : 参见“URL_SCHEME_FTP”的声明
1>c:\program files\microsoft sdks\windows\v7.0a\include\shlwapi.h(863): error C2365: “URL_SCHEME_HTTP”: 重定义;以前的定义是“枚举数”
1> c:\program files\microsoft sdks\windows\v7.0a\include\shlwapi.h(863) : 参见“URL_SCHEME_HTTP”的声明
1>c:\program files\microsoft sdks\windows\v7.0a\include\shlwapi.h(864): error C2365: “URL_SCHEME_GOPHER”: 重定义;以前的定义是“枚举数”
1> c:\program files\microsoft sdks\windows\v7.0a\include\shlwapi.h(864) : 参见“URL_SCHEME_GOPHER”的声明
1>c:\program files\microsoft sdks\windows\v7.0a\include\shlwapi.h(865): error C2365: “URL_SCHEME_MAILTO”: 重定义;以前的定义是“枚举数”
1> c:\program files\microsoft sdks\windows\v7.0a\include\shlwapi.h(865) : 参见“URL_SCHEME_MAILTO”的声明
1>c:\program files\microsoft sdks\windows\v7.0a\include\shlwapi.h(866): error C2365: “URL_SCHEME_NEWS”: 重定义;以前的定义是“枚举数”
1> c:\program files\microsoft sdks\windows\v7.0a\include\shlwapi.h(866) : 参见“URL_SCHEME_NEWS”的声明
造成这个原因是ATL和CJLIB库的兼容性问题上,从错误上看是shlwapi.h里的代码被重定义了,ATL在定义前都会判断一下是否已经定义,而CJLIB则没有判断。解决方法是把CJLIB中的shlwapi.h包含给注释掉。可以在当前项目搜索shlwapi.h,一共有两处。
E:\Programming\VS2010\Gh0st3.6\gh0st\CJ60Lib\Include\ModulVer.h
E:\Programming\VS2010\Gh0st3.6\gh0st\CJ60Lib\Include\ShellTree.h
把其中的 #include
重新编译后,错误一下少了很多,看起来也清爽了许多。
1.1.7
gh0st3.6\gh0st\cj60lib\cj60lib\cjsizedockbar.cpp(89): error C2440:“static_cast”: 无法从“UINT (__thiscall CCJSizeDockBar::* )(CPoint)”转换为“LRESULT (__thiscall CWnd::* )(CPoint)”
1> 从基类型到派生类型的强制转换需要 dynamic_cast 或 static_cast
这句话定位到的是ON_WM_NCHITTEST(),其实就是消息响应函数的返回值类型不匹配,这里也可以看出VS2010和VC6.0的不同。ON_WM_NCHITTEST对应的消息函数是UINTCCJSizeDockBar::OnNcHitTest(CPoint point) ,把返回值类型改下就好了。有两处:
E:\Programming\VS2010\Gh0st3.6\gh0st\CJ60Lib\CJ60Lib\CJSizeDockBar.cpp
UINT CCJSizeDockBar::OnNcHitTest(CPoint point)
修改为:
LRESULT CCJSizeDockBar::OnNcHitTest(CPoint point)
E:\Programming\VS2010\Gh0st3.6\gh0st\CJ60Lib\Include\CJSizeDockBar.h
afx_msg UINT OnNcHitTest(CPoint point);
修改为:
afx_msg LRESULT OnNcHitTest(CPoint point);
后面还有一个一样的错误,只是所在类不一样,修改方法还是一样的
gh0st3.6\gh0st\cj60lib\cj60lib\cjcontrolbar.cpp(155): error C2440:“static_cast”: 无法从“UINT (__thiscall CCJControlBar::* )(CPoint)”转换为“LRESULT (__thiscall CWnd::* )(CPoint)”
1> 从基类型到派生类型的强制转换需要 dynamic_cast 或 static_cast
这里就不再说了,请参考上面的修改。
1.1.8
gh0st3.6\gh0st\cj60lib\cj60lib\cjpagerctrl.cpp(75): error C2440: “static_cast”:无法从“BOOL (__thiscall CCJPagerCtrl::* )(NMPGSCROLL *,LRESULT *)”转换为“BOOL (__thiscall CCmdTarget::* )(NMHDR *,LRESULT *)”
1> 在匹配目标类型的范围内没有具有该名称的函数
gh0st3.6\gh0st\cj60lib\cj60lib\cjpagerctrl.cpp(76): error C2440: “static_cast”:无法从“BOOL (__thiscall CCJPagerCtrl::* )(NMPGCALCSIZE *,LRESULT *)”转换为“BOOL (__thiscall CCmdTarget::* )(NMHDR *,LRESULT *)”
1> 在匹配目标类型的范围内没有具有该名称的函数
这两处的错误都是一样的,都是同一种参数类型不匹配。定位信息:
ON_NOTIFY_REFLECT_EX(PGN_SCROLL, OnPagerScroll)
ON_NOTIFY_REFLECT_EX(PGN_CALCSIZE, OnPagerCalcSize)
可以看出他们所对应的函数分别是OnPagerScroll和OnPagerCalcSize。直接在上面按F12(右键–跳转到定义处)就跳转到函数定义出了。
E:\Programming\VS2010\Gh0st3.6\gh0st\CJ60Lib\CJ60Lib\CJPagerCtrl.cpp
BOOL CCJPagerCtrl::OnPagerScroll(NMPGSCROLL* pNMPGScroll, LRESULT* pResult)
{
*pResult = 0;
return FALSE; // Let parent handle message
}
修改如下:
BOOL CCJPagerCtrl::OnPagerScroll(NMHDR* pNMPGScroll, LRESULT* pResult)
{
*pResult = 0;
return FALSE; // Let parent handle message
}
===================================================
BOOL CCJPagerCtrl::OnPagerCalcSize(NMPGCALCSIZE* pNMPGCalcSize, LRESULT*pResult)
{
switch(pNMPGCalcSize->dwFlag)
修改如下:
BOOL CCJPagerCtrl::OnPagerCalcSize(NMHDR* pNMHDRPGCalcSize, LRESULT* pResult)
{
NMPGCALCSIZE *pNMPGCalcSize = (NMPGCALCSIZE *)pNMHDRPGCalcSize;
switch(pNMPGCalcSize->dwFlag)
===================================================
接着修改头文件中申明的参数类型
E:\Programming\VS2010\Gh0st3.6\gh0st\CJ60Lib\Include\CJPagerCtrl.h
virtual BOOL OnPagerScroll(NMPGSCROLL* pNMPGScroll, LRESULT * pResult);
virtual BOOL OnPagerCalcSize(NMPGCALCSIZE * pNMPGCalcSize, LRESULT* pResult);
修改如下:
virtual BOOL OnPagerScroll(NMHDR* pNMPGScroll, LRESULT * pResult);
virtual BOOL OnPagerCalcSize(NMHDR* pNMHDRPGCalcSize, LRESULT* pResult);
1.2 编译CJ60Lib
首先还是修改字符集为ANSI,不然默认为WChar_t。这步是编译Gh0st每一个项目都需要做的,以后的操作中不再提起,请注意。如果提示A函数和W函数重定义,参数冲突等,都是这个问题,改下项目属性就能解决了。
wchar_t *类型与USHORT *的转换错误
VC6的编译器不支持wchar_t数据类型,wchar_t实际上被定义成unsigned short,VC9的编译器已经支持wchar_t为内置数据类型,但是由一个编译选项控制,这个选项默认是打开的,也就是将wchar_t作为编译器的内置数据类型。但是OLECHAR和WCHAR的定义仍然是unsigned short,在VC6的编译环境中,两者的指针都是USHORT *,相互赋值和做为函数参数传递没有问题,但是如果wchar_t作为编译器的内置数据类型,那就意味着wchar_t *与OLECHAR *或WCHAR *是两种不同类型的指针,相互赋值就会报编译错误,下面的信息就是一个典型的错误输出:
f:\project\.....\shellpidl.cpp(290) : error C2664: 'MultiByteToWideChar' : cannot convert parameter 5 from 'USHORT *' to 'LPWSTR'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
解决的方法就是使用C++的reinterpret_cast操作符或使用C-style强制转换,当然也可以在项目属性设置中关闭前面提到的那个选项。
这个直接编译就能过了。用VS2010编译函数很多安全函数的警告,这个不用管他,想修改也是可以的。还有一个_WIN32_WINNT宏未定义的警告,如非必要,我就不加上去了,尽量的保持和原版的相同。要加的话,直接加在每个项目的StdAfx.h里面。
格式:#define _WIN32_WINNT 0x0500
这里的参数含义可以参看MSDN,后面有一处修改必须加,也会再次提到。
二.编译Gh0st
成功编译CJ60Lib界面库之后,就可以开始编译Gh0st了。
2.1 转换Gh0st3.6项目
直接用VS2010打开Gh0st3.6\gh0st.dsw 提示转换项目,确定转换就行了。这里一共三个项目:gh0st,install,svchost。编译的时候需要先编译svchost再编译install,最后才编译gh0st。
2.2 编译svchost
相同的错误修改就不再说了,参看前面的修改方法。
修改已说过的错误,再继续下面的错误修改。
2.2.1
1>common\FileManager.cpp(202): error C2440:“初始化”: 无法从“const char *”转换为“char *”
1> 转换丢失限定符
char *lpExt = strrchr(lpFile, ‘.’);
修改为:
const char *lpExt = strrchr(lpFile, ‘.’);
1>e:\programming\vs2010\gh0st3.6\server\svchost\common\loop.h(160): error C2440:“=”: 无法从“const char *”转换为“char *”
1> 转换丢失限定符
char *lpFileName = NULL;
lpFileName = strrchr(lpURL, ‘/’) + 1;
修改为:
Const char *lpFileName = NULL;
lpFileName = strrchr(lpURL, ‘/’) + 1;
2.2.2
1>common\ScreenSpy.cpp(355): error C2062: 意外的类型“int”
for (inti = 0, intnToJump = 0; i < nHeight; i += nToJump)
修改为:
int i=0;
for (i = 0, nToJump = 0; i < nHeight; i += nToJump)
2.2.3
1>common\VideoManager.cpp(123): error C4430: 缺少类型说明符 – 假定为 int。注意: C++ 不支持默认 int
定位在:
static dwLastScreen = GetTickCount();
这个错误前面已经提到过,是添加现式定义类型int。这里添加现式类型为 DWORD 比较好,因为后面的函数GetTickCount返回值是DWORD类型。在这里修改如下:
static DWORD dwLastScreen = GetTickCount();
2.2.4
1>common\ScreenManager.cpp(7): fatal error C1083: 无法打开包括文件:“winable.h”: No such file or directory
Winable头文件从VS2008里面就已经不存在了,MSDN里描述如下:
从 Visual Studio 早期版本升级项目时,您可能必须修改 WINVER 和 _WIN32_WINNT 宏,以便它们大于或等于 0×0500。
已移除 Windows API 头文件 Winable.h。而改为包括 Winuser.h。
因为Winuser默认已经包含进来了,所以直接注释这句话就行了。但是如果直接这样,引用Winable中的函数就会出现未定义错误。所以这里除了需要注释这个头文件包含,还需要注释这个文件中的_WIN32_WINNT宏定义,或者修改宏定义大于等于500。我这里直接注释掉了。
#define_WIN32_WINNT 0×0400
#include"ScreenManager.h"
#include"until.h"
#include
修改为:
//#define _WIN32_WINNT 0×0400
#include"ScreenManager.h"
#include"until.h"
//#include
2.3 编译install
这个能直接编译通过,就算不修改默认字符集,但还是建议和前面一样,修改下默然字符。
2.4 编译gh0st
一开始编译就会有个错误提示而终止,如果不修改没法正常编译。
1>C:\Program Files\Microsoft Visual Studio 10.0\VC\atlmfc\include\afx.h(24): fatal error C1189: #error : Building MFC application with /MD[d] (CRT dll version) requires MFC shared dll version. Please #define _AFXDLL or do not use /MD[d]
这个还是需要修改属性页。需要把代码生成里的运行时库改成/MT。如图:
修改之后重新编译就能看到很多错误了。在继续下面的错误修改之前,先把前面讲到的错误类型给修改好。
2.4.1
1>control\BtnST.cpp(4): fatal error C1083: 无法打开包括文件:“stdafx.h”: No such file or directory
提示找不到stdafx.h,其实这个文件是存在的。在属性里添加“./”的包含目录就能解决了。
在属性页的C/C++—General—Additional Include Directories 里添加。
原来的是:
CJ60lib/Include;../common;%(AdditionalIncludeDirectories)
修改后为:
./;CJ60lib/Include;../common;%(AdditionalIncludeDirectories)
如图:
2.4.2
1>e:\programming\vs2010\gh0st3.6\gh0st\TmSchema.h(27): error C2011:“BGTYPE”:“enum”类型重定义
1> C:\Program Files\Microsoft SDKs\Windows\v7.0A\include\vssym32.h(14) : 参见“BGTYPE”的声明
1>e:\programming\vs2010\gh0st3.6\gh0st\TmSchema.h(33): error C2011: “IMAGELAYOUT”:“enum”类型重定义
1> C:\Program Files\Microsoft SDKs\Windows\v7.0A\include\vssym32.h(25) : 参见“IMAGELAYOUT”的声明
1>e:\programming\vs2010\gh0st3.6\gh0st\TmSchema.h(38): error C2011: “BORDERTYPE”:“enum”类型重定义
1> C:\Program Files\Microsoft SDKs\Windows\v7.0A\include\vssym32.h(35) : 参见“BORDERTYPE”的声明
1>e:\programming\vs2010\gh0st3.6\gh0st\TmSchema.h(44): error C2011: “FILLTYPE”:“enum”类型重定义
1> C:\Program Files\Microsoft SDKs\Windows\v7.0A\include\vssym32.h(46) : 参见“FILLTYPE”的声明
1>e:\programming\vs2010\gh0st3.6\gh0st\TmSchema.h(52): error C2011: “SIZINGTYPE”:“enum”类型重定义
1> C:\Program Files\Microsoft SDKs\Windows\v7.0A\include\vssym32.h(59) : 参见“SIZINGTYPE”的声明
1>e:\programming\vs2010\gh0st3.6\gh0st\TmSchema.h(58): error C2011: “HALIGN”:“enum”类型重定义
1> C:\Program Files\Microsoft SDKs\Windows\v7.0A\include\vssym32.h(70) : 参见“HALIGN”的声明
1>e:\programming\vs2010\gh0st3.6\gh0st\TmSchema.h(64): error C2011: “CONTENTALIGNMENT”:“enum”类型重定义
1> C:\Program Files\Microsoft SDKs\Windows\v7.0A\include\vssym32.h(81) : 参见“CONTENTALIGNMENT”的声明
1>e:\programming\vs2010\gh0st3.6\gh0st\TmSchema.h(70): error C2011: “VALIGN”:“enum”类型重定义
又是一堆的类型重定义错误,这次需要现式的指出Windows版本才能解决这个问题。打开stdafx.h,在其中添加 #define _WIN32_WINNT 0×0500 。下面是我的操作,实际放置的位置可以自己调整。
E:\Programming\VS2010\Gh0st3.6\gh0st\StdAfx.h
#define VC_EXTRALEAN// Exclude rarely-used stuff from Windows headers
#include
#include
#include
修改如下:
#define VC_EXTRALEAN// Exclude rarely-used stuff from Windows headers
#define _WIN32_WINNT 0×0500
#include
#include
#include
这里就说下参数的含义,0×0500是指Windows 2000,这个宏定义说明这个程序只是要在Windows 2000 及以上的操作系统上才能正常运行。0×0501 Windows XP、0×0502 Windows Server 2003、 0×0600 Windows Vista、0×0601 Windows 7。
2.4.3
1>TrueColorToolBar.cpp(42): error C2440:“static_cast”: 无法从“void (__thiscall CTrueColorToolBar::* )(NMTOOLBARA *,LRESULT *)”转换为“void (__thiscall CCmdTarget::* )(NMHDR *,LRESULT *)”
1> 在匹配目标类型的范围内没有具有该名称的函数
这个和1.1.8是一样的。这里再说下。
定位到:
ON_NOTIFY_REFLECT(TBN_DROPDOWN, OnToolbarDropDown)
可以在OnToolbarDropDown上点右键跳转到定义(F12),跳转到申明(Ctrl+Alt+F12)
E:\Programming\VS2010\Gh0st3.6\gh0st\TrueColorToolBar.cpp
Void CTrueColorToolBar::OnToolbarDropDown(NMTOOLBAR* pnmtb, LRESULT *plr)
{
for (inti = 0; i < m_lstDropDownButton.GetSize(); i++) {
修改如下:
Void CTrueColorToolBar::OnToolbarDropDown(NMHDR* NMHDRpnmtb, LRESULT *plr)
{
NMTOOLBARA *pnmtb = (NMTOOLBARA *)NMHDRpnmtb;
int i=0;
for (i = 0; i < m_lstDropDownButton.GetSize(); i++) {
E:\Programming\VS2010\Gh0st3.6\gh0st\TrueColorToolBar.h
afx_msg void OnToolbarDropDown(NMTOOLBAR* pnmh, LRESULT* plRes);
修改如下:
afx_msg void OnToolbarDropDown(NMHDR* NMHDRpnmtb, LRESULT* plRes);
2.5
Gh0st就只有这些错误了。下一节将讲解连接错误。
三.解决连接错误
到现在为止,所以代码已经没有任何错误了,但在Gh0st还是编译不成功,而错误全部是在连接错误上。下面来解决掉这些链接错误。
3.1 CJ60StaticLib链接库错误
首先我们看到的是CJ60StaticLib的链接错误
1>CJ60StaticLib.lib(CJListView.obj) : error LNK2001: 无法解析的外部符号 "protected: static struct AFX_MSGMAP const CListView::messageMap" (?messageMap@CListView@@1UAFX_MSGMAP@@B)
1>CJ60StaticLib.lib(CJListView.obj) : error LNK2001: 无法解析的外部符号 "public: __thiscall CString::~CString(void)" (??1CString@@QAE@XZ)
1>CJ60StaticLib.lib(CJListCtrl.obj) : error LNK2001: 无法解析的外部符号 "public: __thiscall CString::~CString(void)" (??1CString@@QAE@XZ)
1>CJ60StaticLib.lib(CJListView.obj) : error LNK2019: 无法解析的外部符号 "public: void __thiscall CString::Empty(void)" (?Empty@CString@@QAEXXZ),该符号在函数 "public: __thiscall CCJListView::CCJListView(void)" (??0CCJListView@@QAE@XZ) 中被引用
1>CJ60StaticLib.lib(CJListCtrl.obj) : error LNK2001: 无法解析的外部符号 "public: void __thiscall CString::Empty(void)" (?Empty@CString@@QAEXXZ)
从错误上看,gh0st链接的是CJ60StaticLib.lib库,但是前面我们编译的CJ60StaticLib产生的库却是CJ60StaticLibd.lib,是CJ60StaticLib的Debug版本的库,这里链接的却是Release版的库。不信可以看下CJ60StaticLib的生成目录:
E:\Programming\VS2010\Gh0st3.6\gh0st\CJ60Lib\Lib
看些日期也就知道,我们前面编译的文件名后面都多了d。从新打开CJ60StaticLib项目。
E:\Programming\VS2010\Gh0st3.6\gh0st\CJ60Lib\CJ60Lib\CJ60Lib.sln
可以直接在界面上的修改成Release,或在项目属性里点配置成Release。如下图:
或者:
修改后如果直接这样编译,会出现类似下面的错误:
1>ShellPidl.cpp(220): error C2664: “MultiByteToWideChar”: 不能将参数 5 从“USHORT *”转换为“LPWSTR”
1> 与指向的类型无关;转换要求 reinterpret_cast、C 样式转换或函数样式转换
一看就知道是默认字符集问题,前面只在Debug模式下修改了默认不是WChar_t类型,而切换到Release模式也要记得修改。重新修改,编译CJ60StaticLib和CJ60Lib。再来看下生成目录。
E:\Programming\VS2010\Gh0st3.6\gh0st\CJ60Lib\Lib
3.2 gh0st链接错误
现在再来编译一次gh0st,链接错误是不是没有出现在CJ60StaticLib上了
1>C:\Program Files\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppBuild.targets(990,5): warning MSB8012: TargetPath(E:\Programming\VS2010\Gh0st3.6\gh0st\.\Release\gh0st.exe) does not match the Linker’s OutputFile property value (E:\Programming\VS2010\Gh0st3.6\Bin\gh0st.exe). This may cause your project to build incorrectly. To correct this, please make sure that $(OutDir), $(TargetName) and $(TargetExt) property values match the value specified in %(Link.OutputFile).
1>nafxcw.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z) 已经在 LIBCMT.lib(new.obj) 中定义
1>nafxcw.lib(afxmem.obj) : error LNK2005: "void __cdecl operator delete(void *)" (??3@YAXPAX@Z) 已经在LIBCMT.lib(delete.obj) 中定义
1>nafxcw.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new[](unsigned int)" (??_U@YAPAXI@Z)已经在 LIBCMT.lib(new2.obj) 中定义
1>nafxcw.lib(afxmem.obj) : error LNK2005: "void __cdecl operator delete[](void *)" (??_V@YAXPAX@Z) 已经在 LIBCMT.lib(delete2.obj) 中定义
1>../Bin/gh0st.exe : fatal error LNK1169: 找到一个或多个多重定义的符号
看错误提示,都是nafxcw.lib已经在LIBCMT.lib里定义,其实这就是VS链接库顺序的问题了,需要修正这些链接库的顺序。
打开gh0st项目的属性页面,在连接选项卡里选择Input。在忽略默认链接库(Ignore Specific Default Libraries)里可以看到原来的gh0st已经忽略了msvcrt.lib,这个对我们没有任何影响,去掉这个忽略。直接修改为:nafxcw.lib;LIBCMT.lib。然后在依赖关系(Additional Dependencies)里指定这两个库的链接顺序,在最前面添加:nafxcw.lib;LIBCMT.lib。这两个一定要在最前面。并且顺便不能乱。至于怎么看顺序,其实很简单,他不是说nafxcw.lib已经在LIBCMT.lib里定义了吗,那就是说在连接nafxcw.lib之前已经连接了LIBCMT.lib。修改如图:
四.结束
最后的运行效果如下:
如果编译之后生成的服务端,直接放到没有装VS2010的扩展库的系统下是不能运行的,只需要把提示缺少的文件从VS2010的安装目录拷贝到系统的system32下就能运行并上线了。
也可以把gh0st里的三个项目都改成Release版,这样就可以直接在其他系统中运行了。这里我就不讲解了,后续如需修改就看各自的了。
4.1 补充
在VM中的Server2003上测试时,发现这次的修改已经是Release版了,可以直接运行,不需要VS2010的扩展库支持了。以前编译的时候改动了很多地方,编译的是Debug版的,而且有警告弹窗。这次为了写本文档,尽量的保持了和原版本的一致。竟然没有以前的错误,也算是比以前的完美点了吧。