MSCommコンポーネントでデータを受信するには?

解決


nabe  2009-07-02 14:35:45  No: 142137  IP: 192.*.*.*

OS:WindowsXP Professional SP3
言語:MS-Access2003 SP3 VBA

あるメーカー製のラベルプリンタとRS-232Cのシリアル通信をしてラベルを印刷するんですが、そのコンポーネントとしてMSCommコンポーネントを使っています。
ラベルプリンタに対してステータス要求コマンドを発行しているんですが、MSCommコンポーネントでは全く受信出来ず、OS付属のハイパーターミナルだと受信が可能です。
よって、、

・プリンタに異常はない
・接続ケーブルにも問題はない

ことになります。実際、MSCommコンポーネントのOutputでデータをプリンタに送信して、ラベル印刷が出来るんですが、どうやってもステータスの受信が出来ません。
ステータス要求と受信部分のソースは次の通りです。

    Do
                                        ' ステータス要求
        objCom.Output = "EST(1)"
                                        ' ステータス取得
        Do
            DoEvents
        Loop Until objCom.InBufferCount >= 8
        strStatus = objCom.Input

        (以下、略)

ステータスは8バイト+CR+LFで返ってくるハズなので、8バイト以上の受信バッファをループで待ってからステータスを取得しようとしていますが、InBufferCountが常に0の状態なので永久ループになってしまいます。
ちなみに、、

        Loop Until Len(objCom.Input) >= 8

ともしてみましたが、やはり受信できないので永久ループです。
MS-Access2003でMSCommコンポーネント(上記のソースではobjComです)を使うのは、無理があるのでしょうか?
しかし、送信が出来て受信が出来ないのはおかしな話ですし、ステータス要求コマンドを送信後に永久ループを止めて、プログラムの実行を終了させてからハイパーターミナルで接続すると、ハイパーターミナル上では(先ほど発行したステータス要求の)ステータスが返ってきます。

どうかお知恵をお借りしたく、投稿させていただきました。
どんなささいな情報でも良いので、レスをいただければ非常に嬉しいです。
宜しくお願いします。

編集 削除
nabe  2009-07-02 15:29:12  No: 142138  IP: 192.*.*.*

一応、自己レスしておきます。
プリンタのステータス監視部分はプライベート関数で完結しており、やむなくその関数内だけWin32APIを使ってみることにしました。

                                        ' シリアルポートのオープン関数の定義
Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long                                        ' CloseHandle
                                        ' シリアルポートのクローズ関数の定義
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
                                        ' シリアルポートの設定関数の定義
Private Declare Function SetCommState Lib "kernel32" (ByVal hCommDev As Long, lpDCB As DCB) As Long
                                        ' データの送信関数の定義
Private Declare Function WriteFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, lpOverlapped As Long) As Long
                                        ' データの受信関数の定義
Private Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As Long) As Long
                                        ' 読み取り用定数
Private Const GENERIC_READ = &H80000000
                                        ' 書き込み用定数
Private Const GENERIC_WRITE = &H40000000
                                        ' 既存ファイルの処理
Private Const OPEN_EXISTING = 3

Private Type DCB
    DCBlength As Long
    BaudRate As Long
    fBitFields As Long
    wReserved As Integer
    XonLim As Integer
    XoffLim As Integer
    ByteSize As Byte
    Parity As Byte
    StopBits As Byte
    XonChar As Byte
    XoffChar As Byte
    ErrorChar As Byte
    EofChar As Byte
    EvtChar As Byte
End Type

Private Function GetPrinterStatus() As Boolean
    (略)
                                        ' シリアルポートオープン
    hdlSireal = CreateFile("COM1", GENERIC_READ Or GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0)
                                        ' シリアル通信の設定
    With udtDCB
        ' 通信速度9600ボー
        .BaudRate = 9600
        ' ビット長8ビット
        .ByteSize = 8
        ' パリティなし
        .Parity = 0
        ' ストップビット1
        .StopBits = 0
    End With
    lngDummy = SetCommState(hdlSireal, udtDCB)
    
    Do
                                        ' ステータス要求
        strStatus = "EST(1)"
        dLen = LenB(StrConv(strStatus, vbFromUnicode))
        lngDummy = WriteFile(hdlSireal, strStatus, dLen, wLen, 0)  ' ココで必ずAccessが死ぬ
                                        ' ステータス取得
        strStatus = Space(10)
        lngDummy = ReadFile(hdlSireal, ByVal strStatus, 10, lngLen, 0)

どうしてもWriteFile関数を呼び出すと、Accessが必ず死ぬ(落ちる)ので、APIでも解決できませんでした。
結構切羽詰まってます。どなたかレスをお願いします。

編集 削除
うに  2009-07-02 17:16:22  No: 142139  IP: 192.*.*.*

>objCom.Output = "EST(1)"
期待しているコマンドを見ると CR + LFが
付いてきているようですが、ステータス要求送信時もCR + LFを
付加して送らないとだめなのでは?

>InBufferCountが常に0の状態なので永久ループになってしまいます。
とありますがループの中で
debug.print objCom.InBufferCount
で受信文字数を表示させても常に0ですか?

編集 削除
オショウ  2009-07-02 17:47:56  No: 142140  IP: 192.*.*.*

ラベルプリンターってどこのメーカー?

デリミタ(CR+LF)までの文字列を受信しないとエラーすら返信がない
ようですが、タイムアウト設定もありません?

因みに、MSComm32はライセンスものでVisualStudio6のインストールが
必須です。

その辺問題ありませんか?

以上。

編集 削除
うに  2009-07-03 00:36:23  No: 142141  IP: 192.*.*.*

>ラベルプリンターってどこのメーカー?
まさにこれかと。

そのプリンタメーカーとのプロトコルの仕様も
分からないので答えようがありません。

私のはエスパー回答です。

編集 削除
nabe  2009-07-03 13:00:24  No: 142142  IP: 192.*.*.*

うにさん、おしょうさん、レスありがとうございます。
プリンタメーカーは無名(業界ではちょっとは有名?)なので伏せておきますが、プリンタの制御コマンドのデリミタは不要でCR+LFがあってもなくても無視する仕様だそうです。また、タイムアウトの設定も不要です。
プロトコルはRS-232Cで9600ボー・データ長8ビット・ノンパリティ・ストップビット1です。
メーカーの技術担当者にFAXでソースを見てもらいましたが、分からないとのことで、途方に暮れてます。
VSに就いては、VS6.0Enterpriseをインストールしているのでライセンス的にも問題はありません。

>>InBufferCountが常に0の状態なので永久ループになってしまいます。
>とありますがループの中で
>debug.print objCom.InBufferCount
>で受信文字数を表示させても常に0ですか?

イミディエイトウィンドウで確認しても常に0です。
先ほど、イベントドリブン方式でやってみましたが、送信も受信も全くイベントが発生しないのを確認しました。
ところが、ハイパーターミナル上ではステータスが返ってきてました(爆)
やはり、MS-Accessでは無理があるんでしょうか?

新規で作り直したいところなんですが、お客さんが今のAccessのUIに慣れてしまっているし、納期的な問題もあって作り直せない状況です。
送信は問題なく、実際にラベル印刷しているのに、受信が全くダメというのはどう考えてもおかしいですし、気持ち悪いです。
ひょっとしてMSCommのバージョンとかって関係ありますかね?

編集 削除
うに  2009-07-03 13:26:02  No: 142143  IP: 192.*.*.*

http://www.vector.co.jp/vpack/filearea/win/hardware/comm/
あたりでソフトを見つけてきて
PCとプリンタの間にもう一台PCをはさんで
モニターするのが早そうです。

編集 削除
オショウ  2009-07-03 14:06:06  No: 142144  IP: 192.*.*.*

そのプリンターメーカーが知りたいのですが・・・

私はFA関係ソフト屋20年やっていて、プリンターメーカーとは
ほぼ全社経験あります。ラベラー貼付装置メーカーさんの下請け
も長いので、大抵解る(知らなくても技術部に問える)もので。

MS-ACCESSから安全に使いたい・・・
と言うのであれば、私的には、VC++(MFC)でシリアル通信のActiveX(OCX)
作って、MS-ACCESSから参照するかCreateObjectして行いますネ!

無茶な話、.NET(VB/C#)で作って(DLL)もう1個、COM化するラッパー
DLLを作って被せ、MS-ACCESSからCreateObjectして動作させるとか。

要はMS-ACCESS側に非同期通信の割り込み受信をさせないようにする
ことが必要なのかもしれません。同期通信のみなら問題は無いよう
にも思いますが・・・

参考まで・・・

編集 削除
GOD  2009-07-03 15:29:44  No: 142145  IP: 192.*.*.*

いくつか確認させて下さい。

>送信も受信も全くイベントが発生しない
>
とありますが、暫く(2〜3秒後)しても OutBufferCountプロパティ が 0 にな
ってはいないということですか。

>ハイパーターミナル上ではステータスが返ってきてました(爆)
>
とありますが、ハイパーターミナル上では"EST(1)"と入力した状態(Enterキーを
押さない)で返答がきていると言うことですか。

編集 削除
マルチポストだよ  2009-07-03 16:50:48  No: 142146  IP: 192.*.*.*

http://www.accessclub.jp/bbs3/wforum.cgi?no=144567&reno=no&oya=144567&mode=msgview&page=0

質問以前のマナー守ろうヨ!

編集 削除
糞塗れ  2009-07-03 19:46:52  No: 142147  IP: 192.*.*.*

http://madia.world.coocan.jp/cgi/BBSHelpMe.htm
マルチポストちゃんは禁止になってないようですが

編集 削除
nabe  2009-07-03 20:01:17  No: 142148  IP: 192.*.*.*

うにさん、レスありがとうございます。
ベクターでRS-232Cを監視するソフトをDLして使ってみましたが、やはりプリンタ側はちゃんとステータスを返してました。
もう何が何だか分かりません。(TT

編集 削除
nabe  2009-07-03 20:09:47  No: 142149  IP: 192.*.*.*

オショウさん、レスありがとうございます。

>私はFA関係ソフト屋20年やっていて、プリンターメーカーとは
>ほぼ全社経験あります。ラベラー貼付装置メーカーさんの下請け
>も長いので、大抵解る(知らなくても技術部に問える)もので。

実は私も20年前まではFA関係のソフト屋をやってました。
と、いうことで話が分かるお人だと思いますのでブッチャケますと、不二レーベル製のラベルプリンタで、コマンドはALLコマンドです。

別にMS-Accessから安全に使いたい・・・ではなく、元々がAccessで作られていたソフトを、サポートが悪い(とお客さんが言っている)某サ○ーのプリンタからの変更です。
前にも書きましたが、お客さんが現在のソフト(Access)に慣れてしまっていることと、納期的に作り直しが効かないからやむなし、なんです。
そういった制約がなければ自由に作れるんですが・・・。

編集 削除
nabe  2009-07-03 20:20:28  No: 142150  IP: 192.*.*.*

GODさん、レスありがとうございます。

>>送信も受信も全くイベントが発生しない
>>
>とありますが、暫く(2〜3秒後)しても OutBufferCountプロパティ が 0 になってはいないということですか。

イミディエイトウィンドウで確認したところでは、何秒経とうがOutBufferCountは0のままです。

>>ハイパーターミナル上ではステータスが返ってきてました(爆)
>>
>とありますが、ハイパーターミナル上では"EST(1)"と入力した状態(Enterキーを押さない)で返答がきていると言うことですか。

Accessのプログラム上でステータス要求コマンド("EST(1)")を送信しており、Accessのプログラム終了後にハイパーターミナルを起動すると、ステータスを受信した、ということです。
送受信のイベントも発生しませんし、ステータス要求コマンドを送信して、何秒待ってもInBufferCountは0のままです。
で、プログラムを終了させてハイパーターミナルを起動するとステータスを受信している、という感じです。

以上、何かお分かりなことがあれば、どんなささいな事でも結構ですので、お知らせ願えると助かります。

編集 削除
オショウ  2009-07-03 20:23:46  No: 142151  IP: 192.*.*.*

http://www.vector.co.jp/soft/dl/win95/business/se245841.html
このようにシーケンサとでもMSComm32使って通信できていますので
設定に問題があるとしか考えられませんネ!〜
以上。参考まで・・・

※  マナーとしてマルチポストは厳禁(が基本かと・・・)
    書いてないからOK・・・と言う考え方はおかしい。
    と思ってます。(個人的には)

編集 削除
nabe  2009-07-03 20:28:39  No: 142152  IP: 192.*.*.*

マルチポストだよ へ

ヒマ人は邪魔をしないで消えて下さい。正直、ウザイです。
マルチポストになるのは分かっていたが、糞塗れさんが書いている通り、この掲示板はマルチポストを禁止してないようだった(本当は悪いのだけれども、君と違って私には時間がない!)ので、書き込みをした次第。

お陰でFAシステム20年のベテランさんからもアドバイスが貰えそうなんだから、これ以上邪魔をしないように!
皆さん、大変申し訳ありませんが、どんなささいな情報でもアドバイスでも結構ですので、宜しくお願いします。<(__)>

編集 削除
しんご  2009-07-03 21:01:43  No: 142153  IP: 192.*.*.*

解決方法の一つとしてですが

1.VB6でプログラムを作成して、プリンタと通信する
  →まずはこの環境でうまくいくかどうか検証する
2.できたなら、Accessに移行する

あるいは

PC2台用意して、片方をVB6で、もう片方をAccessで
プログラム作成して、プログラムがどのように走るかを確認する

という手法はいかがでしょうか?


受信だけができないとなると、
ポートオープン時の設定が間違っているとしか
思えないのですが・・・

時間がないようですが、急がば回れとも言いますので
ご参考に。

編集 削除
オショウ  2009-07-03 23:07:50  No: 142154  IP: 192.*.*.*

同様の問題で受信しなかった・・・と言うのがありました
http://oshiete1.goo.ne.jp/qa131153.html

参考に・・・

※  もう.NETに移行して7年も経過しているので、VB6の
    環境がないので、MS-ACCESS2003でMSCOMM32を認識さ
    せるには、再インストールしなければ確認できません。
    (残念ながら・・・)
    今更VS6を導入する気は無いもので・・・

それと、MSCOMM32使ったコードの方ですが、.Outputした
後、Do〜Loop で、InBufferCountを監視されてますが、こ
の方法ですと、OnCommイベントに入ってこれないかも

OnCommで受信させてグローバル変数に文字列を書き込み、
その文字列長が8文字以上になったら・・・と変更してみ
て下さい。

※  頭が.NETのSerialPortクラス一色なもので・・・
    MSCOMM32の方法、すっかり忘れてます・・・

以上。

編集 削除
うに  2009-07-04 00:17:04  No: 142155  IP: 192.*.*.*

最近はRS232Cポートに接続する機器が中々ないのでこれはという
レスがつきにくいですね。

CR+LFの話では無いようなので検索してみました。
http://www.google.co.jp/search?q=ACCESS+MSCOMM&hl=ja&rlz=1B3GGGL_jaJP282JP282&start=10&sa=N

MScommのOncommイベントが発生しない
http://questionbox.jp.msn.com/qa131153.html
これですかねぇ。(既に見ていたらごめんなさい)

しんごさんの言われるように
一度VB6環境で試してみては如何でしょう?
サンプルもかなり見つかると思うので。

編集 削除
うに  2009-07-04 00:28:14  No: 142156  IP: 192.*.*.*

今気がつきました。
>ハイパーターミナル上では"EST(1)"と入力した状態(Enterキーを押さない)
>で返答がきていると言うことですか。

>>Accessのプログラム上でステータス要求コマンド("EST(1)")を
>>送信しており、Accessのプログラム終了後にハイパーターミナルを
>>起動すると、ステータスを受信した、ということです。

これは検証方法というか認識が違います。
Accessは一度忘れて貰って、ハイパーターミナル単体で
プリンタに接続して、ハイパーターミナルから
EST(1)
と打ったらレスポンスが返ってくるか?という話です。
EST(1) + リターンキーを押さないとレスポンスが返って
こないんじゃないの?
とGODさんは聞いているのだと思います。

編集 削除
うに  2009-07-04 04:11:56  No: 142157  IP: 192.*.*.*

もっとも最速の解決策
不二レーベル様にココのURLと意見をメールで送っておきました。

内容を詳しくは書く必要はないと思いますが、nabeさんの質問を
総合して、問い合わせに対して調査もサンプルPGも提供できないのか?
という趣旨です。

問題ありませんよね?

編集 削除
オショウ  2009-07-04 06:13:25  No: 142158  IP: 192.*.*.*

今更ですが・・・
不二レーベルのサイトでは細かい仕様を公開していないので、何ともなんで
すが、フロー制御機能搭載していません?
ご確認下さい。

サトー時代からACCESSですか・・・無茶な話ですネ!〜
で、作り直しの予算(コスト)無いので、不二レーベル向けに焼き直し?

私なら長いつきあいの企業でなくても焼き直ししますネ!〜
結局、以降の面倒は自分で見るハメになるので・・・

※  どこかにOEM供給しているか、どこかのOEM?
    見たことあるラベラーですネ!

以上。

編集 削除
GOD  2009-07-06 10:59:07  No: 142159  IP: 192.*.*.*

>イミディエイトウィンドウで確認したところでは、何秒経とうがOutBufferCountは0のままです。
>
とのことなので送信は出来ているようです。(送信バッファ0)

>Accessのプログラム上でステータス要求コマンド("EST(1)")を送信しており、
>Accessのプログラム終了後にハイパーターミナルを起動すると、ステータスを受
>信した、ということです。
>
上記で送信できており、PG終了後ハイパーターミナル起動で受信できたことを
考えると設定があやしいのだと思います。
オショウさんがおっしゃる通り、フロー制御はどうなっていますか。
RTSEnable プロパティを Ture にして試して貰えますか。

編集 削除
オショウ  2009-07-06 15:31:26  No: 142160  IP: 192.*.*.*

メーカーに直接確認してみたのですが・・・

> プリンタメーカーは無名(業界ではちょっとは有名?)なので伏せておき
> ますが、プリンタの制御コマンドのデリミタは不要でCR+LFがあってもなく
> ても無視する仕様だそうです。また、タイムアウトの設定も不要です。
> プロトコルはRS-232Cで9600ボー・データ長8ビット・ノンパリティ・スト
> ップビット1です。
> メーカーの技術担当者にFAXでソースを見てもらいましたが、分からないと
> のことで、途方に暮れてます。

    対応が悪いと言うか話になりませんでした。
    ALLコマンドのリファレンスしかお送りすることができない。
    それ以上のことは、マニュアル見てソフト会社さんで頑張ってもらう
    しかない・・・と言っておられました。

    ので、『分からない』と言うよりも『対処しない』と言う対応ではと
    思った次第。

※  別のラベラー専門メーカーさんで不二レーベルを随分昔に使ったこと
    があるので、技術に聞いたところ、そういう状況ならフロー制御じゃ
    ないかナ〜と言うことでした。

    普通はシリアルケーブルを自作して、フロ−制御信号を自分自身に折り
    返し、常時通信OKにします。

    一般のクロスケーブルを使用されているならば、フロー制御なしにして
    も、プログラム側で強制的にRTS/DTRをオンしてやる必要があります。

※  助力できるのは、このくらいかな〜
    頑張って下さい!

お試しください。

以上。

編集 削除
nabe  2009-07-07 17:39:43  No: 142161  IP: 192.*.*.*

皆さん、レスをいただきありがとうございました。
また、不二レーベルにまでお問い合わせいただいたとか。
本当に皆さんの優しさが身に沁みました。
(昨日の月曜日は心労がたたり、体調を崩してお休みしました)

具体的にはGODさんとオショウさんのレスが元で、ストレートケーブルで接続ってのもおかしい(珍しい)が、フロー制御ってしてないんじゃ・・・?
Handshakingプロパティを見ると「No handshaking」でした。orz
無論、RTSEnableプロパティは「いいえ」だし(爆)。

昔とった杵柄とばかりにコーディングしてましたが、こんな基礎的なトラップに気付かずにいたなんて、本当にお恥ずかしい限りです。このAccessのプログラムは、元々はお客さんのシステム室みたいな部門があって(今はないらしい)、そこで作られたプログラムが元なので、とても品質が悪く(まぁプロのSE/PGの仕事ではないです(^^;;)、ソースを見ると、某サトー以外にもオート某ニクスとか東芝某テックなどのコードが。要するに継ぎ足しでプリンタが変わる度にコードを追加していたようで、ステータスをチェックするのは今回が初めてのことです。
で、結論から言いますと、、

Handshakingプロパティ  →  Request-to-send, XOn/XOff handshaking.
RTSEnableプロパティ    →  はい

に設定したところ、無事にステータスを受信することが出来ました。
何とか皆さんのお陰で、ヒントをいただき、試行錯誤しつつ、結果的に満足の行く形でコーディングが完了したので、本当に感謝しております。

実は他にも同時並行で2〜3のタスクをこなさなければならないので、取り急ぎ解決の報告と感謝の言葉まで。この度は本当にありがとうございました。

編集 削除