イメージ 1

イメージ 2

イメージ 3

イメージ 4

イメージ 5

イメージ 6

イメージ 7

イメージ 8

なにのきっかけだか、Km2NetのUSB-IOのインターフェースをC++で制御したくなった。と言うのも最近VisualC++2008ExpressでDLLライブラリを参照利用する方法について色々と調べていたのだ。ここにUSBIOというインターフェースがあったので、これでDLLの参照を試してみたわけです。以下はその内容について書いたものです。
今まではこのUSBIOをエクセルVBAとかVBnet、VB2005、VB2008で利用するDLLの使い方はパケさんの趣味の部屋で公開されており十分利用できていました。今回はVisualC++2008Expressと2010ExpressのC++での制御をトライしてみました。内容としてはライブラリとして公開されているvbausbio.dll(2007/05/18 12:40 制御関数は6つ以下参照)を読み込み制御するものです。ところでインターネット上ではこのUSBIOをVC++2008Expressで制御するフリーのサンプルは機能が制限されているものとして三石印房のUSB-IO専用 DLL Demoがあります。しかしながらこれはコンソール上でのサンプルで、目的としているCLRのWindowsフォームアプリケーションでありませんでした。検索しても何処にもVC++2008ExpressWindowsフォームでの使用例が無いものは何とかしてサンプルでも作るしかないと思い、色々と試してみたわけです。しかしVBの資料はたくさんあるがVC++2010,2008のDLL関数参照資料はほんとに少ないのには参った。
 まず最初に行ったのは、VBA、VB用として公開されているvbusbio.dllの関数をライブラリにEXPORTSすることです。これを行う方法はコンソール窓でコマンドライン処理(DOS式)にて行います。この方法はインターネットで"DLLファイルからlibファイルを作成"と検索すると色々と方法が出てきますので見て解りやすいものを応用します。
用意するものは 任意に作製したフォルダに dumpbin.exe ,lib.exe ,link.exe ,mspdb80.dll とライブラリを作るもとのdllの vbusbio.dll をコピーします。(最初のexeファイル3つはインストールされているのはMicrosoft Visual studio 9.0/vc/bin 最後のはMicrosoft Visual studio 9.0/Common7/IDEにあります。)実際にライブラリを作る手順は次の通りです。コマンドプロンプトで
dumpbin /exports vbausbio.dll > vbausbio.txt
で関数のリストが出てきます。これを関数のみに書き直しdefファイルの拡張子で保存します。vbausbio.defも画像添付しました。これを使いlibを作製します。次にコマンドプロンプトで 
lib /DEF:vbusbio.def /MACHINE:X86 /out:vbusbio.lib
と入力します。エラーがない場合に同フォルダにvbusbio.lib とvbusbio.expが出来ます。ここで出来たvbusbio.libを作製するプロジェクト上にvbusbio.dllと2つコピーします。ちなみにここでEXPORTSしたvbusbio.dllの関数は次の6つです。
[uio_find, uio-free, uio_getdevs, uio_inp, uio_out, uio_seldev]
以上のものをVisualC++2008ExpressのCLRのWindowsフォームアプリケーションで制御できるようにします。まずはプロジェクトを一つ作製します。フォームサンプルが作製されていてあとはツールボックからコマンドボタンとかコントロールを貼り付けたりします。実際のサンプルを載せました。Windowsフォームアプリケーションはウィンドーの処理とかは自動でコーディングされる為、案外複雑に見えますが、実際はコマンドボタン等のイベントを選びイベントの中にコーディングするのみで問題ありません。今回の一番のポイントはvbusbio.dllをc++で利用する時のヘッダーでの宣言方法です。これはヘッダーを新たに自分で追加しても良いし、最初から自動でできているstdafx.hのヘッダー内に追加してもいづれでも全く問題ありません。プログラム上で必要な位置で使用する前に宣言されていれば良いのです。ところで今回の関数の場合は以下のようになります。
extern "C" int __declspec(dllimport) __cdecl uio_out(int Port,int OutDat,int p3);
実際の例でC++Builderのサンプルがありますが、サンプルでは__stdcall が使われています。今回は上記のように宣言してOKとなります。(注意※C++Builder用のDLLやLIBやヘッダーは使いません)同様に残りの関数も宣言します。添付画像参照(省略)実際の制御関数を使ったプログラムは引数を間違えないように、宣言した通りに使用します。ここではC++Builder添付のヘッダーcppusbio.hの資料が大変参考になりました。コマンドボタンを押しコーディング部に ポート1にデータ0をパルス出力なしで書き換えるは uio_out(1,0,0); と書き込みます。以上でコーディングが完成したらビルドする前にプロジェクトにコピーしておいたvbusbio.libを登録します。プロジェクト->プロパティ->構成プロパティ->リンカ->入力->追加の依存ファイル右記入欄に vbusbio.lib と書き込みます。以上でVC++でライブラリがリンクされます。OKをおして戻ります。最終コーディングがすんだらビルドを行います。コーディングミスが一番多いです。問題がなければデバッグに実行ファイルが出来ています。後はスタンドアローンでライブラリを使わない設定にすれば実行ファイルが大きくなりますが単体で動く用にもできる様です。設定は割愛します。以上がVC++2008Expressでのvbausbio.dllをつかった制御でした。

Vista上のNETFramework4.0の最新のVisualC++2010Expressにても同プログラムを読み込ませ変換し動かしてみました。マネージデバッグアシスタントによりPinvoke関数 uio_outがスタックを不安定にしています。Pinvokeシグネチャがアンマネージターゲットシグネチャーに一致していないことが原因として考えられます。呼び出し規約、およびPInvokeシグネチャのパラメータがターゲットのアンマネージシグネチャに一致していることを確認してください。のエラーがプログラム起動後の関数uio-out実行時におきた。色々とインターネットでしらべたが、ライブラリ上の関数と呼び出しパラメータ宣言対応が違っている場合等に起きるようだ。ここではCallingConventionの例に従って宣言を以下のようにヘッダー部stdafx.hを書き換えます。

#pragma once 
using namespace System;
using namespace System::Runtime::InteropServices;
[DllImport("vbausbio.dll")]
extern "C" int uio_out(int Port,int OutDat,int p3);
以下省略
上記の宣言変更でPinvokeエラーは発生しなくなります。
VC++2008Expressで作製したプログラムはVC++2010Expressではエラーが起きる可能性がある事が解りました。とにかく実際に動かしてみるのが、問題発見が一番早いです。
また今回のVBAやVBNet等で利用するDLLは問題なく各VC++Express等で参照できることがわかりました。実際にDLLを作る場合の関数宣言を __stdcall と __cdeclで使い分けて参照の場合の確認等も行いましたが、やはり同じ宣言でないと _stdcallの場合は_stdcall,__cdeclの場合は__cdeclでの対応でなければエラーが出ました。重要なのは、オリジナルのヘッダー宣言部であるといえます。今回のvbausbio.dllの場合はC++Builderの参考資料があったためスムーズに行きました。ヘッダーの関数宣言資料がない場合はVB等の宣言から想定してヘッダーを起こすしかなかったと思います。このvbusbio.dllも進化しているようで現在では19関数まで増えているようです。またUSB-IO2.0もバージョンアップしてきて近日発売のようです。いづれにせよ目的のVC++2010,2008でのvbusbio.dllを使ったWindowsフォームサンプルが出来ました。あとは拡張あるのみ、最近はC++にのめりこんでいますが、C++の学習が追い付いていません。Windowsフォームのコントロールの使い方を習得するのも案外時間がかかるものです。特にExpress版でのMFCを利用できない場合のコントロールの動作サンプル作製はネットヘルプが主である為、特に時間がかかる。本も買ってはいるがMFC中心でコードは全く利用できない。まっ地道にやるしか仕方がないか。