Pythonを使用した1CとDLLの統合

こんにちはHabr! 最近、物流用のアルゴリズムを開発しました。どこかに添付する必要がありました。 Webサービスに加えて、このモジュールを1Cで実装することが決定され、かなりの落とし穴が発生しました。



まず、アルゴリズム自体はdllライブラリの形式で提供されます。このライブラリには、パラメータとしてJSON文字列を取り、2つのコールバックを提供する1つのエントリポイントがあります。 最初は実行ステータスを表示し、もう1つは結果を取得します。 Webサービスのすべては非常に簡単です。Pythonには素晴らしいctypesパッケージがあり、必要なライブラリをロードしてエントリポイントを指定するだけです。



次のようになります。



import ctypes def callback_recv(*args): print(args) lib = ctypes.cdll.LoadLibrary('test.dll') Callback = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p) my_func = getattr(lib, '_ZN7GtTools4testEPKcPFviS1_E') cb_func = Callback(callback_recv) my_func(ctypes.c_char_p('some data'), cb_func)
      
      





あなたが見ることができるように、エントリポイントが非常に読みやすいではありません。 skompilirovnannyhデータにこの行を見つけるには、あなたは簡単に名前が希望する方法を見つけることができる出力に拡張子.LIBと、対応するファイルを開き、-Dパラメータでobjdumpのユーティリティを使用する必要があります。



異なったすべてのエントリポイントの名前、および異なるコンパイラ「不自由」 - このマングリング方法はManglaコンパイラ(マングル«マングル»)という事実によるものです。 例に設定方法は、MinGWのを取得し



1Cでは、それははるかに少ない些細でした。 外部コンポーネントを登録することができ、それはネイティブAPIインタフェース特別だった持っているDLLの必要性を接続します。 マークは、例えば書いたが、離陸しません。 私はそれが理由のgccだと思いました。 すべての私の試みは、Visual Studioを置くためには、インストールに失敗し、何もされている、それは標準ライブラリの十分ではありません。



すでに眠っている私は、独創的な仮説を思い付きました。 Pythonはすべてで可能であることすべてをrazrabotnoので、おそらく問題は、Pythonistasを残すことができませんでした。 一般的に、インターネットの真ん中34で、唯一素晴らしいのPythonに関して。 そしてので、私は正しかったです!



Python用win32com regestrirovat Pythonは、COMオブジェクトなどのオブジェクトことができますパッケージがあります。 私も実際にどのようなCOMオブジェクトを理解していないが、私は彼が1Cに可能であることを知っているので、私にとっては、魔法のようなものでした。



pypiwin32パッケージは、次のように、ピップのことで入れ、そのインストーラをダウンロードする必要はありません。 なぜ一部のオブジェクトは、インストール後にregestrirovalis pip'omではありません。



小さな例を扱った、私が開発に着手しました。 あなたはシステムにCOM-オブジェクトの識別インタフェースを持つオブジェクトを作成する必要がまず



 class GtAlgoWrapper(): # com spec _public_methods_ = ['solve','resultCallback', 'progressCallback',] #   _public_attrs_ = ['version',] #   _readonly_attr_ = [] _reg_clsid_ = '{2234314F-F3F1-2341-5BA9-5FD1E58F1526}' # uuid  _reg_progid_= 'GtAlgoWrapper' # id  _reg_desc_ = 'COM Wrapper For GTAlgo' #   def __init__(self): self.version = '0.0.1' self.progressOuterCb = None # ... def solve(self, data): # ... return '' def resultCallback(self, obj): # ... return obj def progressCallback(self, obj): #     1 ,     #     if str(type(obj)) == "<type 'PyIDispatch'>": com_obj = win32com.client.Dispatch(obj) try: #    1 (progressCallback)    self.progressOuterCb = com_obj.progressCallback1C; except AttributeError: raise Exception('"progressCallback"     ') return obj
      
      



resultCallback'、 'progressCallback']#の class GtAlgoWrapper(): # com spec _public_methods_ = ['solve','resultCallback', 'progressCallback',] # _public_attrs_ = ['version',] # _readonly_attr_ = [] _reg_clsid_ = '{2234314F-F3F1-2341-5BA9-5FD1E58F1526}' # uuid _reg_progid_= 'GtAlgoWrapper' # id _reg_desc_ = 'COM Wrapper For GTAlgo' # def __init__(self): self.version = '0.0.1' self.progressOuterCb = None # ... def solve(self, data): # ... return '' def resultCallback(self, obj): # ... return obj def progressCallback(self, obj): # 1 , # if str(type(obj)) == "<type 'PyIDispatch'>": com_obj = win32com.client.Dispatch(obj) try: # 1 (progressCallback) self.progressOuterCb = com_obj.progressCallback1C; except AttributeError: raise Exception('"progressCallback" ') return obj



class GtAlgoWrapper(): # com spec _public_methods_ = ['solve','resultCallback', 'progressCallback',] # _public_attrs_ = ['version',] # _readonly_attr_ = [] _reg_clsid_ = '{2234314F-F3F1-2341-5BA9-5FD1E58F1526}' # uuid _reg_progid_= 'GtAlgoWrapper' # id _reg_desc_ = 'COM Wrapper For GTAlgo' # def __init__(self): self.version = '0.0.1' self.progressOuterCb = None # ... def solve(self, data): # ... return '' def resultCallback(self, obj): # ... return obj def progressCallback(self, obj): # 1 , # if str(type(obj)) == "<type 'PyIDispatch'>": com_obj = win32com.client.Dispatch(obj) try: # 1 (progressCallback) self.progressOuterCb = com_obj.progressCallback1C; except AttributeError: raise Exception('"progressCallback" ') return obj



' #UUID class GtAlgoWrapper(): # com spec _public_methods_ = ['solve','resultCallback', 'progressCallback',] # _public_attrs_ = ['version',] # _readonly_attr_ = [] _reg_clsid_ = '{2234314F-F3F1-2341-5BA9-5FD1E58F1526}' # uuid _reg_progid_= 'GtAlgoWrapper' # id _reg_desc_ = 'COM Wrapper For GTAlgo' # def __init__(self): self.version = '0.0.1' self.progressOuterCb = None # ... def solve(self, data): # ... return '' def resultCallback(self, obj): # ... return obj def progressCallback(self, obj): # 1 , # if str(type(obj)) == "<type 'PyIDispatch'>": com_obj = win32com.client.Dispatch(obj) try: # 1 (progressCallback) self.progressOuterCb = com_obj.progressCallback1C; except AttributeError: raise Exception('"progressCallback" ') return obj



class GtAlgoWrapper(): # com spec _public_methods_ = ['solve','resultCallback', 'progressCallback',] # _public_attrs_ = ['version',] # _readonly_attr_ = [] _reg_clsid_ = '{2234314F-F3F1-2341-5BA9-5FD1E58F1526}' # uuid _reg_progid_= 'GtAlgoWrapper' # id _reg_desc_ = 'COM Wrapper For GTAlgo' # def __init__(self): self.version = '0.0.1' self.progressOuterCb = None # ... def solve(self, data): # ... return '' def resultCallback(self, obj): # ... return obj def progressCallback(self, obj): # 1 , # if str(type(obj)) == "<type 'PyIDispatch'>": com_obj = win32com.client.Dispatch(obj) try: # 1 (progressCallback) self.progressOuterCb = com_obj.progressCallback1C; except AttributeError: raise Exception('"progressCallback" ') return obj



== "<タイプ'PyIDispatch'>": class GtAlgoWrapper(): # com spec _public_methods_ = ['solve','resultCallback', 'progressCallback',] # _public_attrs_ = ['version',] # _readonly_attr_ = [] _reg_clsid_ = '{2234314F-F3F1-2341-5BA9-5FD1E58F1526}' # uuid _reg_progid_= 'GtAlgoWrapper' # id _reg_desc_ = 'COM Wrapper For GTAlgo' # def __init__(self): self.version = '0.0.1' self.progressOuterCb = None # ... def solve(self, data): # ... return '' def resultCallback(self, obj): # ... return obj def progressCallback(self, obj): # 1 , # if str(type(obj)) == "<type 'PyIDispatch'>": com_obj = win32com.client.Dispatch(obj) try: # 1 (progressCallback) self.progressOuterCb = com_obj.progressCallback1C; except AttributeError: raise Exception('"progressCallback" ') return obj





そしてもちろん、その登録を記述する



 def main(): import win32com.server.register win32com.server.register.UseCommandLine(GtAlgoWrapper) print('registred') if __name__ == '__main__': main()
      
      





あなたはシステムでスクリプトを実行すると、オブジェクトをGtAlgoWrapperます。 1Cからの彼の呼び出しは次のようになります。



  progressCallback1C(, )  (" = " + ); (" = " + );  //...  1() //   =  COM("GtAlgoWrapper"); //  .progressCalback(); //...  = ...; // JSON  .solve(); 
      
      





このように、すべての数字を処理することができるコールバック内に入ります。 まだ不明のままかもしれない唯一のもの - 1CにDLLからデータを転送する方法:



 _dependencies = ['libwinpthread-1.dll', 'libgcc_s_dw2-1.dll', # ..., 'GtRouting0-0-1.dll'] def solve(self, data): prefix_path = 'C:/release' #       try: for dep in self._dependencies: ctypes.cdll.LoadLibrary(os.path.join(prefix_path, dep)) #        lib = ctypes.cdll.LoadLibrary(os.path.join(prefix_path, 'GtAlgo0-0-1.dll')) except WindowsError: raise Exception('cant load' + dep) solve_func = getattr(lib, '_ZN6GtAlgo5solveEPKcPFviS1_ES3_') #   StatusCallback = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p) ResultCallback = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p) scb_func = StatusCallback(self.progressOuterCb) rcb_func = ResultCallback(self.resultOuterCb) #  1C        DLL. Magic! if self.resultOuterCb is None: raise Exception('resultCallback function is not Set') if self.progressOuterCb is None: raise Exception('progressCallback function is not Set') #   solve_func(ctypes.c_char_p(data), scb_func, rcb_func)
      
      



_dependencies = ['libwinpthread-1.dll', 'libgcc_s_dw2-1.dll', # ..., 'GtRouting0-0-1.dll'] def solve(self, data): prefix_path = 'C:/release' # try: for dep in self._dependencies: ctypes.cdll.LoadLibrary(os.path.join(prefix_path, dep)) # lib = ctypes.cdll.LoadLibrary(os.path.join(prefix_path, 'GtAlgo0-0-1.dll')) except WindowsError: raise Exception('cant load' + dep) solve_func = getattr(lib, '_ZN6GtAlgo5solveEPKcPFviS1_ES3_') # StatusCallback = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p) ResultCallback = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p) scb_func = StatusCallback(self.progressOuterCb) rcb_func = ResultCallback(self.resultOuterCb) # 1C DLL. Magic! if self.resultOuterCb is None: raise Exception('resultCallback function is not Set') if self.progressOuterCb is None: raise Exception('progressCallback function is not Set') # solve_func(ctypes.c_char_p(data), scb_func, rcb_func)



'GtAlgo0-0-1.dll')) _dependencies = ['libwinpthread-1.dll', 'libgcc_s_dw2-1.dll', # ..., 'GtRouting0-0-1.dll'] def solve(self, data): prefix_path = 'C:/release' # try: for dep in self._dependencies: ctypes.cdll.LoadLibrary(os.path.join(prefix_path, dep)) # lib = ctypes.cdll.LoadLibrary(os.path.join(prefix_path, 'GtAlgo0-0-1.dll')) except WindowsError: raise Exception('cant load' + dep) solve_func = getattr(lib, '_ZN6GtAlgo5solveEPKcPFviS1_ES3_') # StatusCallback = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p) ResultCallback = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p) scb_func = StatusCallback(self.progressOuterCb) rcb_func = ResultCallback(self.resultOuterCb) # 1C DLL. Magic! if self.resultOuterCb is None: raise Exception('resultCallback function is not Set') if self.progressOuterCb is None: raise Exception('progressCallback function is not Set') # solve_func(ctypes.c_char_p(data), scb_func, rcb_func)



DEP) _dependencies = ['libwinpthread-1.dll', 'libgcc_s_dw2-1.dll', # ..., 'GtRouting0-0-1.dll'] def solve(self, data): prefix_path = 'C:/release' # try: for dep in self._dependencies: ctypes.cdll.LoadLibrary(os.path.join(prefix_path, dep)) # lib = ctypes.cdll.LoadLibrary(os.path.join(prefix_path, 'GtAlgo0-0-1.dll')) except WindowsError: raise Exception('cant load' + dep) solve_func = getattr(lib, '_ZN6GtAlgo5solveEPKcPFviS1_ES3_') # StatusCallback = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p) ResultCallback = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p) scb_func = StatusCallback(self.progressOuterCb) rcb_func = ResultCallback(self.resultOuterCb) # 1C DLL. Magic! if self.resultOuterCb is None: raise Exception('resultCallback function is not Set') if self.progressOuterCb is None: raise Exception('progressCallback function is not Set') # solve_func(ctypes.c_char_p(data), scb_func, rcb_func)



') _dependencies = ['libwinpthread-1.dll', 'libgcc_s_dw2-1.dll', # ..., 'GtRouting0-0-1.dll'] def solve(self, data): prefix_path = 'C:/release' # try: for dep in self._dependencies: ctypes.cdll.LoadLibrary(os.path.join(prefix_path, dep)) # lib = ctypes.cdll.LoadLibrary(os.path.join(prefix_path, 'GtAlgo0-0-1.dll')) except WindowsError: raise Exception('cant load' + dep) solve_func = getattr(lib, '_ZN6GtAlgo5solveEPKcPFviS1_ES3_') # StatusCallback = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p) ResultCallback = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p) scb_func = StatusCallback(self.progressOuterCb) rcb_func = ResultCallback(self.resultOuterCb) # 1C DLL. Magic! if self.resultOuterCb is None: raise Exception('resultCallback function is not Set') if self.progressOuterCb is None: raise Exception('progressCallback function is not Set') # solve_func(ctypes.c_char_p(data), scb_func, rcb_func)



ctypes.c_char_p) _dependencies = ['libwinpthread-1.dll', 'libgcc_s_dw2-1.dll', # ..., 'GtRouting0-0-1.dll'] def solve(self, data): prefix_path = 'C:/release' # try: for dep in self._dependencies: ctypes.cdll.LoadLibrary(os.path.join(prefix_path, dep)) # lib = ctypes.cdll.LoadLibrary(os.path.join(prefix_path, 'GtAlgo0-0-1.dll')) except WindowsError: raise Exception('cant load' + dep) solve_func = getattr(lib, '_ZN6GtAlgo5solveEPKcPFviS1_ES3_') # StatusCallback = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p) ResultCallback = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p) scb_func = StatusCallback(self.progressOuterCb) rcb_func = ResultCallback(self.resultOuterCb) # 1C DLL. Magic! if self.resultOuterCb is None: raise Exception('resultCallback function is not Set') if self.progressOuterCb is None: raise Exception('progressCallback function is not Set') # solve_func(ctypes.c_char_p(data), scb_func, rcb_func)



ctypes.c_char_p) _dependencies = ['libwinpthread-1.dll', 'libgcc_s_dw2-1.dll', # ..., 'GtRouting0-0-1.dll'] def solve(self, data): prefix_path = 'C:/release' # try: for dep in self._dependencies: ctypes.cdll.LoadLibrary(os.path.join(prefix_path, dep)) # lib = ctypes.cdll.LoadLibrary(os.path.join(prefix_path, 'GtAlgo0-0-1.dll')) except WindowsError: raise Exception('cant load' + dep) solve_func = getattr(lib, '_ZN6GtAlgo5solveEPKcPFviS1_ES3_') # StatusCallback = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p) ResultCallback = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p) scb_func = StatusCallback(self.progressOuterCb) rcb_func = ResultCallback(self.resultOuterCb) # 1C DLL. Magic! if self.resultOuterCb is None: raise Exception('resultCallback function is not Set') if self.progressOuterCb is None: raise Exception('progressCallback function is not Set') # solve_func(ctypes.c_char_p(data), scb_func, rcb_func)



セット」) _dependencies = ['libwinpthread-1.dll', 'libgcc_s_dw2-1.dll', # ..., 'GtRouting0-0-1.dll'] def solve(self, data): prefix_path = 'C:/release' # try: for dep in self._dependencies: ctypes.cdll.LoadLibrary(os.path.join(prefix_path, dep)) # lib = ctypes.cdll.LoadLibrary(os.path.join(prefix_path, 'GtAlgo0-0-1.dll')) except WindowsError: raise Exception('cant load' + dep) solve_func = getattr(lib, '_ZN6GtAlgo5solveEPKcPFviS1_ES3_') # StatusCallback = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p) ResultCallback = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p) scb_func = StatusCallback(self.progressOuterCb) rcb_func = ResultCallback(self.resultOuterCb) # 1C DLL. Magic! if self.resultOuterCb is None: raise Exception('resultCallback function is not Set') if self.progressOuterCb is None: raise Exception('progressCallback function is not Set') # solve_func(ctypes.c_char_p(data), scb_func, rcb_func)



セット」) _dependencies = ['libwinpthread-1.dll', 'libgcc_s_dw2-1.dll', # ..., 'GtRouting0-0-1.dll'] def solve(self, data): prefix_path = 'C:/release' # try: for dep in self._dependencies: ctypes.cdll.LoadLibrary(os.path.join(prefix_path, dep)) # lib = ctypes.cdll.LoadLibrary(os.path.join(prefix_path, 'GtAlgo0-0-1.dll')) except WindowsError: raise Exception('cant load' + dep) solve_func = getattr(lib, '_ZN6GtAlgo5solveEPKcPFviS1_ES3_') # StatusCallback = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p) ResultCallback = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p) scb_func = StatusCallback(self.progressOuterCb) rcb_func = ResultCallback(self.resultOuterCb) # 1C DLL. Magic! if self.resultOuterCb is None: raise Exception('resultCallback function is not Set') if self.progressOuterCb is None: raise Exception('progressCallback function is not Set') # solve_func(ctypes.c_char_p(data), scb_func, rcb_func)





正常に動作させるために、最初にすべてのそれはGtAlgoWrapperクラスを登録するのpython-コールスクリプトを必要とし、その後、安全1Cの設定を実行することができます。



それは、強力なジャングルにクロールされません、それはパイソンを使用してDLLライブラリおよび1Cをリンクするのがいかに簡単です。

すべてのマジック!



便利なリンク
docs.python.org/3/library/ctypes.html -パッケージをctypesは

citforum.ru/book/cook/dll0.shtml -ダミーのための動的ライブラリ

habrahabr.ru/post/191014 - NativeAPI

infostart.ru/public/115486 - CでのCOMオブジェクト++

infostart.ru/public/190166 - PythonでCOMオブジェクト

pastebin.com/EFLnnrfp -記事からPythonで完全なスクリプトコード



All Articles