I am using pybind11 to let python call an existing C module (library). The connection is through, however, in the C library, ::GetModuleFileName (Visual Studio) is called to to determine the physical path of the loaded module as it is run in C . But when I call the library from python (Jupyter Notebook) through pybind11, the physical path of python.exe is returned. How can I configure or change to make sure the physical path of the C library is obtained?
The C code is like this: Lib.h
#pragma once
void run();
Lib.cpp
#include <fstream>
#include <stdexcept>
#include <windows.h>
#include "libloaderapi.h"
#include "Lib.h"
void run()
{
char buf[1024];
::GetModuleFileName(0, buf, sizeof(buf));
std::ofstream of;
of.open("logging.txt");
if (!of.is_open()) {
throw std::runtime_error("Cannot open logging.txt");
}
of << "The loaded module is " << buf << std::endl;
}
The pybind11 interface code: Direct.cpp
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
#include <pybind11/stl.h>
#include "Lib.h"
namespace py = pybind11;
// wrap c function
void wrapper() {
run();
}
PYBIND11_MODULE(run_app, m) {
// optional module docstring
m.doc() = "pybind11 plugin";
m.def("run", &wrapper, "Run C Application");
}
The pybind11 setup file: setup.py
#from distutils.core import setup, Extension
#from distutils import sysconfig
from setuptools import setup, Extension
import pybind11
# The following is for GCC compiler only.
#cpp_args = ['-std=c 11', '-stdlib=libc ', '-mmacosx-version-min=10.7']
cpp_args = []
sfc_module = Extension(
'run_app',
sources=['Direct.cpp',
'Lib.cpp'],
include_dirs=[pybind11.get_include(), '.'],
language='c ',
extra_compile_args=cpp_args,
)
setup(
name='run_app',
version='1.0',
description='Python package with RunApp C extension (PyBind11)',
ext_modules=[sfc_module],
)
To build:
python setup.py build
The python code calling this library: py_run_app.py
import os
import sys
sys.path.append(os.path.realpath('build\lib.win-amd64-3.7'))
from run_app import run
run()
After the run:
python py_run_app.py
In the logging.txt The loaded module is C:....\python.exe
What I want to see is the physical location of the module.
CodePudding user response:
"Module" in Windows parlance is a DLL or an executable file loaded to be a part of a process. Each module has a module handle; by convention, the special handle NULL
signifies the executable file used to create the process.
GetModuleFileName
requires module handle as the first argument. You pass 0
, you get back the name of the module with the special handle NULL
, i.e. the executable. This is fully expected.
In order to get the file name of a DLL, you need to find out what its handle is. You can find the handle of the current module:
HMODULE handle;
static char local;
bool ok = GetModuleHandleEx (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
(LPCSTR)&local,
&handle);
local
can be any function or static/extern variable in the current module. ref.