あるお客様から
「64bit版アプリから、複数の特電Spartan-6ボードを同時に使用したい。」
というご依頼をいただきました。
複数の特電Spartan-6ボードを開くためのドライバとDLLは、必要とされるお客様に32bit版で提供してきたのですが、どうしても64bit版が必要とのことでした。
WOW64があるから32bit版のDLLでできるのではないかと思っていたのですが、MFCを使うアプリではだめなのですね。きっと。
そこで、「複数のボードを同時に開くDLL」を作ろいとしたのですが、VisualC++でのDLLの作り方を忘れていたため、いろいろとはまりました。
まずは、DLLの作り方を備忘録として書いておきます。
DLLで関数をexportするには、関数の宣言の前に__declspec(dllexport)を付けるか、その関数の名前をDEFファイルに書いておきます。私は__declspec(dllexport)のほうが好きです。
descspecを使う場合は、
__declspec(dllexport) int WINAPI hoge();
のようにして関数を宣言します。
descspecを使わない(DEFファイル)の場合は、
int WINAPI hoge();
のようにします。
WINAPIは、DLLからエクスポートする関数にはこれを付けます。引数が右から順にスタックに詰められるそうです。
DEFファイルを使ってエクスポートする関数を列挙する場合、「DEFファイル」は、
LIBRARY "tkusb"
EXPORTS
USBGetMaxInstance @1
USBGetBoardInfo @2
USBSetBoardUserId @3
USBGetDriverVersion @4
USBGetFirmwareVersion @5
USBReadEEPROM @6
USBWriteEEPROM @7
・・・
のように書きます。@数字は、序数といってDLLの中に入っている関数を示す数字です。
自分の過去のプログラムを見ていて、以下のような書き方をする場合もありました。
LIBRARY "tkusb"
EXPORTS
USBGetMaxInstance@0 = USBGetMaxInstance @1
USBGetBoardInfo@4 = USBGetBoardInfo @2
USBSetBoardUserId@4 = USBSetBoardUserId @3
USBGetDriverVersion@0 = USBGetDriverVersion @4
USBGetFirmwareVersion@0 = USBGetFirmwareVersion @5
USBReadEEPROM@12 = USBReadEEPROM @6
USBWriteEEPROM@12 = USBWriteEEPROM @7
・・・
「関数名@数字 = 関数名 @数字」という形になっていますが、これはBorlandC++で作ったDLLをVisualC++で使うためのインポートライブラリを生成するための書き方です。@数字は、その関数の引数の総バイト数を表すようです。この形式のDEFファイルの書き方でVisualC++でビルドすると、USBGetMaxInstance@0という関数名の関数として扱われてしまうようで、リンクできません。
まぁ、この形式のDEFファイルを作るには人間が引数を数えなければいけないから、ミスも入るでしょう。DLLはVisualC++で作るべきだと思います。
さて、これでDLLを作る準備ができたわけですが、VisualStudop2010 Expressで64bit版のDLLを作る方法は、過去の記事「Visual Studio Expressで64bit版DLLを作成してみる」
http://nahitafu.cocolog-nifty.com/nahitafu/2014/04/visual-studio-e.html
に書いてありました。
過去の記事に書いてあった方法でビルドはできました。しかし、実行すると不正な処理して止まってしまいます。
どうやら、その原因はCyAPIをOpenしていることが原因でした。
64bit版のCyAPIのバージョンが古いためか、
CCyUSBDevice hCyApi= new CCyUSBDevice();
delete hCyApi;
だけで不正な処理をして止まってしまうようです。結局、cyusb.sysとcyapi.dllを使わずに、ezusb.sysベースのデバイスドライバを使うようにしたところ、止まらずに起動できるようになりました。
自分の過去の日記を読んでみると、
「Spartan-6ボードのWindows7 64bit対応」
http://nahitafu.cocolog-nifty.com/nahitafu/2011/02/21/index.html
に書いていたのですが、2011年ごろに一時期EZ-USB FX2LPをCyAPIでアクセスしようとして開発していたけれども、速度の問題などで、結局、古いezusb.sysを64bit版でコンパイルすることにしたようでした。
マルチボード対応のDLLを使ったアプリは、
#include <stdio.h>
#include "tkusb.h"
int main()
{
TKUSB_HANDLE h = USBOpenExByID(0);
printf("Handle = %x\n",h);
if(!h) return 0;
USBSetSmajModeEx(h,0); // Smajモードを解除し、通常動作モードへ
unsigned char buffer[256];
for(int i=0;i<256;i++) buffer[i] = i;
USBWriteDataEx(h,buffer,256,1); // BRAMに256バイト書き込み
memset(buffer,0,256);
USBReadDataEx(h,buffer,256,1); // BRAMから256バイト読み出し
for(int i=0;i<256;i++)
{
printf("%x ",buffer[i]);
}
USBCloseEx(h);
return 0;
}
という感じになります。最初のUSBOpenExByIDという関数の引数を変えると、USBにつながった複数のSpartan-6ボードを開けるという仕組みです。
もちろん、PCにつながっている特電Spartan-6ボードの総数を調べる関数もあり、ボード上のEEPROMに書かれた小さなデータを読み出す機能もあるので、複数のボードを区別して開くこともできるというわけです。
もう数日テストしてみて、問題がなければリリースしたいと思います。
最近のコメント