1

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;
}
4

1 に答える 1

0

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;
}
于 2013-09-11T15:03:19.600 に答える