5

Python から DLL を呼び出そうとしています。DLL はストレート C で書かれており、それほど複雑なことは何もありません。これは、ctypes がまさにそのために作成されたものです。ただし、DLL 関数呼び出しから返された構造体内で正しい値を取得するのに問題があります。渡された構造体の最初の値は正しく返されますが、他の値は返されません。

このコードは、メモリ内のバッファーから複数のメッセージを読み取ります。ReadFirst() / ReadNext() コーディング パラダイムを使用します。状態を追跡するために渡される「現在のメッセージ」構造体があります。

これは、現在の ReadFirst() / ReadNext() 状態を保持する C 構造体です...

typedef struct
    {
    unsigned int            uMsgNum;
    uint32_t                ulCurrOffset;
    uint32_t                ulDataLen;
    Su1553F1_ChanSpec     * psuChanSpec;
    Su1553F1_Header       * psu1553Hdr;
    SuCmdWordU            * psuCmdWord1;
    SuCmdWordU            * psuCmdWord2;
    uint16_t              * puStatWord1;
    uint16_t              * puStatWord2;
    uint16_t                uWordCnt;
    uint16_t              * pauData;
    } Su1553F1_CurrMsg;

これは、ctypes で記述された ctypes 構造体の対応物です...

class CurrMsg_1553F1(ctypes.Structure):
    ''' Data structure for the current 1553 message info structure '''
    _pack_   = 1
    _fields_ = [("MsgNum",      ctypes.c_uint32),
                ("CurrOffset",  ctypes.c_uint32),
                ("DataLen",     ctypes.c_uint32),
                ("pChanSpec",   ctypes.POINTER(ChanSpec_1553F1)),
                ("p1553Hdr",    ctypes.c_void_p),
                ("pCmdWord1",   ctypes.POINTER(CmdWord)),
                ("pCmdWord2",   ctypes.POINTER(CmdWord)),
                ("pStatWord1",  ctypes.c_void_p),
                ("pStatWord2",  ctypes.c_void_p),
                ("WordCnt",     ctypes.c_uint16),
                ("pData",       ctypes.c_void_p)]

以下で詳細を説明しますが、問題の核心は、ReadFirst() / ReadNext() の呼び出しが MsgNum の値を正しく返しますが、他の値はガベージであることです。ここにサンプル出力があります...

MsgNum 0  CurrOffset 40912728  DataLen 40912732  Messages = 3664897
MsgNum 1  CurrOffset 40912728  DataLen 40912748  Messages = 60417
MsgNum 2  CurrOffset 40912728  DataLen 40912748  Messages = 60417
etc.

MsgNum は正しく、ReadFirst() / ReadNext() は正しい回数反復します。ただし、CurrOffset と DataLen の値はガベージです。(Messages の値は、他のメモリへのポインターから逆参照されます。私はまだその権利を持っているとは思いませんが、この他の問題が修正されるまで、その値を保存する必要があります。CurrOffset と DataLen が間違っている場合、pChanSpec へのポインターはもおそらく間違っています。)

関数のインターフェイスは次のとおりです...

EnI106Status enI106_Decode_First1553F1
    (SuI106Ch10Header * psuHeader,
     void             * pvBuff,
     Su1553F1_CurrMsg * psuMsg);

EnI106Status enI106_Decode_Next1553F1
    (Su1553F1_CurrMsg * psuMsg);

これらの DLL 関数は、(印刷ステートメントのデバッグと共に) によって呼び出されます...

def __init__(self, PacketIO):
    self.CurrMsg  = CurrMsg_1553F1()

def Decode_First1553F1(self):
    Status = self.PacketIO._IrigDataDll.enI106_Decode_First1553F1(ctypes.byref(self.PacketIO.Header), ctypes.byref(self.PacketIO.Buffer),  ctypes.byref(self.CurrMsg))
    print "MsgNum %d  CurrOffset %d  DataLen %d  Messages = %d" % \
        (Decode1553.CurrMsg.MsgNum, Decode1553.CurrMsg.CurrOffset, Decode1553.CurrMsg.DataLen, Decode1553.CurrMsg.pChanSpec.contents.MsgCnt)
    return Status

def Decode_Next1553F1(self):
    Status = self.PacketIO._IrigDataDll.enI106_Decode_Next1553F1(ctypes.byref(self.CurrMsg))
    print "MsgNum %d  CurrOffset %d  DataLen %d  Messages = %d" % \
        (Decode1553.CurrMsg.MsgNum, Decode1553.CurrMsg.CurrOffset, Decode1553.CurrMsg.DataLen, Decode1553.CurrMsg.pChanSpec.contents.MsgCnt)
    return Status

C DLL は Visual Studio 2005 でコンパイルされます。私はこの DLL をさまざまな C および C++ .NET プログラムで問題なく使用しました。

ctypes と structs を使用して他のコードで値を返しましたが、問題なく動作しているようです。構造体の最初の値は問題ありませんが、後続の値はかなりずれているため、これはデータ アライメントの問題のように「感じられます」。ctypes 構造体でpack =1 を設定し、コンパイルされた DLL コードでバイト アラインメントを設定しました。各構造体の sizeof 出力を行い、それらが予想されるサイズであることを確認しました。

私はしばらくの間、この壁に頭をぶつけていて、アイデアがありません。次に何を試すかについて何か考えはありますか?

4

1 に答える 1

2

C構造体の最初の要素はunsignedintですが、Python構造体はc_uint32です。あなたはそれらがあなたのアーキテクチャで同じサイズであると確信していますか?

それでも問題が解決しない場合は、次のようにして問題の原因を追跡します。

_pack_まず、 Python宣言と#pragma pack、Cソースからのその他の配置操作を削除します。既知の場所、ネイティブアライメントから開始します。

それで...

構造体を反復処理し、各メンバーのオフセットを。で出力するCプログラムを作成しoffsetof(struct, field)ます。また、このプログラムはFirst()を呼び出し、Next()を数回呼び出して、構造体をそのままバイナリでファイルに書き込む必要があります。

次に、structモジュールを使用してPythonスクリプトを記述し、Cプログラムから書き出した構造体を繰り返し処理し、フィールドサイズと配置の知識を身に付けて、struct.unpack(...)を呼び出して形式を見つけます。構造体を適切に定義する文字列。

その知識があれば、ctypes.Structureを適切にコーディングできるはずです。

于 2012-11-16T13:45:43.637 に答える