【问题标题】:How can i force the Windows.h to be linked statically instead of dynamically in visual studio? [closed]如何强制 Windows.h 在 Visual Studio 中静态链接而不是动态链接? [关闭]
【发布时间】:2019-12-24 00:10:54
【问题描述】:

如何强制我的链接器静态链接到 Windows.h,以便 Windows 库的所有函数都进入我的可执行文件?

我希望 API 调用(如 VirtualAllocEx、OpenProcess)和其他 API 调用(如写入另一个进程的内存等)以及 CreateRemoteThread(基本上所有通信 API 调用和内存分配调用)都在我的可执行文件中,所以我没有为它使用 Windows.h,所以基本上我的 IAT 不会包含这些功能,实现这一点的最佳方法是什么?

【问题讨论】:

  • 感谢您的链接,但我怎样才能强制它静态链接 windows.h? @πάντα ῥεῖ
  • "如何强制它静态链接 windows.h?" - 这是没有意义的。 "Windows.h" 是一个header 文件,不是 一个库。它可能会从一个库(或许多不同库)中公开内容,但它本身并不是一个库。
  • @MeryTed 你的谷歌有什么问题吗?我添加了另一个链接。
  • @dedecos 即使在这种情况下,我们也可以解释 crt 库依赖于编译器,因为它包含运行编译器库函数(fopen、get、printf 等)所需的基本函数。一些编译器,如 MSVC,允许选择如何使用特定的行开关静态或动态地链接它们,因此他必须参考编译器文档。更难解释的是,由于技术原因,2的使用有所不同。 IE。选择静态链接不允许在同一进程空间中运行的 DLL 之间共享文件指针。
  • @πάνταῥεῖ再次您不能静态链接系统库因为每个 DLL 都使用共享部分来跟踪进程间仲裁并允许内核与用户代码交互而不会相互干扰过程。简而言之,实际情况要复杂得多。

标签: c++ c visual-studio linker static-linking


【解决方案1】:

你不能。

这些东西是操作系统的一部分。

操作系统有权做你自己的代码不能做的事情。

此外,您的操作系统的实现对于该版本的操作系统是正确的。

这是一件好事。您不想静态链接操作系统的 API 实现。

头文件Windows.h 仅提供允许您调用它们的声明。

【讨论】:

    【解决方案2】:

    我在 MS Windows 操作系统下的 cmets 中说过,动态库有一些与静态库代码无关的特性。让我们尝试以非常简单的方式解释:

    首先,一个DLL独立于当前可执行文件加载,直接从OS模块加载函数加载,作为一个单独的对象,代码内存映射到当前进程内存,但保留映射到不同的进程。

    在加载过程中,加载器会创建不同的内存区域,这些区域可以是单个进程独有的,也可以是进程间共享的,也可以是 DLL 内部函数私有的。

    共享区域允许创建互斥体、信号量和内核仲裁多任务环境和资源共享所需的任何数据。

    反之,静态库仅在当前进程中加载​​,代码段与用户程序代码段放在一起,数据段以同样的方式添加到当前可执行数据空间中。

    由于这些原因以及更多原因,您不能将任何系统库函数静态链接到您的可执行文件


    使用 CRT 库进行静态和动态链接的简单实验。

    在您打开文件的位置创建一个主程序:

    #include <stdio.h>
    extern void DllReadRoutine(FILE *);
    int main(int argc, char *argv[])
    {
        FILE *fp = fopen("Myfile.txt", "r");
        //Diagnostic omitted to keep it simple
        DllReadRoutine(fp);    //Pass the file pointer to the external DLL function
        fclose(fp);
        return 0;
    }
    

    现在创建 DLL(我们省略 DLL 条目):

    #include <stdio.h>
    void DllReadRoutine(FILE *fp);
    int main(int argc, char *argv[])
    {
        int c;
        while ((c=fgetc(pFile)) != EOF)
        {
            putchar(c);
        }
    }
    

    然后编译两个链接CRT第一次静态(在MSVC上使用/MT)和动态第二次(在MSVC上使用/MD)。

    在第一种情况下,DLL 函数将失败,因为到 CRT 的静态链接创建的本地打开文件表与主可执行文件的本地表不兼容。结果是崩溃。

    在第二种情况下,作为打开文件表的内部 CRT 数据是在可执行文件和 DLL 都可以访问的共享区域中创建的。在这种情况下,代码将顺利运行。

    【讨论】:

    • 但是当我使用 /MT 而不是 /MD 的运行时库选项时,它确实有点用,因为我的二进制文件的大小从 9kb 变为 77,并且文本部分变得更大,所以我假设这些是来自添加到我的 .text 部分的 Windows 的 API 调用,对吗?但我不知道为什么 IAT 表仍然包含我使用的函数(来自 user32.dll 的 MessageBox)并且它只包含这个,认为它会从 IAT 中删除,因为我静态链接它
    • @MeryTed 否。使用 /MT 或 /MD 您指示链接器分别静态或动态链接仅编译器 CRT(编译器运行时库)。不是系统库。检查我上面提供的示例代码。
    【解决方案3】:

    我想你可能误解了静态链接的过程。 Windows.h 头文件包含各种活动类型的声明,例如函数调用。请注意,这些是声明而不是函数本身的二进制实现。查看ShellExecuteA 文档。滚动到文档末尾,您将看到如下所示的需求部分:

    要求

    Minimum supported client Windows XP [desktop apps only] 
    Minimum supported server Windows 2000 Server [desktop apps only] 
    Target Platform Windows Header shellapi.h 
    Library Shell32.lib 
    DLL Shell32.dll (version 3.51 or later)
    

    Windows.h 包括 shellapi.h(目标平台 Windows 标头)。 Shellapi.h 包含 ShellExecuteA 的声明(我们在文档中查找的函数)。本节还告诉您包含函数的二进制实现的库,在本例中为 Shell32.lib。如果您知道函数声明及其二进制实现的位置,则可以链接它。链接器只是将(函数)名称与链接时可用的(实现)名称相匹配。在 Windows 上,您应该能够使用 lib 文件进行静态链接,或者使用 dll 文件进行动态链接。如果静态链接,则将 lib 文件中的二进制实现包含到可执行文件中。如果 MS 修复了 a 但在您使用的函数中,除非您重新编译,否则您不会得到该修复。如果您动态链接(链接到 dll),您的可执行文件将更小,并且更包含未来的 MS 更改。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-15
      • 1970-01-01
      • 2019-07-05
      • 1970-01-01
      相关资源
      最近更新 更多