Windows
0
VC2015编写不需要运行库的资磁(支持)XP的程序
金坷居士 2016-5-23 18:25:23
VC制作的软件,从VC2005之后的都需安装运行库才可以运行,从xp到win10一直都没改变,而且这货,上下版本还不能互相兼容orz这就是为啥在添加和删除程序里能看到各版本VC运行库的原因。
在某些情况下,比如绿色软件或者在pe下运行的软件,运行库可能带不全或者不好安装,于是制作一个不需要VC运行库的程序就是很有必要的了
首先创建一个VC2015的Win32 Project,选择默认选项创建一个窗体程序
打开菜单Project-> xxx Property(xxx是项目名)或者直接按Alt+F7,
选择Configuration为All Configuration, Platform为All Platform
将Basic Runtime Checks改为Default
将Security Check改为Disable Security Check(/GS-)
在stdafx.h的#progma once下面添加:
#ifdef _DEBUG
#pragma comment (linker, "/nodefaultlib:msvcrtd.lib")
#else
#pragma comment (linker, "/nodefaultlib:msvcrt.lib")
#endif

这时候编译一般会出现一堆堆的错误
首先解决LNK2001 unresolved external symbol wWinMainCRTStartup, wWinMainCRTStartup是VC的CRT定义的Win32程序入口点,MFC程序为WinMainCRTStartup,控制台和DLL为mainCRTStartup和_DllMainCRTStartup。
没有了运行库就没有了入口点orz没有入口点就创建一个咯,wWinMainCRTStartup不接收任何参数,我写的入口如下,可以放在stdafx.cpp里:
int __cdecl wWinMainCRTStartup() {
    STARTUPINFO info;
    info.cb = sizeof(STARTUPINFO);
    GetStartupInfo(&info);
  
    int ret = wWinMain(GetModuleHandle(NULL),
        0,
        GetCommandLine(),
        info.dwFlags & STARTF_USESHOWWINDOW ? info.wShowWindow : SW_SHOWDEFAULT);
    ExitProcess(ret);
    return ret;
}

之后应该就可以顺利编译工程了,这样制作出来的程序和静态链接的程序比起来,体积极小
本方法并不是完美的,有这些缺点:
C++的异常不能用了, new delete也不能用了,也就是说这时候C++基本完全废了
C和C++的标准库大部分也都不能用了,不过这个有解决方法,我自己想出来的,可能不是很完美,就是手动实现某些stdlib里的函数,给了些常用的实现,都是互联网上搜索的:
void* __cdecl malloc(ULONG_PTR uSize) {
    return (void *)HeapAlloc(GetProcessHeap(), 0, uSize);
}
  
void __cdecl free(LPVOID pMemBlock) {
    HeapFree(GetProcessHeap(), 0, (LPVOID)pMemBlock);
}


#pragma function(memcpy)

void* memcpy(void * dst, const void * src, size_t count)
{
    void * ret = dst;
  
#if defined (_M_IA64)
    {
        extern void RtlMoveMemory(void *, const void *, size_t count);
  
        RtlMoveMemory(dst, src, count);
    }
#else /* defined (_M_IA64) */
    /*
    * copy from lower addresses to higher addresses
    */
    while (count--) {
        *(char *)dst = *(char *)src;
        dst = (char *)dst + 1;
        src = (char *)src + 1;
    }
#endif /* defined (_M_IA64) */
  
    return(ret);
}
  
#pragma function(memset)
void* __cdecl memset(void* src, int c, size_t count) {
    char *tmpsrc = (char*)src;
    while (count--)
        *tmpsrc++ = (char)c;
    return src;
}

有的时候编译会看到俩错误,找不到__imp__invalid_parameter_noinfo和__imp__errno,并不晓得这俩是啥,于是空函数代替之:
extern "C" void __cdecl __imp__invalid_parameter_noinfo() {
  
}
  
extern "C" void __cdecl __imp__errno() {
  
}


还有个说不清的问题,就是调用COM组件的时候有点奇怪。。
还有,MFC不适用!也就是说,复杂的软件就不要用这种方法咯
参考
https://www.kechuang.org/t/80005
http://stackoverflow.com/questions/2938966/how-to-use-vc-intrinsic-functions-w-o-run-time-library

[修改于 3 年前 - 2016-06-17 19:11:11]

2016-6-17 16:57:49
1楼
0

感觉这样还不如用汇编。。。

便携性的话,静态编译就够用了。兼容性的话,去掉运行库提升有限,直接降编译器版本或者用MinGW效果更好。

[修改于 3 年前 - 2016-06-18 00:36:26]

2016-6-20 23:27:36
2楼
0

gcc+自备源码,到目标机运行的时候再编译(只是gcc还要安装不易携带) 或者。。。使用网页应用,但是不适合复杂计算等

2016-10-20 11:47:20
3楼
0
引用 drzzm32:
gcc+自备源码,到目标机运行的时候再编译(只是gcc还要安装不易携带)
或者。。。使用网页应用,但是不适合复杂计算等
直接codeblocks绿色版。。。
4楼
0
VC6.0一直用的很high的路过……

我用的都是比较底层的东西,没有花里胡哨的,所以用一个老的编译器,直接就不用考虑不同的客户会用什么版本的windows了
5楼
0
引用 amo:
VC6.0一直用的很high的路过……

我用的都是比较底层的东西,没有花里胡哨的,所以用一个老的编译器,直接就不用考虑不同的客户会用什么版本的windows了
个人用vc++2005比较多→_→其实主要是因为vc6在win7中用着不爽→_→不过现在顶多用到vs2010了吧,谁会用xp sp2之前的系统呢

[修改于 3 年前 - 2016-10-21 17:44:08]

2017-12-2 14:05:52
金坷居士(作者)
6楼
0
新的发现,如果按照上面的还是出错的话

1. Configuration Properties -> C/C++ -> Optimization -> Whole Program Optimization = false
2. Configuration Properties -> C/C++ -> Optimization -> Enable Intrinsic Functions = false
3. #include <Windows.h> 要写成
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
不然会找不到malloc

想参与大家的讨论?现在就 登录 或者 注册

万流景仰
专栏收藏夹发私信
学术分 11科创币 16.43总主题 171 帖总回复 1711 楼拥有证书:会员 学者 机友 笔友
注册于 2011-09-23 14:21最后登录 2019-04-25 01:17

个人简介

怪哉!灵异的三极管电流流向! 这素一个在仿真的RCC电路,示波器上绿色的是集电极电流红色的是发射极电流。窝萌都知道发射姬电流素集电极电流和基极电流之和,所以讲道理发射极电流一定比集电极略大。可仿真结果刷了三观,Q1集电极电流一部分流经基极,然后流经Q2的C->E。

Github  https://github.com/kccd/nkc.git

科创研究院 (c)2001-2019

蜀ICP备11004945号-2 川公网安备51010802000058号