2015年5月28日木曜日

b-PAC+PT-9700PC(PT-9800PCN)で、COM相互運用型エラー、エラーは出ないが印刷も出ない、COMエラー発生し印刷できない


久々のプログラム制作

今さら感あるバーコードですが、JAN(EAN)とCODE39を印字しようと調べるとブラザーのラベルプリンターが他社の1/10程の低価格。またB-PACと言うSDKがあり自プログラムから印刷可能。早々PT-9700PCを購入し、そのB-PACを使ってみると・・・

嵌る・・・。プリンターが全くうんともすんとも言わない。

環境はWindows7の64bitとWindows8.1の64bit+VS2010、VS2012、VS2013、の6通り。
全て試したがエラー発生せず。エラーが発生しない=こう言うのが一番困ります。




ちなみにブラザーのラベルプリンターの価格は・・
「今どきUSB接続しか出来ないPT-9700PCが約2万、LAN接続できるPT-9800PCNは何と倍の4万強」高過ぎですね。
一応プリンターやSDKが外れの可能性もあるので安い方、PT-9700PCを購入。







エラーその1

「相互運用型 ‘bpac.DocumentClass’ を埋め込むことができません。代わりに適用可能なインターフェイスを使用してください」。

<対処方法>
これはググると答えが沢山出てくる。「b-pac エラー」などで。

このサイトから情報登録するとSDKをDL出来るが、ここでDLしたSDKをインストール。
(私はVer3.1.003の64bitバージョンDL ← これも間違いの原因=その2で悩んだエラーの原因)
するとVisualStudioのプロジェクトにCOMの参照を追加できるのだが・・。

現実には参照で、Brother b-PAC 3.1 Type Library(ver1.3、なんで1.3なの?)を追加するとbpacと言う参照が出来、これをクリックすると「相互運用機能型の埋め込み」と言うプロパティーがあり、これがTrueになってるからFalseにする。

この問題は5分で解決。






エラーその2

上記対処してもプリンターは全くうんともすんとも言わない。プリンターを購入するとラベルをデザインできるP-touch Editor 5.1と言うのが付いており、このソフトからは問題なく印刷できる。


<エラー内容>

なし。そう、エラーにならないのです、自プロから印刷ボタンをクリックしても何の応答もなし。テンプレートのオープン、StartPrint、PrintOut、EndPrint、クローズ、何のエラーも起こらずスルーしてしまいます。

結局半日ほど悩み・・こういう時はホボ凡ミスが原因が多い・・と、初心に戻り最初から抜けがないか手順を追ってみと発見!原因は・・・やはりクダラナイ・・


<原因>

PT-9700PC(PT-9800PCN)に適合しているSDKが何と!!32ビット版のみ!
※私は64bit windowsなので気にせず64bit版をインストールしていた。

流石元が古いプリンターとSDKです。答えはブラザーのサイトにありましたが、もっと分かり易い所に書け!と言いたくなります。



b-PACトップ → 動作環境の下の方
 


<対処方法>

1.b-PAC、64bitSDKをアンインストール(私の場合)
2.b-PAC、32bitSDKをDLしてインストール


上記行うと、32bit版SDKが、ちゃんとx86フォルダへインストールされます。





余談)
Brotherのサンプルプログラムが使うラベルのテンプレートフォルダは64bit版sdkをインストールしたと仮定しているようで、要注意!!
素直にサンプルに従い、プログラムで読み込むテンプレートフォルダ先を間違えるとまた変なエラーが発生し悩むでしょう





これで大丈夫だろうと思っていたら、今度はCOMエラーが発生。今更COMですか?めんどくさい・・・

エラーその3へ進む・・・






エラーその3

テンプレートのOPENで下記エラー発生。

<エラー内容>

------------------------------------
COMException
------------------------------------
CLSID {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} を含むコンポーネントの COM クラス ファクトリを取得中に、次のエラーが発生しました: 80040154

クラスが登録されていません (HRESULT からの例外:0x80040154 (REGDB_E_CLASSNOTREG))。
------------------------------------

こういう濃いエラーは、ググれば絶対誰かがUPしている筈!とググったら素晴らしい方が記事を残してくれていました!
こちらの素晴らしい方のおかげで即解決 → こちらのお方
自己解決ではありませんが、最近はnetデバッグありですから。


※余談だが、最近netを見ていると2/3程のブログは嘘を書いている=本人自身が嘘を書いている事に気付いていない。かなりレベルの低い自称SEがいるのでご注意!こういう方々を雇ってしまったら爆弾抱えている状態=かなり怖ろしい・・しかも60-70%がこう言う方々。今後は面接よりペーパーテストを強烈に重視したいと思います。




<原因>

32bit版COMなので(何だか知らんがSDKが32bitだからそうだろうと勝手に解釈)、
プロジェクトのターゲットプラットフォームも32bitにしないとCOMエラーが発生する。



<対処>

プロジェクトのプロパティーにあるターゲットプラットホームをx86にする。








これ等、エラー3点の対処を行うと、バーコードが印刷された!祝


余談、最初から滞りなくやれたら「なんだこれ?こんな簡単なんだ」となるのでしょうが、システム開発ってクダラナイ事に時間取られすぎます。それがノウハウになりますが、でもそもそも論から言えば、それって違うのでは?ですね。早く明るい業界になって欲しいものです。




以上で、C#、.NET Framework4(2~4、OK!)を使い、自プロからBrotherラベルプリンターへの出力印刷が完了です。

ちなみに制作しているモノはシリアルNo+製造番号ロットNo自動採番+バーコード出力プログラムです。









<その他の注意点:別のエラー>

これも1度引っかかったので解説。

・サンプルプログラム実行時の注意点!

上記で言いましたが私の場合、P-touch Editor 5.1で作成したテンプレート、ibx、のロケーションフォルダ。32bit版sdkなので¥Program Files (x86)¥、です。

ブラザーのサンプルは¥Program Files¥となっているので要注意。このまま実行すればまた別のエラーが発生して悩みます。

※くだらないエラーであればある程、原因特定するのに時間かかる事が多いのでご注意を。




以上で解決です。

ちなみに上記サンプルで普通に印刷出来ます。







< まとめ >

1.32bitか64bitか、SDKを間違えずにインストールする
  ※印刷したいラベルプリンターに対応しているSDKを間違えずにDLしインストールする
  確認はこちら → こちら

2.SDK提供のコンポーネントをプロジェクトの参照に追加する
  ※SDKをインストールすると、参照の追加で勝手にCOMの一覧に出てくる

3.interop.bpac(COM)の相互運用型をfalseに
  ※参照設定下にあります(C#の場合)VBだとどこにあるのか知りません。

4.プロジェクトのターゲットプラットホームをx86にする
  ※PT-9700PC、PT-9800PCN等の場合、SDKが32bitだからx86にした。
  確認はこちら → こちら
  ※64bitSDKならx64かAnyCPUでokでは?ご自身でテスト下さい。

5.ブラザー提供のサンプルプログラム
  ラベルのテンプレートフォルダのフォルダ位置が正しいか確認
  ※Program Files (x86)かProgram Files 、どちらなのか、インストールしたSDK位置に合わせる 

6.コンパイル → 実行

※上記はPT-9700PC(PT-9800PCN)が32bitSDKにしか対応していないから32bit版をDLしたり、ターゲットプラットホームをx86にしている

ブラザーのどのラベルプリンターでも同様!ではないので、先程紹介したリンクから確認する事
http://www.brother.co.jp/dev/bpac/env/index.htm ← ここ!







・エラーとは関係ないが、一応、どのフレームワークに対応しているのか試す

 〇:.NET framework 2.0
 〇:.NET framework 3.0
 〇:.NET framework 3.5
 〇:.NET framework 4
 ×:.NET framework 4.5
 ×:.NET framework 4.51


どうやら4.5以上はダメ、エラーが出る。だから素直に4を使いました。
よってVS2013でも開発出来る。

 
 



・それと使用フレームワークを.NET framework 2.0(や3.0?)に変更して遊んでいるとプロジェクトフォルダーにゴミがたんまり出来る(本当はゴミではないが・・)

system.なんちゃらとかMicrosoft.なんちゃらとか・・プロ内で使ってるからMSが親切にCOPYしてくれたのかな?

BrotherのSDKもサンプルも、元は古いので使用フレームワークが2.0や3.0になっている。
従って、遊んでるとゴミ?だらけになるので注意。

その場合は、フォルダ内の見た目が悪いので、プロジェクトを削除し、新しいモノに作り直しましょう
※ソースも消さないよう、どこかに保管しとかないと後で泣きますよ

そしてプロジェクトのプロパティーでフレームワークを4.0などになっているか、確認しましょう。









一応、プログラムからテンプレートのバーコードの数値をセットして印字するプログラムソース兼テストプログラム、載せときます。どうでも良い程度のコードですが、一応。C#。

ちゃんと環境が正しく、かつ、プリンターが正常に接続されていれば、
code39バーコードのコード:C987Z6001Q(末尾に自動でチェックデジットが追加されていた=助かった)が、印刷されます。テープ幅は12mmを使用。

        const int TAPE_WIDTH = 12;
        const string TEMPLATE_FOLDER = "C:\\Users\\xx\\xx管理システム\\";
        const string TEMPLATE_FILE = "CODE39_1.lbx";
        const string TEMPLATE_PRINTER = "";
        public bool BarPrint()
        {
            string templatePath = TEMPLATE_FOLDER + TEMPLATE_FILE + TEMPLATE_PRINTER;
            bool ret = false;

            bpac.DocumentClass doc = new DocumentClass();
            if (doc.Open(templatePath))
            {
                MessageBox.Show(doc.Width.ToString(), "tape幅");
                MessageBox.Show(doc.Length.ToString(), "tape長DPI");
                MessageBox.Show((doc.Length * 254 / 1440).ToString(), "tape長");
                MessageBox.Show(doc.GetMediaId().ToString(), "メディアID");
                MessageBox.Show(doc.GetMediaName(), "メディア名");
                MessageBox.Show(doc.GetPrinterName(), "プリンター名");
                MessageBox.Show(doc.GetBarcodeIndex("CODE39").ToString(), "バーコードインデックス");
                MessageBox.Show(doc.CurrentSheet, "カレントシート");
                MessageBox.Show(doc.CutLineCount.ToString(), "カットライン");
                object[] sheetNames = doc.SheetNames as object[];
                foreach (string sheetName in sheetNames)
                {
                    MessageBox.Show(sheetName, "シート名");
                }
                // プリンターリストを取得
                object[] printers = (object[])doc.Printer.GetInstalledPrinters();
                foreach (string printerName in printers)
                {
                    //オンラインかどうかをチェックする
                    if (doc.Printer.IsPrinterOnline(printerName))
                    {
                        MessageBox.Show(printerName, "Online");
                    }
                    else
                    {
                        MessageBox.Show(printerName, "Offline");
                    }
                }
                // バーコード生成&セット
                doc.SetBarcodeData(doc.GetBarcodeIndex("CODE39"), "C987Z6001Q");
                // 印刷
                doc.StartPrint("", bpac.PrintOptionConstants.bpoDefault);
                doc.PrintOut(1, bpac.PrintOptionConstants.bpoDefault);
                doc.EndPrint(); // ここを通り過ぎると印刷される模様 
                   
                doc.Close();
                ret = true;
            }
            else
            {
                System.Windows.Forms.MessageBox.Show("プリンターがOPENできませんでした。", "エラー");
            }
            doc = null;
            return ret;
        }
    }



 <結果>

doc.Width         680      テープ幅
doc.Length        2556      テープ帳DPI
doc.Length * 254 / 1440     450      テープ長
doc.GetMediaId()       259      メディアID
doc.GetMediaName()     12mm      メディア名
doc.GetPrinterName()     Brother PT-9700PC  プリンター名
doc.GetBarcodeIndex("CODE39")  0       バーコードインデックス
doc.CurrentSheet      シート1     カレントシート
doc.CutLineCount      0       カットライン
doc.SheetNames as object[n]  シート1     SheetNames
doc.Printer.IsPrinterOnline(printerName) Brother PT-9700PC  オンライン
doc.SetBarcodeData(doc.GetBarcodeIndex("CODE39"), "C987Z6001Q");

印刷されたバーコード ⇒  C987Z6001QI
※印字してみたところ、自動でチェックデジットが追加されていた(上記の場合は I です)

それをバーコードリーダーで読込  ⇒  c987z6001qi




・元になったテンプレートと印刷結果を載せておきます

このテンプレートのバーコード、下のテープ部からはみ出てますが、はみ出た部分は無視され普通に印刷してくれます。
※ファイル名が違いますが・・でも同一テンプレートです





こんな小さな印刷物、テープ幅12mmにCODE39だから物凄く小さいです。
でも2千円のリーダーでもちゃんと読み取れます。





この写真はブラザーのテストプログラムから印字したものですが、上記プログラムからも印刷出来ますので。




という事で久々にプログラム組みましたが、やはり楽しいですね。
何時もDBしか相手にしていませんでしたが、こうやって目で見えるモノが出てくると、尚楽しいです。



 おわり