在进程和 DLL 之间共享全局/静态变量

2023-11-23

我只想在进程和进程调用的 dll 之间共享静态/全局变量。 exe和dll位于同一内存地址空间。我不希望该变量在其他进程之间共享。


问题的阐述:

假设有一个静态/全局变量x in a.cpp。两个都是exefoo.exe和动态链接库bar.dll have a.cpp,所以变量x是在两个图像中。

Now, foo.exe动态加载(或静态)bar.dll。那么问题就在于变量是否x是否由exe和dll共享。

在 Windows 中,这两个人never分享x:exe 和 dll 将有一个单独的副本x。然而,在Linux中,exe和dll确实共享该变量x.

不幸的是,我想要 Linux 的行为。我首先考虑使用pragma data_seg在 Windows 上。但是,即使我正确设置了共享数据段,foo.exe and bar.dll从不分享x。回想起那个bar.dll被加载到地址空间foo.exe。但是,如果我运行另一个实例foo.exe, then x是共享的。但是,我不想x供不同进程共享。所以,使用data_seg失败了。

我可以通过在 exe 和 dll 之间创建唯一的名称来使用内存映射文件,我现在正在尝试。


两个问题:

  1. 为什么 Linux 和 Windows 的行为不同?谁能对此进行更多解释?
  2. 在 Windows 上解决此问题最简单的方法是什么?

获取主程序和 dll 共享相同的 Linux 行为x,您可以从 dll 或主程序中导出该变量。另一个模块必须导入该变量。

您可以通过使用 DEF 文件(请参阅微软的文档),或者通过用变量标记用途__declspec(dllexport)它的定义位置,以及__declspec(dllimport)在任何其他模块中使用它(请参阅微软的文档)。这与窗口中的模块之间共享任何函数、对象或变量的方式相同。

如果您希望程序在运行时加载库,但主程序可能必须在加载库之前使用该变量,则程序应导出该变量,而 dll 应导入它。这里有点先有鸡还是先有蛋的问题,因为dll依赖于主程序,而主程序又依赖于dll。看http://www.lurklurk.org/linkers/linkers.html#wincircular

我写了一个示例,说明如何使用 Microsoft 的编译器和 mingw(Windows 中的 gcc)来完成此操作,包括程序和库可以相互链接的所有不同方式(静态地,在程序启动时加载 dll、加载 dll运行时期间)

main.h

#ifndef MAIN_H
#define MAIN_H

// something that includes this
// would #include "linkage_importing.h"
// or #include "linkage_exporting.h"
// as appropriate

#ifndef EXPLICIT_MAIN
LINKAGE int x;
#endif // EXPLICIT_MAIN

#endif // MAIN_H

main.c

#ifdef EXPLICIT_DLL
#include "dyn_link.h"
#endif // EXPLICIT_DLL
#include <stdio.h>
#include "linkage_exporting.h"
#include "main.h"
#include "linkage_importing.h"
#include "dll.h"

FNCALL_DLL get_call_dll(void);

int main(int argc, char* argv[])
{
   FNCALL_DLL fncall_dll;
   fncall_dll = get_call_dll();
   if (fncall_dll)
   {
      x = 42;
      printf("Address of x as seen from main() in main.c: %p\n", &x);
      printf("x is set to %i in main()\n", x);
      fncall_dll();
      // could also be called as (*fncall_dll)();
      // if you want to be explicit that fncall_dll is a function pointer
      printf("Value of x as seen from main() after call to call_dll(): %i\n", x);
   }
   return 0;
}

FNCALL_DLL get_call_dll(void)
{
#ifdef EXPLICIT_DLL
   return get_ptr("dll.dll", "call_dll");
#else
   return call_dll;
#endif // EXPLICIT_DLL
}

dll.h

#ifndef DLL_H
#define DLL_H

// something that includes this
// would #include "linkage_importing.h"
// or #include "linkage_exporting.h"
// as appropriate

// declaration of type to hold a
// pointer to the function
typedef void(*FNCALL_DLL)(void);

#ifndef EXPLICIT_DLL
LINKAGE void call_dll(void);
#endif // EXPLICIT_DLL

#endif // DLL_H

dll.c

#ifdef EXPLICIT_MAIN
#include "dyn_link.h"
#endif // EXPLICIT_MAIN
#include <stdio.h>
#include "linkage_importing.h"
#include "main.h"
#include "linkage_exporting.h"
#include "dll.h"

int* get_x_ptr(void);

LINKAGE void call_dll(void)
{
   int* x_ptr;
   x_ptr = get_x_ptr();
   if (x_ptr)
   {
      printf("Address of x as seen from call_dll() in dll.c: %p\n", x_ptr);
      printf("Value of x as seen in call_dll: %i()\n", *x_ptr);
      *x_ptr = 31415;
      printf("x is set to %i in call_dll()\n", *x_ptr);
   }
}

int* get_x_ptr(void)
{
#ifdef EXPLICIT_MAIN
   return get_ptr("main.exe", "x");   // see note in dyn_link.c about using the main program as a library
#else
   return &x;
#endif //EXPLICIT_MAIN
}

dyn_link.h

#ifndef DYN_LINK_H
#define DYN_LINK_H

// even though this function is used by both, we link it
// into both main.exe and dll.dll as necessary.
// It's not shared in a dll, because it helps us load dlls :)
void* get_ptr(const char* library, const char* object);

#endif // DYN_LINK_H

dyn_link.c

#include "dyn_link.h"
#include <windows.h>
#include <stdio.h>

void* get_ptr(const char* library, const char* object)
{
   HINSTANCE hdll;
   FARPROC ptr;
   hdll = 0;
   ptr = 0;

   hdll = LoadLibrary(library);
   // in a better dynamic linking library, there would be a
   // function that would call FreeLibrary(hdll) to cleanup
   //
   // in the case where you want to load an object in the main
   // program, you can use
   // hdll = GetModuleHandle(NULL);
   // because there's no need to call LoadLibrary on the
   // executable if you can get its handle by some other means.

   if (hdll)
   {
      printf("Loaded library %s\n", library);
      ptr = GetProcAddress(hdll, object);
      if (ptr)
      {
         printf("Found %s in %s\n", object, library);
      } else {
         printf("Could not find %s in %s\n", object, library);
      }
   } else {
      printf("Could not load library %s\n", library);
   }
   return ptr;
}

连接导入.h

// sets up some macros to handle when to use "__declspec(dllexport)",
// "__declspec(dllimport)", "extern", or nothing.

// when using the LINKAGE macro (or including a header that does):
//    use "#include <linkage_importing.h>" to make the LINKAGE macro
//    do the right thing for importing (when using functions,
//    variables, etc...)
//
//    use "#include <linkage_exporting.h>" to make the LINKAGE macro
//    do the right thing for exporting (when declaring functions,
//    variables, etc).
//
//    You can include either file at any time to change the meaning of
//    LINKAGE.

// if you declare NO_DLL these macros do not use __declspec(...), only
// "extern" as appropriate

#ifdef LINKAGE
#undef LINKAGE
#endif
#ifdef NO_DLL
   #define LINKAGE extern
#else
   #define LINKAGE extern __declspec(dllimport)
#endif

联动_导出.h

// See linkage_importing.h to learn how this is used
#ifdef LINKAGE
#undef LINKAGE
#endif
#ifdef NO_DLL
   #define LINKAGE
#else
   #define LINKAGE __declspec(dllexport)
#endif

构建 mingw 显式 Both.sh

#! /bin/bash
echo Building configuration where both main
echo and dll link explicitly to each other
rm -rf mingw_explicit_both
mkdir -p mingw_explicit_both/obj
cd mingw_explicit_both/obj

# compile the source code (dll created with position independent code)
gcc -c -fPIC -DEXPLICIT_MAIN ../../dll.c
gcc -c -DEXPLICIT_DLL ../../main.c
gcc -c ../../dyn_link.c

#create the dll from its object code the normal way
gcc -shared -odll.dll dll.o dyn_link.o -Wl,--out-implib,libdll.a

# create the executable
gcc -o main.exe main.o dyn_link.o

mv dll.dll ..
mv main.exe ..
cd ..

构建 mingw 显式 dll.sh

#! /bin/bash
echo Building configuration where main explicitly
echo links to dll, but dll implicitly links to main
rm -rf mingw_explicit_dll
mkdir -p mingw_explicit_dll/obj
cd mingw_explicit_dll/obj

# compile the source code (dll created with position independent code)
gcc -c -fPIC ../../dll.c
gcc -c -DEXPLICIT_DLL ../../main.c
gcc -c ../../dyn_link.c

# normally when linking a dll, you just use gcc
# to create the dll and its linking library (--out-implib...)
# But, this dll needs to import from main, and main's linking library doesn't exist yet
# so we create the linking library for main.o
# make sure that linking library knows to look for symbols in main.exe (the default would be a.out)
gcc -omain.exe -shared main.o -Wl,--out-implib,main.a  #note this reports failure, but it's only a failure to create main.exe, not a failure to create main.a

#create the dll from its object code the normal way (dll needs to know about main's exports)
gcc -shared -odll.dll dll.o dyn_link.o main.a -Wl,--out-implib,libdll.a

# create the executable
gcc -o main.exe main.o dyn_link.o

mv dll.dll ..
mv main.exe ..
cd ..

构建 mingw 显式 main.sh

#! /bin/bash
echo Building configuration where dll explicitly
echo links to main, but main implicitly links to dll
rm -rf mingw_explicit_main
mkdir -p mingw_explicit_main/obj
cd mingw_explicit_main/obj

# compile the source code (dll created with position independent code)
gcc -c -fPIC -DEXPLICIT_MAIN ../../dll.c
gcc -c ../../main.c
gcc -c ../../dyn_link.c

# since the dll will link dynamically and explicitly with main, there is no need
# to create a linking library for main, and the dll can be built the regular way
gcc -shared -odll.dll dll.o dyn_link.o -Wl,--out-implib,libdll.a

# create the executable (main still links with dll implicitly)
gcc -o main.exe main.o -L. -ldll

mv dll.dll ..
mv main.exe ..
cd ..

构建 mingw 隐式.sh

#! /bin/bash
echo Building configuration where main and
echo dll implicitly link to each other
rm -rf mingw_implicit
mkdir -p mingw_implicit/obj
cd mingw_implicit/obj

# compile the source code (dll created with position independent code)
gcc -c -fPIC ../../dll.c
gcc -c ../../main.c

# normally when linking a dll, you just use gcc
# to create the dll and its linking library (--out-implib...)
# But, this dll needs to import from main, and main's linking library doesn't exist yet
# so we create the linking library for main.o
# make sure that linking library knows to look for symbols in main.exe (the default would be a.out)
gcc -omain.exe -shared main.o -Wl,--out-implib,main.a  #note this reports failure, but it's only a failure to create main.exe, not a failure to create main.a

# create the dll from its object code the normal way (dll needs to know about main's exports)
gcc -shared -odll.dll dll.o main.a -Wl,--out-implib,libdll.a

# create the executable (exe needs to know about dll's exports)
gcc -o main.exe main.o -L. -ldll

mv dll.dll ..
mv main.exe ..
cd ..

构建 mingw static.sh

#! /bin/bash
echo Building configuration where main and dll
echo statically link to each other
rm -rf mingw_static
mkdir -p mingw_static/obj
cd mingw_static/obj

# compile the source code
gcc -c -DNO_DLL ../../dll.c
gcc -c -DNO_DLL ../../main.c

# create the static library
ar -rcs dll.a dll.o

# link the executable
gcc -o main.exe main.o dll.a

mv main.exe ../
cd ..

构建 msvc 显式 Both.bat

@echo off
echo Building configuration where both main
echo and dll link explicitly to each other
rd /s /q win_explicit_both
md win_explicit_both\obj
cd win_explicit_both\obj

rem compile the source code
cl /nologo /c /DEXPLICIT_MAIN ..\..\dll.c
cl /nologo /c /DEXPLICIT_DLL ..\..\main.c
cl /nologo /c ..\..\dyn_link.c

rem create the dll from its object code the normal way
link /nologo /dll dll.obj dyn_link.obj

rem create the executable
link /nologo main.obj dyn_link.obj

move dll.dll ..\
move main.exe ..\
cd ..

构建 msvc 显式 dll.bat

@echo off
echo Building configuration where main explicitly
echo links to dll, but dll implicitly links to main
rd /s /q win_explicit_dll
md win_explicit_dll\obj
cd win_explicit_dll\obj

rem compile the source code
cl /nologo /c ..\..\dll.c
cl /nologo /c /DEXPLICIT_DLL ..\..\main.c
cl /nologo /c ..\..\dyn_link.c

rem normally when linking a dll, you just use the link command
rem that creates the dll and its linking library.
rem But, this dll needs to import from main, and main's linking library doesn't exist yet
rem so we create the linking library for main.obj
rem make sure that linking library knows to look for symbols in main.exe (the default would be main.dll)
lib /nologo /def /name:main.exe main.obj

rem create the dll from its object code the normal way (dll needs to know about main's exports)
link /nologo /dll dll.obj main.lib

rem create the executable
link /nologo main.obj dyn_link.obj

move dll.dll ..\
move main.exe ..\
cd ..

构建 msvc 显式 main.bat

@echo off
echo Building configuration where dll explicitly
echo links to main, but main implicitly links to dll
rd /s /q win_explicit_main
md win_explicit_main\obj
cd win_explicit_main\obj

rem compile the source code
cl /nologo /c /DEXPLICIT_MAIN ..\..\dll.c
cl /nologo /c ..\..\main.c
cl /nologo /c ..\..\dyn_link.c

rem since the dll will link dynamically and explicitly with main, there is no need
rem to create a linking library for main, and the dll can be built the regular way
link /nologo /dll dll.obj dyn_link.obj

rem create the executable (main still links with dll implicitly)
link /nologo main.obj dll.lib

move dll.dll ..\
move main.exe ..\
cd ..

构建msvc隐式.bat

@echo off
echo Building configuration where main and
echo dll implicitly link to each other
rd /s /q win_implicit
md win_implicit\obj
cd win_implicit\obj

rem compile the source code
cl /nologo /c ..\..\dll.c
cl /nologo /c ..\..\main.c

rem normally when linking a dll, you just use the link command
rem that creates the dll and its linking library.
rem But, this dll needs to import from main, and main's linking library doesn't exist yet
rem so we create the linking library for main.obj
rem make sure that linking library knows to look for symbols in main.exe (the default would be main.dll)
lib /nologo /def /name:main.exe main.obj

rem create the dll from its object code the normal way (dll needs to know about main's exports)
link /nologo /dll dll.obj main.lib

rem create the executable (exe needs to know about dll's exports)
link /nologo main.obj dll.lib

move dll.dll ..\
move main.exe ..\
cd ..

构建 msvc static.bat

@echo off
echo Building configuration where main and dll
echo statically link to each other
rd /s /q win_static
md win_static\obj
cd win_static\obj

rem compile the source code
cl /nologo /DNO_DLL /c ..\..\dll.c
cl /nologo /DNO_DLL /c ..\..\main.c

rem create the static library
lib /nologo dll.obj

rem link the executable
link /nologo main.obj dll.lib

move main.exe ..\
cd ..
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在进程和 DLL 之间共享全局/静态变量 的相关文章

随机推荐

  • 如何检查函数模板是否已专门化?

    有没有办法在编译时确定某个函数模板是否是专门的 例如 假设有以下函数模板 template
  • 'selenium.common.exceptions.WebDriverException:消息:无法访问 u'chrome

    我正在使用 webdriver 来配置路由器 但是当我运行脚本时 from selenium import webdriver self driver webdriver Chrome 它打开chrome并且没有响应 然后引发异常 铬无法到
  • Scala 中的平等关系

    我刚刚偶然发现了托尼 莫里斯的一张关于 Java 的博客文章该语言的一个基本问题是 为集合定义定制的相等关系 我认为这是一个big deal并想知道是否有一些 scala 解决方案 这个经典问题体现在对交易的思考中 假设我以 150p 的价
  • WPF 命令和事件有什么区别?

    WPF 和 WPF 有什么区别Command and Event 一般来说 您可以对事件执行与命令几乎相同的操作 只是处理用户交互的模式不同 Commands在 WPF 中 允许您将命令处理程序的实现移至业务层 命令结合了启用状态和执行 因
  • Ember:嵌套组件事件冒泡

    我创建了一组嵌套组件 代码在这里 http emberjs jsbin com hasehija 2 edit HTML level 1 level 2 level 3
  • String.Format 一个整数以在丹麦文化中使用带有小数值的千位分隔符

    我有一根绳子totalPRice它的值是这样的1147 5我想要两件事 1 对值进行四舍五入 以便后面始终有两位数 2 在此字符串中实现千位分隔符 这样最终的输出将是这样的1 147 50我尝试过这样的事情 String Format 0
  • 使用 htaccess 将子目录重定向到子域

    我对使用 htaccess 比较陌生 除了我在网上阅读的内容之外 从未做过任何编码 我正在使用 Bluehost 并且我想将我的博客子目录重定向到子域 示例 我想将 www example com blog 重定向到 blog exampl
  • 使用 HttpContextScoped() 时 StructureMap 不会处理数据上下文

    我的目标是拥有一个数据上下文 MainDbContext ASP NET MVC 中的每个 HTTP 请求 并在请求结束时处理数据上下文 我正在使用以下 StructureMap 配置 public static class Contain
  • 连接文件与路径以获得C中的完整路径

    使用 C 我尝试将目录中的文件名与其路径连接起来 以便我可以为每个文件调用 stat 但是当我尝试在循环内使用 strcat 时 它将前一个文件名与下一个文件名连接起来 它在循环期间修改argv 1 但我已经很长时间没有使用C了 所以我很困
  • 为 PHP 数组的每一项添加前缀

    我有一个 PHP 数字数组 我想在其前面加上减号 我认为通过使用爆炸和内爆这是可能的 但我对 php 的了解不可能真正做到这一点 任何帮助 将不胜感激 本质上我想从这里开始 array 1 2 3 4 5 to this array 1 2
  • 在 MySQL 中存储时间间隔值的最佳方法?

    愚蠢的简单问题 但我一直无法找到一个优雅的解决方案 我想将时间间隔存储在 MySQL 列中 例如 1 40 1小时40分钟 0 30 30 分钟 然后能够运行查询并对它们求和 现在我将它们存储为 INT 值 1 40 但我必须手动进行加法
  • Numpy 数组每个项的均值和标准差

    我有一个二维数组 相同形状 的列表 并且希望在与输入形状相同的结果数组中获取所有项的平均值和偏差 我很难从文档中了解这是否可能 我对 axis 和 keepdims 参数的所有尝试都会产生不同形状的结果 例如 我希望有 mean x x 等
  • 使用 Hibernate (JPA) 查询 Postgresql 找不到表

    我正在使用 JPA 与 Hibernate 和 Postgresql 开发一个应用程序 使用 Netbeans 向导 我从现有数据库创建了实体类 其中一个类的摘录如下 Entity Table name ADM TYPES XmlRootE
  • 更改数据库中所有存储过程的 ANSI_NULLS 设置

    我们在 ANSI NULLS 设置和计算列方面存在一些问题 并且我们有大量的存储过程 SET ANSI NULLS OFF 我们想把它们全部改成 SET ANSI NULLS ON 有没有一种简单的方法可以做到这一点 或者我必须将所有 SP
  • 如何使用 dart_pdf 将资产图像和图标转换为 flutter 中的 PdfImage

    使用的库 dart pdf搜索后我发现同样的问题GITHUB但无法解决问题 我尝试了这个 但出现了模糊的图像 请帮忙 ByteData data await rootBundle load assets test jpg var codec
  • 改变iphone sdk中图像的颜色

    我有一个图像 我想通过编程更改该图像的颜色 我想改变这张图片的颜色 UPDATE 使用这个方法 UIImage imageNamed NSString name withColor UIColor color load the image
  • Rails flash[:notice] 总是 nil

    我不明白为什么我的 Rails 视图无法识别 flash notice 或 flash error 关于渲染的部分视图 我不断收到以下错误 具体错误是 ActionView Template Error 当你没有预料到时 你得到了一个 ni
  • 在每个文档中构建具有附加字段的反应式出版物

    我想制作一个包含几个附加字段的出版物 但我不想使用Collection aggregate当集合发生变化时 我的出版物更新就会丢失 所以我不能只使用self added在其中 我打算使用Cursor observeChanges为了实现这一
  • GMP pow 中的溢出处理

    我只是 GMP 库的间接用户 主要通过swi prolog and yap 但我对解决这个问题非常感兴趣 当使用大得离谱的值执行求幂时 主机系统或 GMP 不再能够适当地处理溢出 我已经与上述系统的开发人员交谈过 但他们没有看到解决此问题的
  • 在进程和 DLL 之间共享全局/静态变量

    我只想在进程和进程调用的 dll 之间共享静态 全局变量 exe和dll位于同一内存地址空间 我不希望该变量在其他进程之间共享 问题的阐述 假设有一个静态 全局变量x in a cpp 两个都是exefoo exe和动态链接库bar dll