Python3.8调用C DLL时unsigned char数组及访问违规问题
Let's break down your issue and work through the solutions step by step. You've already fixed the initial type mismatch error, but the access violation indicates there's still a problem with how your parameters are being passed to the DLL function.
Problem Recap
You're trying to call this __stdcall C DLL function from Python 3.8:
extern void* __stdcall Reentrante_CreerNouvelleIdentification ( int NumeroDuCapteur , DetectorType_t DetectorType, float DetectorVolume, float Resolution, float ResolutionCzt, float C1 , float C2 , float C3 , float C4 , unsigned char CustomLibrary[NB_ISOTOPES_CANDIDAT], float FeThick, float CdThick, float PbThick, int maxIsoPourReportingIdent, const char* BkgPath );
After fixing the initial TypeError by changing the 10th argument type to ct.POINTER(ct.c_ubyte) and using WinDLL (correct for __stdcall), you're now hitting:
OSError: exception: access violation writing 0x00000014
This error means the DLL is trying to write to an invalid memory address (0x14 is a very low, non-pointer address), which usually points to a parameter mismatch or invalid data being passed.
Root Cause Analysis
Here are the most likely issues:
- Incorrect size for
CustomLibraryarray: You hardcodedn=70, but ifNB_ISOTOPES_CANDIDAT(the array size defined in the DLL's header) is a different value, the DLL will read/write beyond the bounds of your array, corrupting memory. - Temporary array object being garbage collected: If you pass the array directly as
CustomLib(*tab)without storing it in a variable, there's a small chance Python's GC could reclaim it mid-call, leaving the DLL with a dangling pointer. - Invalid
BkgPathparameter: If the DLL doesn't accept aNULL(Python'sNone) for this argument, trying to access it could lead to memory errors (though the error address here suggests this might not be the primary issue). - Mismatched enum base type: If
DetectorType_tis defined as anunsigned intinstead of a signedintin the C code, passing a signed int could cause unexpected behavior.
Step-by-Step Solutions
1. Verify NB_ISOTOPES_CANDIDAT Value
First, check the DLL's header file or documentation to get the exact value of NB_ISOTOPES_CANDIDAT. Update your array size to match this value:
# Replace with the actual NB_ISOTOPES_CANDIDAT value from DLL header NB_ISOTOPES_CANDIDAT = 70 CustomLib = ct.c_ubyte * NB_ISOTOPES_CANDIDAT tab = [0] * NB_ISOTOPES_CANDIDAT custom_lib = CustomLib(*tab) # Store in a variable to avoid GC
2. Ensure Array Persists During Call
Store the array in a named variable before passing it to the function. This guarantees the object exists for the duration of the DLL call:
# Instead of passing CustomLib(*tab) directly: custom_lib = CustomLib(*tab) s2 = SIA.Reentrante_CreerNouvelleIdentification(..., custom_lib, ...)
3. Fix the BkgPath Parameter
If the DLL requires a valid path (even an empty one), pass a bytes string instead of None. If the path is optional, confirm with the DLL docs—if it does accept NULL, you can keep None, but if not:
# Example: Pass a valid background path as bytes bkg_path = b"C:/Data/SOFTS/SMI_5510/background_file.txt" # Or empty string if allowed bkg_path = b""
4. Validate Enum Type
If DetectorType_t is an unsigned enum, update the argtypes to use ct.c_uint instead of ct.c_int:
SIA.Reentrante_CreerNouvelleIdentification.argtypes = [ ct.c_int, ct.c_uint, ct.c_float, ct.c_float, ct.c_float, ct.c_float, ct.c_float, ct.c_float, ct.c_float, ct.POINTER(ct.c_ubyte), ct.c_float, ct.c_float, ct.c_float, ct.c_int, ct.c_char_p ]
Full Modified Code Example
Putting it all together (adjust NB_ISOTOPES_CANDIDAT and bkg_path to match your actual values):
import os import ctypes as ct WorkFolder = "C:/Data/SOFTS/SMI_5510" os.add_dll_directory(WorkFolder) # Use WinDLL for __stdcall functions SIA = ct.WinDLL(os.path.join(WorkFolder, "SIA_Identification.dll")) # Replace with the actual NB_ISOTOPES_CANDIDAT value from DLL header NB_ISOTOPES_CANDIDAT = 70 CustomLib = ct.c_ubyte * NB_ISOTOPES_CANDIDAT tab = [0] * NB_ISOTOPES_CANDIDAT custom_lib = CustomLib(*tab) # Persist array during call # Set up function types correctly SIA.Reentrante_CreerNouvelleIdentification.restype = ct.c_void_p SIA.Reentrante_CreerNouvelleIdentification.argtypes = [ ct.c_int, ct.c_int, ct.c_float, ct.c_float, ct.c_float, ct.c_float, ct.c_float, ct.c_float, ct.c_float, ct.POINTER(ct.c_ubyte), ct.c_float, ct.c_float, ct.c_float, ct.c_int, ct.c_char_p ] # Use a valid BkgPath if required bkg_path = None # Replace with b"your/path/here" if needed # Call the function s2 = SIA.Reentrante_CreerNouvelleIdentification( 666, 0, 250.0, 7.5, 12.5, 1.0, 0.0, 0.0, 0.0, custom_lib, 0.0, 0.0, 0.0, 5, bkg_path )
Additional Checks
- Double-check all float values are passed as floats (add
.0to integers like250to avoid accidental int-to-float conversion issues). - Ensure the DLL is loaded correctly—use
os.path.jointo avoid path issues. - If the error persists, use a tool like Dependency Walker to check for missing dependencies in the DLL.
内容的提问来源于stack exchange,提问作者El Pacificador

