2016-11-17 9 views
1

私は、分光データを記録し、第三者のアプリケーションによって制御されるデバイスを持っています。自動化の目的で、アプリケーションのCOMインターフェイスを使用してPythonでデータを取得したいと考えています。パイソンからAPIを使用してのための適切な文書が存在しないので、私は成功した最初のフレームを取得し、別のWebソースからの次のコードを、収集:win32comラッパーのイントロスペクション方法は?

comtypes.client.GetModule(('{1A762221-D8BA-11CF-AFC2-508201C10000}', 3, 11)) 
import comtypes.gen.WINX32Lib as WinSpecLib 
win32com.client.pythoncom.CoInitialize() 
doc = win32com.client.Dispatch("WinX32.DocFile") 

buffer = ctypes.c_float() 
frame = 1 
spectrum = doc.GetFrame(frame, buffer) 

をしかし、GetFrameへの呼び出しは、Visualにおけるその定義と矛盾しています製造業者によって提供される基本的な、:Visual Basicの配列に

Sub GetFrame(frame As Integer, buffer As Variant) 

GetFrameコピー文書からデータを。 bufferが空のバリアントである場合、GetFrameは、適切なサイズとデータ型の配列を作成し、データをコピーする前にバッファをポイントするように設定します。

これは、Python bufferに変わらなく、機能GetFrameは、実際のデータを返すないのに対し、機能GetFrameは、戻り値はありませんしながら、Visual Basicで変数bufferがデータで満たされていることを意味しています。

プログラムのランダムなクラッシュがMemoryErrorを投げているのを観察していないと、コードのこの時点でメモリリークが発生しているとは限りません。だから私の疑問は、への各呼び出しのために、win32comが何らかの形でAPIのラッピングを混乱させたために、バッファ用に割り当てられたメモリが解放されていないということです。

その理由は私の実際の質問につながります。どのようにしてラッパーをイントロスペクションして、それが何をしているのか理解できますか?これまでのところ、win32comによって生成されたコードがどのファイルにも格納されているというヒントは見つかりませんでしたが、正しい場所を見ていない可能性があります。

はIPythonで、私はまたdoc.GetFrame??を使用して情報を取得しようとしましたが、それはどのような実装を返しませんでした:

Signature: doc.GetFrame(frame=<PyOleMissing object at 0x06F20BC8>, FrameVariant=<PyOleMissing object at 0x06F20BC8>) 
Docstring: <no docstring> 
File:  c:\programming\python\src\<comobject winx32.docfile> 
Type:  method 

他に何私はAPIラッパーに関する詳細情報を入手しようとすることができますか?

答えて

1

私は最終的に私の問題の解決策を見つけることができました。最初の重要な実現は、Dispatchの代わりにEnsureDispatchを呼び出すと、win32comによって生成されたラッパーにアクセスできることが判明しました。対応するファイルは次のフォルダに位置していた私の場合は

>>> import win32com.client 
>>> doc = win32com.client.gencache.EnsureDispatch ("WinX32.DocFile") 
>>> print(doc.GetFrame.__module__) 
'win32com.gen_py.1A762221-D8BA-11CF-AFC2-508201C10000x0x3x12.IDocFile4' 

次のようにGetFrame

C:\WinPython\WinPython-32bit-3.5.2.2\python-3.5.2\Lib\site-packages\win32com\gen_py\1A762221-D8BA-11CF-AFC2-508201C10000x0x3x12 

実装が見えます。

def GetFrame(self, frame=defaultNamedNotOptArg, FrameVariant=defaultNamedNotOptArg): 
    'Get Frame Data' 
    return self._ApplyTypes_(10, 1, (24, 0), ((2, 1), (16396, 3)), 'GetFrame', None, frame, FrameVariant) 

したがって、魔法は_ApplyTypes_です。このメソッド自体はwin32com\client\__init__で定義されています。

def _ApplyTypes_(self, dispid, wFlags, retType, argTypes, user, resultCLSID, *args): 
    return self._get_good_object_(
     self._oleobj_.InvokeTypes(dispid, 0, wFlags, retType, argTypes, *args), 
     user, resultCLSID) 

すべてが基本的にInvokeTypesに渡されていることがわかります。Python-win32メーリングリストのthisメッセージによれば、InvokeTypesInvokeと非常によく似ていて、IDispatch::Invokeの再実装です。 Pythonに統合されたC++実装のソースコードはhereです。

私の元々の質問で私が気になるのは、このC++実装の説明もあります。InvokeのPythonバージョンはbyref引数を明示的に戻り値に変換します。したがって、少なくとも、私が最初に疑ったメモリリークはないはずです。

ここで、引数の型について何がわかりますか?必要な情報はタプル((2, 1), (16396, 3))に格納されます。 2つの引数があります.1つ目は入力専用の引数(1)で、2つ目は入出力引数(3 = 1 | 2)です。 thisのブログエントリによれば、それぞれの最初の数字は、Variantのデータ型の種類を示しています。

thisリストでは、数字が実際に何を意味するかを調べることができます。最初の引数は符号付きint16です。これはフレーム番号を指定するため意味があります。 2番目の数字は次の意味を持ちます。

16396 = 0x400c = VT_VARIANT | VT_BYREF 

documentationは何VT_VARIANTが実際に意味、教えてくれる。

いずれに指定された型、または要素もしくは含まれているフィールドの種類は、スーパー有益、まだ未VARIANT

でなければなりません。 ctypes.c_floatを渡す選択肢は、本当に良い選択ではないようです。代わりに、私は恐らくthisの議論から触発された変種を渡しています。

var = win32com.client.VARIANT(pythoncom.VT_VARIANT | pythoncom.VT_NULL | pythoncom.VT_BYREF, None) 
spectrum = doc.GetFrame(frame, var) 

この変更を行って以来、私はもはやこのコード部分のクラッシュを観察していないので、元の質問は私のために解決されます。

関連する問題