b-PAC SDKをPython + pythonnetで操作してみた

以前、ブラザーのラベルプリンタを操作するb-PACについて、C#でいろいろと試してみました。
ブラザーのラベルプリンタまわりを操作する b-PAC SDK を使ってみた - メモ的な思考的な

 
そんな中、前回インストールしたpythonnetを使うことで、.NET + b-PACを扱えるのではないかと考え、試してみることにしました。

 

環境

  • Windows10 x64
  • Python 3.5.1 x86
  • pythonnet 2.1.0
  • Brother QL720-NW
  • b-PAC SDK 3.1.004 (x86版)

 
virtualenv環境は以下のとおりです。

D:\sandbox>mkdir bpac_python
D:\sandbox>cd bpac_python
D:\sandbox\bpac_python>virtualenv -p c:\python35-32\python.exe env
D:\sandbox\bpac_python>env\Scripts\activate

# pythonnetを入れるために、pipを8系にアップグレード
(env) D:\sandbox\bpac_python>python -m pip install --upgrade pip
(env) D:\sandbox\bpac_python>pip install pythonnet

 

COMオブジェクトの生成

COMオブジェクトを生成するには、Activator.CreateInstance(Type.GetTypeFromProgID('ProgID')) を使うのが良さそうでした。
Instantiating a legacy COM object in C# dynamically (using its ID in a string) - Stack Overflow

以下のコードを動作させてみた結果、

import clr
from System import Activator, Type
doc = Activator.CreateInstance(Type.GetTypeFromProgID('bpac.Document'))
print("doc: {}".format(doc.__class__))
#=> doc: <class 'System.__ComObject'>

b-PACのCOMオブジェクトが生成できたようです。

 

プリンタの列挙

列挙するために、GetInstalledPrintersを使ってみたところ、

printers = doc.Printer.GetInstalledPrinters
#=> AttributeError: '__ComObject' object has no attribute 'Printer'

エラーとなりました。

 
そこで、リフレクションを使ってPrinterを取得してみます。

printer = doc.GetType().InvokeMember("Printer", BindingFlags.GetProperty, None, doc, None )
print("Printer:{}".format(printer))
#=> Printer:System.__ComObject

取得できましたが、またComObjectっぽいようです。

 
属性を確認したところ、

print(dir(printer))
#=> ['CreateObjRef', 'Equals', 'Finalize', 'GetHashCode', 'GetLifetimeService', 'GetType', 'InitializeLifetimeService', 'MemberwiseClone', 'Overloads', 'ReferenceEquals', 'ToString', '__call__', '__class__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__overloads__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__']

GetInstalledPrintersが見当たりませんでした。

 
そのため、再度リフレクションを使って取得してみます。

printers = doc.GetType().InvokeMember("GetInstalledPrinters", BindingFlags.GetProperty, None, printer, None )
print("InstalledPrinters:{}".format(printers))
#=> InstalledPrinters:System.Object[]

何かが取得できたようです。

 
中身を確認すると、

for p in printers:
    print("installed Printer:{}".format(p))
#=> installed Printer:Brother QL-720NW

プリンター情報が取得できました。

 
ここまでやったところで、

  • プリンタ情報を取得するだけでもかなりの手間でつらい
  • リフレクションを使ったイベントハンドラ設定方法がよく分からない

と感じたため、これ以上試すのはやめました。

 
b-PAC のFAQページにも

b-PACのコンポーネントは、COM コンポーネントとして実装されています

動作環境・b-PACのバージョン|FAQ(よくあるご質問)|b-PACサポート|開発者ツール|ブラザー

とあったことからも、やはりCOMを使うのが正しいのかなと感じました。

 

その他

なお、pythonnetでExcelを扱った場合は、

xlsx = Activator.CreateInstance(Type.GetTypeFromProgID('Excel.Application'))
print("xlsx: {}".format(xlsx.__class__))
#=> xlsx: <class 'Microsoft.Office.Interop.Excel.ApplicationClass'>

のように良い感じになっていましたので、それ以降もうまいこと使える印象を受けました。

 

ソースコード

プリンタ情報の取得だけですが、GitHubに上げました。
thinkAmi-sandbox/bpac_python-sample

pythonnet_ver.pyが今回のファイルになります。