Встраивание Python в DLL: место чтения нарушения прав доступа, когда объект списка Py_DECREF - PullRequest
1 голос
/ 05 октября 2019

Я пытаюсь встроить Python в XLL, чтобы позволить функциям Python вызываться в Excel. XLL - это библиотека DLL, которая также включает как минимум 2 функции, которые сообщают Excel, как регистрировать или отменять регистрацию экспортируемых функций из библиотеки DLL, так что это можно рассматривать точно как традиционную библиотеку DLL. Проблема, с которой я сталкиваюсь, заключается в том, что при уменьшении счетчика ссылок объекта списка Python происходит сбой программы со следующей ошибкой:

Исключение, выданное в 0x1E14E37D (python37.dll) в EXCEL.EXE: 0xC0000005: Доступнарушение чтения местоположения 0x00000064.

У меня нет этой проблемы при уменьшении строк счетчиков ссылок, чисел с плавающей запятой, bool и т. д. Эта проблема возникает только у объекта списка и кортежа.

Ниже я сделал простой пример с двумя функциями, доступными для Excel, testFloat и testList. Обе сделаны очень простыми, чтобы попытаться отладить проблему, поэтому функции не принимают аргументов и оба возвращают xltypenil в Excel, который заполнит ячейку 0. Каждая функция создает свой собственный объект Python (float или список) и затем уменьшает значениеколичество ссылок.

#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <Windows.h>
#include <XLCALL.H>
#include <FRAMEWRK.H>

LPCWCHAR uFuncs[][3]{
    {L"testFloat", L"Q", L"testFloat"},
    {L"testList", L"Q", L"testList"},
};

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

int WINAPI xlAutoOpen(void) {
    if (!Py_IsInitialized()) {
        Py_InitializeEx(0);
    }

    // register functions with Excel
    XLOPER12 xDLL;
    Excel12f(xlGetName, &xDLL, 0);
    for (int i{ 0 }; i < sizeof(uFuncs) / sizeof(uFuncs[0]); i++) {
        Excel12f(xlfRegister, 0, 4,
            (LPXLOPER12)& xDLL,
            (LPXLOPER12)TempStr12(uFuncs[i][0]),
            (LPXLOPER12)TempStr12(uFuncs[i][1]),
            (LPXLOPER12)TempStr12(uFuncs[i][2])
        );
    }
    Excel12f(xlFree, &xDLL, 0);

    return 1;
}

int WINAPI xlAutoClose(void) {
    if (Py_IsInitialized()) {
        Py_FinalizeEx();
    }
    return 1;
}

LPXLOPER12 testFloat(void) {
    static XLOPER12 xRet;
    PyObject* obj{ PyFloat_FromDouble(2.5) };
    Py_DECREF(obj);
    xRet.xltype = xltypeNil;
    return &xRet;
}

LPXLOPER12 testList(void) {
    static XLOPER12 xRet;
    PyObject* obj{ Py_BuildValue("[dd]", 3.4, 4.5) };
    Py_DECREF(obj);  // <---- This is where the debugger says the error is
    xRet.xltype = xltypeNil;
    return &xRet;
}

В настоящее время я получаю следующую ошибку:

Исключение, выданное в 0x1E14E37D (python37.dll) в EXCEL.EXE: 0xC0000005: Место чтения нарушения доступа0x00000064.

Я ожидаю, что это запустится без ошибок и вернет 0 в ячейку Excel, вызывающую функцию.

...