【问题标题】:How to initialize CRT when doing LoadLibrary("*.exe")执行 LoadLibrary("*.exe") 时如何初始化 CRT
【发布时间】:2013-09-11 04:08:29
【问题描述】:

我正在尝试将 numpy 数组传递给 C 并在那里进行一些计算。

我将可执行文件构建为 exe 并导出 Python 然后调用的一些函数。该程序有效,但我无法使用printf() 等标准功能。如果我将二进制文件构建为 dll,它就可以工作。通过在互联网上搜索,我了解到 dll 加载和 exe 加载(maincrtstartup?)对运行时库进行初始化。是否可以复制他们所做的以便我可以使用printf()

Python 代码

import  numpy as np
import ctypes
from numpy.ctypeslib import ndpointer

lib = ctypes.cdll.LoadLibrary('pycon.exe')

fun = lib.fun
fun.restype = None
fun.argtypes = [ndpointer(ctypes.c_double),
                ctypes.c_size_t]



data = np.ones((5,5)).astype('double')
def wfun(d):
    fun(d, d.size)
print data
wfun(data)
print data

C 代码

#include <stdio.h>
#include <math.h>
extern "C" __declspec(dllexport) 
void fun(double *datav, size_t size) {
    //printf("crash");
    double * data = (double *) datav;
    int i;
    for (i = 0; i < size; ++i)
        data[i] = 1.7159*tanh(0.66666667*data[i]);
}


extern "C" __declspec(dllexport) 
void init() {
    //what to put here?
}


int main(int argc, char* argv[])
{
    return 0;
}

【问题讨论】:

    标签: c++ python c winapi msvcrt


    【解决方案1】:

    我意识到将 exe 视为 dll 比我想象的要复杂得多。我最终得到了以下解决方法。

    蟒蛇

    import  numpy as np
    import ctypes as C
    
    lib = C.cdll.LoadLibrary('pycon.exe')
    lib.init( C.windll.kernel32.GetProcAddress( C.windll.msvcrt._handle,'printf'))
    
    d = np.ones((5)).astype('double')
    lib.fun(d.ctypes.data_as(C.POINTER(C.c_double)), C.c_size_t(5))    
    

    c

    #include <stdio.h>
    #include <math.h>
    
    int (*pyprintf)(const char *,...) =0;
    
    extern "C" __declspec(dllexport) 
    void fun(double *datav, size_t size) {
            double * data = (double *) datav;
            int i;
            for (i = 0; i < size; ++i)
            {
                data[i] = 1.7159*tanh(0.66666667*data[i]);
                pyprintf("workign! %f\n",data[i]);
            }
    }
    
    extern "C" __declspec(dllexport) 
    void init(int (*_printfPtr)(const char *,...)) {
            pyprintf=_printfPtr;
    }
    
    int main(int argc, char* argv[])
    {
        printf("exe");
        return 0;
    }
    

    编辑

    好奇心使我变得更好,兔子洞越来越大,现在它比上面稍微少了一点,似乎可以同时作为 exe 和 dll 运行,并且加载代码更多。

    要求

    • 'exe' 必须只依赖于 kernel32
    • pefile 包
    • 链接器标志/FIXED:NO -entry:_DllMainCRTStartup@12

    蟒蛇

    import  numpy as np
    import ctypes as C
    import pefile
    
    def unprotect( address): 
        crap = C.byref(C.create_string_buffer("\x00"*4))
        res = C.windll.kernel32.VirtualProtect(address, 0x1000, 0x40, crap)
    
    lib = C.cdll.LoadLibrary('pycon.exe')
    k32 = C.windll.kernel32
    pe =  pefile.PE('pycon.exe')
    
    
    for entry in pe.DIRECTORY_ENTRY_IMPORT:
      #print entry.dll
      #assuming that the exe only has dependency on kernel32
      for imp in entry.imports:
        diff = imp.address-0x400000
        memptr = k32.GetProcAddress(k32._handle,imp.name)
        unprotect(lib._handle+diff)
        fptr = (C.c_uint).from_address(lib._handle+diff)
        fptr.value = memptr
    
    d = np.ones((5)).astype('double')
    lib.init()
    lib.fun(d.ctypes.data_as(C.POINTER(C.c_double)), C.c_size_t(5))   
    print d
    

    c

    #include <stdio.h>
    #include <math.h>
    #include <windows.h>
    
    extern "C" BOOL WINAPI  _CRT_INIT(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);
    
    extern "C" __declspec(dllexport) 
        void fun(double *datav, size_t size) {
            double * data = (double *) datav;
            int i;
            for (i = 0; i < size; ++i)
            {
                data[i] = 1.7159*tanh(0.66666667*data[i]);
                printf("workign! %f\n",data[i]);
            }
            fflush(stdout);
    }
    
    extern "C" __declspec(dllexport) 
        void init() {
            _CRT_INIT(NULL,DLL_PROCESS_ATTACH,NULL);
    }
    
    
    BOOL APIENTRY DllMain( HMODULE hModule,
                          DWORD  ul_reason_for_call,
                          LPVOID lpReserved
                          )
    {
        _CRT_INIT(NULL,DLL_PROCESS_ATTACH,NULL);
        printf("main exe");
        return TRUE;
    }
    

    【讨论】:

    • .exe 文件视为.dll 似乎有点荒谬。 DLL 的存在是有充分理由的,它们与 EXE 不同是有充分理由的。并且“解决”问题所涉及的工作量在很大程度上说明了为什么试图让一个人做另一个人的工作是……好吧,如果不是徒劳的练习,挫折感的练习,而且有点毫无意义边。 AFAICS,您不能独立运行 EXE;它必须从 Python 运行。这与 EXE 的用途完全相反。
    猜你喜欢
    • 1970-01-01
    • 2014-06-13
    • 2015-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-11
    • 2017-10-21
    • 1970-01-01
    相关资源
    最近更新 更多