"WindowsError: исключение: нарушение прав доступа..." - вопрос ctypes

Вот прототип для функции C, которая находится в DLL:

extern "C" void__stdcall__declspec(dllexport) ReturnPulse(double*,double*,double*,double*,double*);

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

Вот тема: Как обернуть эту функцию C с несколькими аргументами в ctypes?

Поэтому я использовал полезную информацию в ветке выше, но теперь я получаю эту ошибку: WindowsError: исключение: нарушение прав доступа 0x00001001

Я не уверен, как поступить. Я на Windows XP - если я войду в учетную запись администратора, это решит проблему? Или это проблема с неизменяемостью объектов памяти Python?

Спасибо всем!

Отредактировано с соответствующим Python:

FROGPCGPMonitorDLL = windll.LoadLibrary('C:\Program Files\MesaPhotonics\VideoFROG 7.0\PCGPMonitor.dll')

#Function argument:double* pulse
sizePULSE = 2 ##Manual is super unclear here
pulse = c_double * sizePULSE
ptrpulse = pulse()

#Function argument:double* tdl
sizeTRACE = FROGPCGPMonitorDLL.GetSize()
if sizeTRACE == 0 :
    sizeTRACE = 1 #Manually set size to 1 for testing purposes
    print "Size of FROG trace is zero. Probably not right."
tdl = c_double*sizeTRACE
ptrtdl = tdl()


#Function argument:double* tdP
sizeTRACE = FROGPCGPMonitorDLL.GetSize()
if sizeTRACE==0:
    sizeTRACE=1
    print "Size of FROG trace is zero. Probably not right."
tdP = c_double*sizeTRACE
ptrtdP = tdP()


#Function Argument:double* fdl
sizeTRACE = FROGPCGPMonitorDLL.GetSize()
if sizeTRACE==0:
    sizeTRACE=1
    print "Size of FROG trace is zero. Probably not right."
fdl = c_double*sizeTRACE
ptrfdl = fdl()

#Function Argument: double* fdP
sizeTRACE = FROGPCGPMonitorDLL.GetSize()
if sizeTRACE==0:
    sizeTRACE=1
    print "Size of FROG trace is zero. Probably not right."
fdP = c_double*sizeTRACE
ptrfdP = fdP()

FROGPCGPMonitorDLL.ReturnPulse(ptrpulse, ptrtdl, ptrtdP,ptrfdl,ptrfdP)

Отредактировано, чтобы добавить соответствующий код! Я просто пишу простой скрипт, чтобы каждая из функций устройства работала первой. Я знаю, что переменную sizeTRACE можно использовать повторно, но сейчас это просто тестовый код, и устройство не подключено, поэтому GetSize() возвращает ноль. Умножение на ноль убило бы мое жужжание, поэтому сейчас я делаю его равным 1. Если это не ясно, я прошу прощения и постараюсь отредактировать этот пост.

Второе редактирование: было предложено подключить устройство и посмотреть, помогло ли это. Я только что подключил лягушку, но у меня все та же ошибка. Очень странно, и я довольно невежественен. В любом случае, спасибо еще раз всем!

2 ответа

Полученная ошибка не связана с правами администратора. Проблема в том, что вы используете C и непреднамеренно выполняете недопустимые операции (такие операции, которые, если их не проверять, могут привести к сбою в вашей системе).

Полученная ошибка указывает на то, что ваша программа пытается выполнить запись на адрес памяти 1001, но не должна выполнять запись на этот адрес памяти.

Это может произойти по ряду причин.

Одной из возможных причин является то, что значение double*, которое вы передаете ReturnPulse, не такое большое, как ожидает ReturnPulse. Возможно, вам, по крайней мере, нужно заставить GetSize работать должным образом... вы можете обойти его, просто выделив очень большой массив вместо вызова GetSize. т.е.

ptrfdP = (c_double*100000)()

Это выделит 100000 двойников, что может быть более подходящим для захвата цифрового импульса.

Другая проблема заключается в том, что преобразование типов может происходить не так, как ожидалось.

Возможно, вам повезет больше, если ctypes знает, что ReturnPulse использует пять двойных указателей. т.е.

# sometime before calling ReturnPulse
FROGPCGPMonitorDLL.ReturnPulse.argtypes = [POINTER(c_double), POINTER(c_double), POINTER(c_double), POINTER(c_double), POINTER(c_double)]

Если ни один из этих методов не работает, отправьте документацию по использованию на ReturnPulse, которая должна помочь нам распознать предполагаемое использование.

Или, что еще лучше, отправьте пример кода, который должен работать в C, и я переведу его в эквивалентную реализацию в ctypes.

Редактирование: добавление примера реализации ReturnPulse и использования ctypes.

Я реализовал что-то вроде того, что я ожидаю, что ReturnPulse будет делать в C DLL:

void ReturnPulse(double *a, double*b,double*c,double*d,double*e)
{
    // write some values to the memory pointed-to by a-e
    // a-e should have enough memory allocated for the loop
    for(int i = 0; i < 20; i++)
    {
        a[i] = 1.0*i;
        b[i] = 3.0*i;
        c[i] = 5.0*i;
        d[i] = 7.0*i;
        e[i] = 13.0*i;
    }
}

Я компилирую это в DLL (которую я называю examlib), а затем вызываю ее, используя ctypes со следующим кодом:

LP_c_double = ctypes.POINTER(ctypes.c_double)
examlib.ReturnPulse.argtypes = [LP_c_double, LP_c_double, LP_c_double, LP_c_double, LP_c_double, ]

a = (ctypes.c_double*20)()
b = (ctypes.c_double*20)()
c = (ctypes.c_double*20)()
d = (ctypes.c_double*20)()
e = (ctypes.c_double*20)()

examlib.ReturnPulse(a,b,c,d,e)

print 'values are'
for array in (a,b,c,d,e):
    print '\t'.join(map(str, array[:5]))

В результате получается

values are
0.0     1.0     2.0     3.0     4.0
0.0     3.0     6.0     9.0     12.0
0.0     5.0     10.0    15.0    20.0
0.0     7.0     14.0    21.0    28.0
0.0     13.0    26.0    39.0    52.0

Действительно, даже без установки ReturnPulse.argtypes код выполняется без ошибок.

ptrpulse и friends - идентификаторы python, указывающие на различные объекты ctypes (я думаю, они все c_double*2). Они либо должны быть обернуты объектом указателя ctypes, либо переданы в функцию C с помощью ctypes.byref.

Другие вопросы по тегам