jl7gmnのblog

yahooブログから移行してきました。アマチュア無線を中心としたブログです。

ソフトウェア

vbausbio.dllをVisual C++2008 その6

イメージ 1

イメージ 2

イメージ 3

夜クーラーをかけていてそのまま寝てしまい朝の1時に目を覚ましてしまった。寝付けないので、確認済みのプログラムをブログアップすることにした。先のVisual C++2010Expressで作成したUSBIOとハムログデータ送受信のVisual C++2008Express版だ。主な違いは先に述べたDLLライブラリのインポート(読み込み)の宣言の違いだけです。他はすべて同じプログラムコードで動きます。この違いをあらためて見てみるとVisual C++2008Expressはすごいと感じています。何がかと言いますと、「ライブラリ名を指定しなくとも目的のライブラリを探して読み込んでくれている。」事です。基本的にはライブラリの存在するフォルダ位置が決まっているから位置はいいとして、ライブラリ数はかなりたくさんあるから、そのなかから定義の関数を探し出していることになります。Visual C++2010Expressはとい言うときちんとライブラリ名を指定しなければなりません。ま私の現状での経験則ですので他の指定しない方法もあるかもしれませんが...上位バージョンだからな~? 指定しない方法わかる方いましたら是非教えてくださいまし。
--------------------------------------------------------------------------------
【FindWindowの例】
☆☆☆ VisualC++2008Express ☆☆☆
extern System::IntPtr __declspec(dllimport) __cdecl FindWindow(unsigned char class Name,unsigned char wndName);

☆☆☆ VisualC++2010Express ☆☆☆
[DllImport("user32.dll")]
extern System::IntPtr FindWindow(String^ className,String^ wndName);
--------------------------------------------------------------------------------
VisualC++2008Expressでも問題なく動きます。マネージドとアンマネージドの混合プログラムはいろいろと大変な変換処理が付きまとう事のほうが少し厄介な気がしています。Frameworkライブラリだけでのプログラムはやりたいことをこのライブラリだけでコーディングするのは実際難しいかも??私の感想です。
時間も3時を回ったので、一応また寝ます。おわり

vbausbio.dllをVisual C++2008 その5

イメージ 1

イメージ 2

イメージ 3

ブログの記事作成は少し間が空いたが、これはいろいろと調べたり、本屋でVISUAL C++2008の本を買ったりコーディングしたり無線をしたりと忙しかったからです。今回はハムログのデータの読み込みをVisual C++2010Expressで行いました。今回は少し厄介で型変換でのエラーに時間を食ってしまいました。ただこれはハムログのデータ読み込みとはあまり関係なく私の興味でWindowsのAPIでの情報取得についてどうしてもクリアしておきたかった内容だったのでトライしました。それはAPIでのウィンドウのキャプションの読み込みをSendMessageでWM_GETTEXT,WM_GETTEXTLENGTH,のウィンドウメッセージを用いFindWindowW,でHWNDを入手し文字情報を得るということです。インターネットを探すと意外といろいろとありそうですが、Visual C++2010Expressとなると、これがまたきちんと動くサンプルがありません。特に今回はchar型の配列として char tex[255];を用いこれにウィンドゥメッセージを入れるところまでは案外問題ありませんでした。ところがこの配列にはウィンドゥメッセージが入ったのはいいのですが、入り方が以下のように入ったため通常のchar型からString型への変更はうまくいきません。
データのウィンドウキャプションは"Visual C++2010Express USBIO " です。
【データの状況】
tex[0]='V',tex[1]='',tex[2]='i',tex[3]='',tex[4]='s'...............
値としては 86,0,105,0,115,.........で一つおきにデータが入っています。このために通常の型変換では2配列目のtex[1]の値が0のため 'V'の文字のみしか文字列として変換されません。これは他の一般的なchar型->String変換をやってみましたがどれも1文字だけしか取り込みすることができませんでした。しかしMSDNの型変換の中のMarshal::PtrToStrinigUniメソッド(IntPtr)で次のうたい文句をためすべく(マネージStringを割り当て、アンマネージUnicode文字列から最初のnull文字に遭遇するまでの文字をすべてコピーします。)やったところすべて変換できました。ここにたどり着くまでが長かったです。インターネット上では私はこの変換を見つけることはできませんでした。似たようなMarshal::PtrToStrinigAnsiはありましたがこれも一文字のみしか変換できませんでした。あとはこのキャプションの文字長を得るためのWM_GETTEXTLENGTHでの場合ですが、式としては、私はbool型かと思っていました。そのため 式をbool としていました。

bool reham; //NG例 
reham=::SendMessage(hundle,WM_GETTEXTLENGTH,wParam,lParam);

ところが、文字長はbool型では入手できません。これを int型にかえてやることで、戻り値が文字長として入り取得する事ができるようになります。以下のように直しました。
後先になりましたが、hundle はGetActiveWindow()で入手します。当初配列に入るものだと思っていましたので、char配列をとってありますが、データは入りませんが、そのままにしてあります。
rehamはint型のグローバル変数としてトップに宣言しておきます。

【例】
int reham;

hundle=GetActiveWindow();
char nagasa[255];
wParam = (WPARAM)255;
lParam = (LPARAM)&nagasa;
reham=::SendMessage(hundle,WM_GETTEXTLENGTH,wParam,lParam);
textBox13->Text=reham.ToString();
値は通常のint型をToString()変換でテキストボックスに文字として表示してます。以上でAPIはうまくいきました。本題のハムログのデータの取り込みですが、これはハムログの仕様が重要です。OMのJG1MOU 浜田氏のHamlogMs.txtに書いてある内容が重要です。以下抜粋:読み取りの場合はハムログ内では(cbData==0)または(lpData==NULL)で呼び出された場合、呼び出し側アプリのSendMessage()の第3引数のハンドルに文字列を返送する。cbData と lpDataがセットされて呼び出された場合、ハムログ内部ではFindWindowにより見つけたハンドルに文字列を返送する。という2方法がかかれています。
上記を踏まえてプログラム上でハムログのハンドルと自分のプログラムのハンドルを求めます。先のhundleも自分のプログラムのハンドルとして使えます。ただ注意しなければならないのは、開発途中でのハンドルはウィンドゥズが勝手に作っており時々、続行F5で走らせていると、ハンドルが違う事があります。つまり固定ハンドルとしては基本的に使えないということです。コンパイルしてしまえば問題はないようです。開発途中では動かないことがあるわけです。このため対策を採ります。ハンドルを取り込む部分はキャプション情報を使います。タイトルは変わることはありませんのでこの方法でハンドルを入手します。GetActiveWindow()は確かにいつもアクティブかはわからないので少し不安です。
【ハンドル入手対策】
Hwnd8=::FindWindowW(NULL,(LPCWSTR)_T("Visual C++2010Express USBIO "));
自分のプログラムのタイトル(キャプション)は自分で変更しない限り変わりません。
この方法で毎回問題なく自分のプログラムの側のハンドルが入手できます。
ハムログ側のハンドルは先のハムログへデータ送出と同じです。以下のとおりです。
Hwnd1=::FindWindow((LPCTSTR)_T("TThwin"),NULL);

相手と自分のハンドルが求まったので入手するコマンドを構造体のcdsに設定します。
~省略
int kite1=0;
char buffs[255];
HWND Hwnd1,Hwnd8,hundle;
WPARAM wParam;
LPARAM lParam;
COPYDATASTRUCT cds;

Hwnd1=::FindWindow((LPCTSTR)_T("TThwin"),NULL);
kite1=::FindWindow((LPCTSTR)_T("TThwin"),NULL);
if(kite1 != true){
textBox9->Text="Hamlog Not Active";
}
else{
textBox9->Text="Hamlog Active";
}
Hwnd8=::FindWindow(NULL,(LPCWSTR)_T("Visual C++2010Express USBIO "));
cds.dwData=101 //コールサインを取り込む場合101
strcpy_s(buffs,""); //NULLでなく ""でないとエラーがでる.strcpyもこれstrcpy_s
cds.cbData=0; //ハムログの仕様どおりに設定
cds.lpData=NULL; //同上

wParam = (WPARAM)Hwnd8; //自分のプログラムのハンドルを設定します。
lParam = (LPARAM)&cds; //データを設定した構造体のポインタを設定
::SendMessage(Hwnd1,WM_COPYDATA,wParam,lParam);
kite=::SetForegroundWindow(Hwnd1);

以上がハムログからデータを取得する心臓部です。あとはコールバックでのWM_COPYDATAメッセージを受け取った時にハムログが返送してくるデータを受け取るということになります。
画像でのせましたので参考にしてください。コールバックでの重要なところは最初の一行です。これもVisual C++2010Expressとしての例はなかなか見つかりませんでした。
ToInt32()での変換が必要です。以下のようにしないとデータを取り込めません。
COPYDATASTRUCT *pcds = (COPYDATASTRUCT*)m.LParam.ToInt32();
後は取り込み後のIntPtrからStringAnsiでの変換です。ウィンドゥのキャプションと違いハムログからのデータは問題ないのでこの型変換で行います。
textBox12->Text=Marshal::PtrToStringAnsi((IntPtr)pcds->lpData,pcds->cbData);

以上でフォーム上のテキストボックスに取り込んだ値がゲットできています。しかし型変換が一番大変なエラー数を出す感じがしていますが、型をあわせる事を念頭にプログラムすれば何とかできそうです。実際のプログラムではニューメリックコントロールをコマンド番号の101から117までを指定して、タイマーコントロールをつけて番号を変えたイベントで取り込みを2秒毎に行えるようにしています。AUTO ON (タイマー起動)とAUTO OFF(タイマー停止)をつけています。通常はボタンのData Receiveを押すことでコマンド番号に対するハムログのLOG-[A]上の対応データが取り込まれます。画像はコマンド115
での全データ入手画面です。しかしVisual C++2010Expressを使ってハムログのデータを取り込んだりしている人はいないです?。なさそうなのでハムログでのVisual C++2010Expressのサンプルとして出した次第です。でもVC++2010Expressは大変ですが、動いたらしめたものです。後は応用がききます。今回は特にWindowsのシステムの構成がWMメッセージで事細かに動作していることが理解できました。まとめるとWindowsはすべてメッセージで動いています。Windowsは忙しいシステムだ!が私の感想です。

vbausbio.dllをVisual C++2008 その4

イメージ 1

イメージ 2

イメージ 3

イメージ 4

USBIOのハード制御はひとまずアイデア待ちで小休止ですが、Visual C++2010Expressを用いたハムログへのデータ送出をやって見た。いままではVisualC++2008Expressでのプログラムコーディングが主としていたが、今回から方針を変えた。というのは、VC++2008Expressの入っているPCがとても遅くなってきたため、Vista に入れてあるVisualC++2010Expressを使うことにしました。画面もワイドなのでインターネットを検索しながらコーディングできる為好都合です。ということで今回からVisualC++2010Expressでのプログラミングということになります。もちろんVisualC++2008Expressも動作の確認、書き換え等の対処は行います。私の作業はWindowsXpがメインですから!。
VisualBasic 2008Expressではすでにハムログへのデータ送出関連はすべてできているから変数値の確認はVBを利用できるので安心だ。とにかくWindowsAPIなるものを使用して行うわけだが、やはりVisualC++2010ExpressのC++/CLIでの実際の利用例がないに等しい。もちろんマイクロソフトのホームページにはMSDNライブラリがある。これはやはりサンプルコードがあるが実際の例として使うには少しわかりずらい。何度本屋へ行って専門書を調べようかと思ったことか。今回悩んだのは対象Windowsフォームからハンドル取得のUser32ライブラリのFindWindows関数の引数の設定である。インターネットで調べたVC++2010での関数引数例をそのまま利用すると見事にすべてエラーが発生する。まず第一に宣言している内容がMSDNライブラリでは以下のようにかかれている.MFCの例だがAPIも踏襲されているので仕様はほぼ同じだ(似ている。?)
--------------------------------------------------------------------------------
static CWnd* PASCAL FindWindow(
LPCTSTR lpszClassName,
LPCTSTR lpszWindowName
);
パラメーター
lpszClassName
ウィンドウのクラス名 (WNDCLASS 構造体) を示す NULL で終わる文字列へのポインター。 lpClassName が NULL のときは、すべてのクラス名が一致します。

lpszWindowName
ウィンドウ名 (ウィンドウのタイトル) を示す NULL で終わる文字列へのポインター。 lpWindowName が NULL のときは、すべてのウィンドウ名が一致します。
---------------------------------------------------------------------------------
このパラメータがインターネットの大概のサンプルでは第1パラメータと第2パラメータが逆になっているのだ。これは本当に困る。そのまま信じてコーディングするとエラーから抜け出せなくなる可能性が大である。MSDNライブラリできちんと第1パラメータはウィンドウのクラス名、第2パラメータはウィンドウ名(ウィンドウのタイトル)と記載されてる。今回はこのクラス名を調べるプログラムを利用してハムログのクラス名を確認して行った。VB2008Expressではハムログのクラス名は’TThwin'とJG1MOU浜田OMの資料HamlogMs.txt上に記載されているので、そのまま使用できる。これは作者でないとわからないわけだが、さきのクラス名を調べるプログラムは大変ありがたい。いろいろとあるようだが、私が使ったのはwinmap.exeというエクスプローラ風のアプリケーションです。これでハムログのクラスが間違いなく’TThwin'であることが確認できました。またパラメータの記載の方法もインターネット上の資料には正確に記載しているものが、ごくわずかでした。クラス名の第1パラメータへの記載の実際は
VC++2010Expressの例としてのNG例とOK例を以下に記します。実際にOK例はすべて確認済みです。
-------------------------------------------------------------------
[NG例]
Hwnd1=FindWindow(("TThwin"),NULL);
[OK例]
Hwnd1=::FindWindow((LPCTSTR)_T("TThwin"),NULL);
Hwnd1=FindWindow((LPCTSTR)_T("TThwin"),NULL);
Hwnd1=::FindWindow(_T("TThwin"),NULL);
-------------------------------------------------------------------
以上のとおりまず関数前の”::”がVisualC++2010Expressでは要るらしいが、なくてもコンパイルは通るようです。
またクラス名のパラメータ指定をマクロの"_T"で指定することである。(LPCTSTR)はあってもなくてもよいようです。ハムログのデータ送出で使う他関数についてはサンプルを(詳細は省略)以下に記します。また実際コードは画像を参考にしてください。
-------------------------------------------------------------------
『SendMessage関数』
::SendMessage(Hwnd2,WM_COPYDATA,wParam, lParam);
『SendMessage関数』
bool kite=0;
kite=::SetForegroundWindow(Hwnd2);
-------------------------------------------------------------------
ボタンをひとつ用意してボタンを押すとハムログのCALLのテキストにあらかじめ用意したデータのコールサインが送られるサンプルです。CALLを指定するデータはSendMessage関数のパラメータにlParamとして送られます。送出されると次の日付にフォーカスが移り終了します。これもSendMessage関数で任意の位置へカーソルを動かす指定をしてリターンコードを送るようにすれば自在にカーソルフォーカス位置の制御が可能です。VBでは自動でPCの日付を入れてコールサインへフォーカス指定の制御をしていました。
コマンドボタンでのハムログ入力ダイアログへのデータ送出がVC++/CLIで可能となりました。ついでにこの送出部を汎用性を持たせるべく関数化(戻り値なし)しました。
--------------------------------------------------------------------
『ヘッダー部での宣言』
void hamlogTX_datvc2010(int dcode,char hamdat[256]);
『プログラム上での関数の使用(ボタン内のコード)』
int dcode=1;
char hamdat[]="HAMLOG ";
hamlogTX_datvc2010(dcode,hamdat);

dcode=2;
char hamdat1[]="11/11/11";
strcpy_s(hamdat,hamdat1);
hamlogTX_datvc2010(dcode,hamdat);
--------------------------------------------------------------------
上はコールサインの場所にコマンド1を指定して"HAMLOG"データをセットしhamlogTX_datvc2010関数を指定します。同じルーチンで複数個所のデータを送る場合はデータはConstですので、別配列をそれぞれつくってそれにデータを入れそれを規定の配列にstrcpy_sでコピーしてhamlogTX_datvc2010関数を指定します。上はコールサインと日付が関数を利用してデータ送付される例です。
関数化すると本当に楽になります。関数の利用はdcodeにはハムログ入力ダイアログの送出場所指定番号、hamdatには送出文字データをセットして関数を指定します。
ここで注意することは、charの指定です。配列は[256]を予約していますが、最初のデータが入ったときにhamdatが自動にて入れたデータ文字数が予約されてしまいます。ですので、最初のデーターは文字データ数の最大を予想してスペースをデータとして入れてあります。そうしないと最初の文字データ+内部コード(改行等)の文字数よりデータ数が多いものを送るとエラーとなります。このブログ上では空白部が削除されてしまっています。"HAMLOG**************************************************";*はわかるように空白がわりに書き換えしました。実際は空白です。
またVISUALC++2008ExpressではUSER32.DLLの関数の宣言が異なりました。FindWindowの例を下記します。
---------------------------------------------------------------------
『VC++Express2010宣言』
[DllImport("user32.dll")]
extern System::IntPtr FindWindow(String^ className, String^ wndName);
『VC++Express2008宣言』
extern System::IntPtr __declspec(dllimport) __cdecl FindWindow(unsigned char className,unsigned char wndName);
---------------------------------------------------------------------
他インクルードヘッダーとして以下を使いましたので追加してます。
#include <tchar.h> // '_T'識別子用
#include <windows.h> // strcpy_s,strlen,他各定義用(HWND,LPARAM,........)
いつも思うのだが、このVisualC++2010Expressもそうだが、資料の公開があまりにもされていないので普及していないのだと思う、動くサンプルがユーザーを増やすのだがこれが少ないためユーザーが少ない。とにかく簡単なサンプルからはじめるのが一番良いと思っています。
 以上今回の作業は終了!。次はハムログからのデータ読み取りを行いたいですが、これまた大変そうであるので、まずは、UUSBIOのLEDの点滅の制御とか、現在のハムログの2重起動防止などの細かいところをやって見ようかしらん!?ステップバイステップ!! つづく

vbausbio.dllをVisual C++2008 その3

イメージ 1

イメージ 2

C++/CLIのプログラムはコントロールを使ってプログラミングしている限りVBやVCとあまり違いがないのがとても嬉しい。今回は以前作成したVBでのハムログ制御のVC++版をやってみようとおもっている。色々と制御以外のC++特有の処理とかが必要となるだろうけれどもまずはトライの精神で臨みます。プログラムも追加追加での対応なので、段々と拡張していき、フォームが大きくなっていきます。画面に収まっている時点では追加体制で、ある程度、機能がそろった時点で、新たに専用プログラム化することを一応目標としました。何かしらの目標がないと続かないと思って、まずは次のステップということで、アプリケーションの起動をプログラムで行います。もちろん対象のアプリケーションは、かの有名なハムログWINです。まずは買ってきてあるかんたんVC++のあらすじ読みてきなシェル系の目次をサーチし、次にインターネットでの検索サーチ、次から次とそれらしき資料が出てくるは、出てくるは、試してみるとエラーが出る。こんなことの繰り返しである。ところが、すばらしいネットの参考ブログかあった。今は伏せておくが、ヒントとして「IT.***」である。案外かゆいところへ手が届いていて私の性格にすんなりあった読みやすいし動作も間違いがないとてもすばらしいブログであると思う。とにかく検索すればすぐわかると思う。とにかく使えるサンプルがたくさんあるところが一番である。まずはさておいて、実際のアプリケーションを起動するプログラムコードは、Processを用いたものです。まずはそのセンテンスを以下に書きます。ハムログ起動のコマンドボタンのコードの中に書きます。
なお対象OSはWindowsXPを実使用予定でいますので、Visual C++2008Expressエディション(NetFramework3.5)が主となります。使用PC依存によります。Visual C++2010Expressエディション(NetFramework4.0)は使いません。ただし後で時間があれば試したいと思っています。(2010での他のNetFrameworkの選択は可能ですが...)
【ハムログ起動プログラム】
名前空間を記述します。(ヘッダー宣言部)
using namespace System::Diagnostics;

private: System::Void button11_Click(System::Object^ sender, System::EventArgs^ e) {
Process^ ps = gcnew Process();
ps->StartInfo->FileName = "Hamlogw.exe";
ps->StartInfo->WorkingDirectory = "C:\\Program Files\\HAMLOG2011-1";
ps->EnableRaisingEvents=true;
textBox6->Text="Hamlogw.exe ACTIVE!";
bool bSuccess;
bSuccess = ps->Start();
while (!ps->HasExited)
{
  Application::DoEvents();
}
textBox6->Text="Hamlogw.exe finish";
}

【起動プログラム説明】
psをマネージドタイプでインスタンス化します。
ProcessStartInfoクラスを使用してFileNameプロパティでアプリを指定します。
同様にWorkingDirectoryプロパティでハムログのあるパスを指定します。
ここで注意しなければならないのが、私も間違えてエラーを最初だしてしまいましたが、階層の記号「¥」を一つしか書かないとエラーが出ます。「\」は2つ必要です。
ProcessEnableRasingEventsをtrueに設定してプロセスが終了したときにイベントを発生させる設定をします。
ProcessStartでアプリケーションを起動します。
プロセスの起動状態はHasExitedプロパティで判断します。詳しい説明は先のブログにありますので確認してみてください。以上がプログラムでアプリケーションを起動するコードですが、起動したら、次はアプリを止める方法です。

【ハムログ強制終了プログラム】
private: System::Void button12_Click(System::Object^ sender, System::EventArgs^ e) {
//アプリケーションの強制終了
  array<Process^>^ ps = Process::GetProcessesByName("Hamlogw");
  for each (Process^ item in ps)
  {
   item->Kill();
  }
}

【強制終了プログラム説明】
これはこういうものだということでおまじない的にそのまま使います。
プロセスの名前を指定してそれをkillで強制終了させます。
以上で起動ボタンでハムログが立ち上がります。起動した画像も載せました。この状態でフォーム上からのUSBIOコントロールもハムログも問題なく動作しています。
ついでなのでフォーム上に時計をフォーム読み込み時に表示させました。私の作業時間が何時頃かがわかります。案外深夜から朝方が多いかも。今日のステップは終了します。次はなににしようかしらん!

vbausbio.dllをVisual C++2008,2010で使う

イメージ 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中心でコードは全く利用できない。まっ地道にやるしか仕方がないか。
アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

QRコード
QRコード
  • ライブドアブログ