如何获取当前dll或exe模块所在路径?

        有时我们需要在当前运行的dll或exe模块中去动态加载当前模块同路径中的另一个库,或者启动当前模块同路径中的另一个exe程序,一般需要获取当前模块的路径,然后去构造同路径下目标模块的绝对路径,然后通过该绝对路径去加载或启动该目标进程。

       最近我们在一个SDK项目中遇到了类似的问题,客户的Java程序通过JNI调用我们的C++ 动态库umssdk.dll,然后在该dll动态库初始化的接口中自动启动同路径下的XxLauncher.exe程序。umssdk.dll库中启动XxLauncher.exe程序的代码如下:

// 启动XxLauncher.exe
void StartExe()
{
    TCHAR achLog[256] = { 0 };
    TCHAR szPath[MAX_PATH] = { 0 };
    TCHAR *p = szPath;

    // 获取当前模块的路径
    ::GetModuleFileName(NULL, szPath, MAX_PATH);

    // 用当前模块的路径去构造目标模块XxLauncher.exe的绝对路径,然后使用该绝对路径去启动该exe程序
    p += _tcslen(szPath);
    while (*p-- != _T('\\'));
    *(p + 2) = 0;
    _tcscat(szPath, _T("XxLauncher.exe"));

    SHELLEXECUTEINFO si;
    RtlZeroMemory(&si, sizeof(SHELLEXECUTEINFO));
    si.cbSize = sizeof(SHELLEXECUTEINFO);
    si.lpFile = szPath;
    si.nShow = SW_SHOWNORMAL;
    si.lpVerb = _T("open");

    BOOL bRet = ShellExecuteEx(&si);
    if (!bRet) 
    {
        int nErr = GetLastError();

        int nHInsVal = (int)si.hInstApp;
    }
}

代码中调用API函数GetModuleFileName获取当前dll模块的路径,然后用当前模块的路径去构造目标模块XxLauncher.exe的绝对路径,然后使用该绝对路径去启动该exe程序。

       Java主程序通过JNI加载的umssdk.dll路径如下所示,要启动的程序XxLauncher.exe也在umssdk.dll同一个路径中,如下所示:

但客户Java程序在启动umssdk.dll库时,弹错如下的报错提示框:

居然跑到D:\aa_tools\5.0_idx_64\eclipse\jre\bin\路径下去启动XxLauncher.exe程序,难道这是受当前的工作路径影响导致的?

       于是去查看启动XxLauncher.exe程序代码,代码中使用API函数GetModuleFileName去获取当前加载的umssdk.dll路径,隐约中想起来,当给GetModuleFileName函数第一个参数传递NULL时,GetModuleFileName获取的好像是启动当前进程的主程序路径,即Java主程序的路径。于是,到MSDN上查看GetModuleFileName函数的说明,如下:

当第一个参数传NULL时,GetModuleFileName获取的是确实是启动当前进程的主程序路径,就是Java主程序的路径。

        如果要获取当前umssdk.dll库的路径,应该传入umssdk.dll模块的实例句柄,那如何获取umssdk.dll实例句柄呢?dll库的实例句柄可以在dll库的入口函数DllMain中获取,如下所示:

HMODULE g_hDLLInstance = NULL;

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    g_hDLLInstance = hModule;

    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

即定义一个全局实例句柄变量g_hDLLInstance,在DllMain中将当前dll模块的句柄保存下来,然后在调用GetModuleFileName函数时使用该g_hDLLInstance变量接口,修改后的代码如下所示:

// 启动XxLauncher.exe
void StartExe()
{
    TCHAR achLog[256] = { 0 };
    TCHAR szPath[MAX_PATH] = { 0 };
    TCHAR *p = szPath;

    // 获取当前模块的路径
    ::GetModuleFileName(g_hDLLInstance, szPath, MAX_PATH);

    // 用当前模块的路径去构造目标模块XxLauncher.exe的绝对路径,然后使用该绝对路径去启动该exe程序
    p += _tcslen(szPath);
    while (*p-- != _T('\\'));
    *(p + 2) = 0;
    _tcscat(szPath, _T("XxLauncher.exe"));

    SHELLEXECUTEINFO si;
    RtlZeroMemory(&si, sizeof(SHELLEXECUTEINFO));
    si.cbSize = sizeof(SHELLEXECUTEINFO);
    si.lpFile = szPath;
    si.nShow = SW_SHOWNORMAL;
    si.lpVerb = _T("open");

    BOOL bRet = ShellExecuteEx(&si);
    if (!bRet) 
    {
        int nErr = GetLastError();

        int nHInsVal = (int)si.hInstApp;
    }
}

       如果是exe模块,如何获取当前exe模块的实例句柄呢?其实很简单,在WinMain函数中记录一下即可,如下所示:

int APIENTRY _tWinMain(HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPTSTR    lpCmdLine,
    int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);

    // 此处将当前应用程序的实例保存到g_hInstance,因为有的API调用时要使用该参数
    g_hInstance = hInstance;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/694054.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java自学阶段二:JavaWeb开发50(Spring和Springboot学习)

Spring、Springboot基础知识学习 目录 学习目标Spring基础概念IOC控制反转DI依赖注入事务管理AOP面向切面编程Spring案例说明(Postman使用、Restful开发规范、lombok、Restful、nginx了解) 一:学习目标: 1)了解Sprin…

海洋日特别活动—深海来客——可燃冰

深海中有一种神奇的物质,似冰又不是冰。 别看它其貌不扬,但本领不小,遇火即燃,能量巨大,可谓是能源家族的新宠。它就是被国务院正式批准列为我国第173个矿种的“可燃冰”! 可燃冰到底是个啥?它…

C++ | Leetcode C++题解之第133题克隆图

题目&#xff1a; 题解&#xff1a; class Solution { public:Node* cloneGraph(Node* node) {if (node nullptr) {return node;}unordered_map<Node*, Node*> visited;// 将题目给定的节点添加到队列queue<Node*> Q;Q.push(node);// 克隆第一个节点并存储到哈希…

Java Web学习笔记31——Maven介绍

Maven&#xff1a;Java项目的构建工具。 Maven&#xff1a; Maven是Apache旗下的一个开源项目&#xff0c;是一款用于管理和构建Java项目的工具。 Apache软件基金会&#xff0c;成立于1999年7月&#xff0c;是目前世界上最大的最受欢迎的开源软件基金会&#xff0c;也是一个专…

手把手带你做一个自己的网络调试助手(2) - TCP服务器完善

服务器指定客户端发送 自定义控件comboBox - 刷新客户端列表 目的&#xff1a; 自定义控件&#xff0c;当鼠标点击这个comboBox控件的时候去刷新客户端列表 mycombobox.h #ifndef MYCOMBOBOX_H #define MYCOMBOBOX_H#include <QComboBox> #include <QWidget>cl…

服务部署:.NET项目使用Docker构建镜像与部署

前提条件 安装Docker&#xff1a;确保你的Linux系统上已经安装了Docker。如果没有&#xff0c;请参考官方文档进行安装。 步骤一&#xff1a;准备项目文件 将你的.NET项目从Windows系统复制到Linux系统。你可以使用Git、SCP等工具来完成这个操作。如何是使用virtualbox虚拟电…

SpringCloud Gateway中Filters详细说明

前面 https://blog.csdn.net/J080624/article/details/139494909 我们研究了GateWay中各种路由断言的使用。SpringCloud GateWay 还提供了各种过滤器用来对请求和响应进行处理。 官网地址&#xff1a;SpringCloud Gateway Filter 【1】GatewayFilter Factories 路由过滤器允…

20240609如何查询淘宝的历史价格

20240609如何查询淘宝的历史价格 2024/6/9 18:39 百度&#xff1a;淘宝历史价格 淘宝历史价格查询网站 https://zhuanlan.zhihu.com/p/670972171 30秒学会淘宝商品历史价格查询&#xff01; https://item.taobao.com/item.htm?id693104421622&pidmm_29415502_2422500430_1…

排序-读取数据流并实时返回中位数

目录 一、问题描述 二、解题思路 1.顺序表排序法 2.使用大根堆、小根堆 三、代码实现 1.顺序表排序法实现 2.大根堆、小根堆法实现 四、刷题链接 一、问题描述 二、解题思路 1.顺序表排序法 &#xff08;1&#xff09;每次读取一个数就对列表排一次序&#xff0c;对排…

python-微分方程计算

首先导入数据 import numpy as np from scipy.integrate import odeint from scipy.optimize import minimize import matplotlib.pyplot as pltdata np.array([[30, 4],[47.2, 6.1],[70.2, 9.8],[77.4, 35.2],[36.3, 59.4],[20.6, 41.7],[18.1, 19],[21.4, 13],[22, 8.3],[2…

初识 peerDependencies

目录 初步认识 peerDependencies semver 介绍 # 摘要 # 简介 # 语义化版本控制规范&#xff08;SemVer&#xff09; # 合法语义化版本的巴科斯范式语法 # 为什么要使用语义化的版本控制&#xff1f; # FAQ 示例讲解&#xff1a;vue-router 插件 # 说明 声明 验证 初…

电子阅览室有何作用

随着互联网的快速发展&#xff0c;电子阅览室逐渐成为人们获取知识的新方式。它为读者提供了便捷、高效的阅读体验&#xff0c;具有诸多作用。首先&#xff0c;电子阅览室拥有丰富的电子书籍资源&#xff0c;涵盖了各个领域的知识。无论是文学作品还是学术论文&#xff0c;读者…

商城项目【尚品汇】08异步编排-01基础篇

文章目录 1.线程的创建方式1.1继承Thread类&#xff0c;重写run方法1.2实现Runnable接口&#xff0c;重写run方法。1.3实现Callable接口&#xff0c;重新call方法1.4以上三种总结1.5使用线程池创建线程1.5.1线程池创建线程的方式1.5.2线程池的七大参数含义1.5.3线程池的工作流程…

探索 Docker:容器化技术的未来

1. 引言 在传统的软件开发和部署过程中&#xff0c;经常会遇到诸如“开发环境和生产环境不一致”、“依赖环境冲突”、“部署困难”等问题。为了解决这些问题&#xff0c;容器化技术应运而生。Docker 作为最受欢迎的容器平台之一&#xff0c;已经在业界得到广泛应用。它不仅简化…

【C++】——Stack与Queue(含优先队列(详细解读)

前言 之前数据结构中是栈和队列&#xff0c;我们分别用的顺序表和链表去实现的&#xff0c;但是对于这里的栈和队列来说&#xff0c;他们是一种容器&#xff0c;更准确来说是一种容器适配器 ✨什么是容器适配器&#xff1f; 从他们的模板参数可以看出&#xff0c;第二个参数模…

摆脱Jenkins - 使用google cloudbuild 部署 java service 到 compute engine VM

在之前 介绍 cloud build 的文章中 初探 Google 云原生的CICD - CloudBuild 已经介绍过&#xff0c; 用cloud build 去部署1个 spring boot service 到 cloud run 是很简单的&#xff0c; 因为部署cloud run 无非就是用gcloud 去部署1个 GAR 上的docker image 到cloud run 容…

张大哥笔记:经济下行,这5大行业反而越来越好

现在人们由于生活压力大&#xff0c;于是就干脆降低自己的欲望&#xff0c;只要不是必需品就不买了&#xff0c;自然而然消费也就降低了&#xff0c;消费降级未必是不好的现象&#xff01; 人的生物本能是趋利避害&#xff0c;追求更好的生存和发展空间&#xff0c;回避对自己有…

C++使用thread_local实现每个线程下的单例

对于一个类&#xff0c;想要在每个线程种有且只有一个实例对象&#xff0c;且线程之间不共享该实例&#xff0c;可以按照单例模式的写法&#xff0c;同时使用C11提供的thread_local关键字实现。 在单例模式的基础上&#xff0c;使用thread_local关键字修饰单例的instance&…

Redis原理篇——哨兵机制

Redis原理篇——哨兵机制 1.Redis哨兵2.哨兵工作原理2.1.哨兵作用2.2.状态监控2.3.选举leader2.4.failover 1.Redis哨兵 主从结构中master节点的作用非常重要&#xff0c;一旦故障就会导致集群不可用。那么有什么办法能保证主从集群的高可用性呢&#xff1f; 2.哨兵工作原理 …

【Python】读取文件夹中所有excel文件拼接成一个excel表格 的方法

我们平常会遇到下载了一些Excel文件放在一个文件夹下&#xff0c;而这些Excel文件的格式都一样&#xff0c;这时候需要批量这些文件合并成一个excel 文件里。 在Python中&#xff0c;我们可以使用pandas库来读取文件夹中的所有Excel文件&#xff0c;并将它们拼接成一个Excel表…