Странная ошибка нарушения доступа при попытке установить обратный вызов с помощью ctypes - PullRequest
0 голосов
/ 06 августа 2020

Я пытаюсь создать простой движок, написанный на C ++ и обернутый в python с типами. Я хочу установить функцию рисования окна с помощью ctypes CFUNCTYPE. К сожалению, по каким-то причинам не работает. Понятия не имею, где может быть ошибка, поэтому публикую все. Я получаю сообщение об ошибке

exception: access violation reading 0x000001D15D9D0B51
  File "C:\Pancake2d\Pancake2d-python\pancake2d\window.py", line 28, in run
    pancake2d.API.lib.runWindow(self.obj)
  File "C:\Pancake2d\Pancake2d-python\test.py", line 13, in <module>
    wnd.run()

, но адрес, к которому пытается получить доступ код, каждый раз отличается, поэтому я предполагаю, что эта функция просто не установлена, и я пытаюсь вызвать неопределенное значение.

pancake2d. cpp

#include<new>
#define GLEW_BUILD
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "pancake2d.h"

#include "classes/window.h"

const char * version()
{
    const char* result = "Pancake2d - version 0.0.1";
    return result;
}

bool init() {
    if (!glfwInit()) {
        return false;
    }
    //glewInit();
    return true;
}

window* createWindow(int width, int height, const char* title) {
    return new window(width, height, title);
}

void deleteWindow(void* ptr) {
    delete ptr;
}

void closeWindow(window* wnd) {
    wnd->close();
}

void runWindow(window* wnd) {
    wnd->run();
}

bool setDrawingFunction(window* wnd, void(*ptr)()) {
    try {
        wnd->setDrawFunction(ptr);
    }
    catch(...) {
        return false;
    }
    return true;
}

void setUpdateFunction(window* wnd, void(*ptr)()) {
    wnd->setUpdateFunction(ptr);
}

pancake2d.h

#pragma once
#include <new>

#include "classes/window.h"
#include "graphics.h"

#ifdef PANCAKE2D_EXPORTS
#define exp __declspec(dllexport)
#else
#define imp __declspec(dllimport)
#endif
#ifdef  __cplusplus
extern "C" {
#endif


    exp const char* version();

    exp bool init();

    exp window* createWindow(int, int, const char *);

    exp void deleteWindow(void*);

    exp void closeWindow(window*);

    exp void runWindow(window*);


    exp bool setDrawingFunction(window*, void(*ptr)());
    exp void setUpdateFunction(window*, void(*ptr)());

#ifdef __cplusplus
}
#endif

window.h

#pragma once
#include <GL/glew.h>
#include <GLFW/glfw3.h>
class window
{
public:
    GLFWwindow* wnd;

    window(int width, int height, const char* title);
    void close();

    void (*update)();
    void (*draw)();

    void run();

    void setDrawFunction(void (*fnptr)());
    void setUpdateFunction(void (*fnptr)());
};

окно. cpp

#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include "window.h"

void default_draw() {
    glClear(GL_COLOR_BUFFER_BIT);
}

void default_update() {
}

window::window(int width, int height, const char* title)
{
    glfwWindowHint(GLFW_SAMPLES, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_COMPAT_PROFILE, GL_TRUE);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    wnd = glfwCreateWindow(width, height, title, NULL, NULL);

    if (wnd == NULL) { glfwTerminate(); return; }

    glfwMakeContextCurrent(wnd);

    if (glewInit() != GLEW_OK) {
        glfwTerminate();
        return;
    }

    //void (*draw)(window*) {default_draw};
    draw = default_draw;
    update = default_update;
}

void window::close() {
    glfwDestroyWindow(wnd);
}

void window::setDrawFunction(void(*fnptr)()) {
    draw = fnptr;
}

void window::setUpdateFunction(void(*fnptr)()) {
    update = fnptr;
}

void window::run() {
    while (glfwWindowShouldClose(wnd) == 0)
    {
        glClear(GL_COLOR_BUFFER_BIT);

        //update(this);
        draw();

        glfwSwapBuffers(wnd);
        glfwPollEvents();
    }

    close();
}

pancake2d / window.py

from ctypes import *

import pancake2d.API

function_empty = CFUNCTYPE(None)

def init():
    pancake2d.API.lib.createWindow.argtypes = [c_int, c_int, c_char_p]
    pancake2d.API.lib.createWindow.restype = c_void_p

    pancake2d.API.lib.deleteWindow.argtypes = [c_void_p]

    pancake2d.API.lib.closeWindow.argtypes = [c_void_p]

    pancake2d.API.lib.runWindow.argtypes = [c_void_p]

    pancake2d.API.lib.setDrawingFunction.argtypes = [c_void_p, function_empty]
    pancake2d.API.lib.setDrawingFunction.restype = c_bool

class Window:
    def __init__(self, width: int = 500, height: int = 500, caption: str = "Pancake2d Project"):
        self.obj = pancake2d.API.lib.createWindow(width, height, c_char_p(bytes(caption, encoding="UTF-8")))

    def close(self):
        pancake2d.API.lib.closeWindow(self.obj)

    def run(self):
        pancake2d.API.lib.runWindow(self.obj)

    def set_draw(self, fun):
        return pancake2d.API.lib.setDrawingFunction(self.obj, function_empty(fun))

pancake2d / init .py

from ctypes import *
import os

import pancake2d.API
import pancake2d.useless
import pancake2d.window
import pancake2d.graphics

mypath = os.path.dirname(os.path.realpath(__file__))

def init():
    print(os.path.join(mypath, "Pancake2d.dll"))
    os.environ['PATH'] = os.path.join(mypath, "lib") + os.pathsep + os.environ['PATH']
    pancake2d.API.lib = cdll.LoadLibrary(os.path.join(mypath, "Pancake2d.dll"))
    pancake2d.API.lib.init()
    pancake2d.useless.init()
    pancake2d.window.init()
    pancake2d.graphics.init()

test.py

import pancake2d, time, random
from ctypes import *
pancake2d.init()

def draw():
    pancake2d.graphics.setBackgroundColor(random.randint(1, 255), random.randint(1, 255), random.randint(1, 255))

wnd = pancake2d.window.Window(700, 200, "Test")
if not wnd.set_draw(draw):
    print ("Something went wrong") # This does not happen
pancake2d.graphics.setBackgroundColor(128, 128, 128)

wnd.run()

Буду очень благодарен за любой ответ.

...