とある機器のOCXからの関数での変数の扱いがわからないのでお助けください。
function AXSensor1.GetFInfo(var pSRInfo: OleVariant):integer;
取り込んだActiveX内に上記の関数が有り、変数OleVariantにDATAが入るのですが
そして、このOleVariantに入れたデータをDBに格納して管理をしたいのですが
OleVariantをByteに変換?扱いが分からなくて・・・
サンプルがVB.netとVC.net系しか無く
参考にして、色々と数日間 調べたり試したりしてるのですが
未熟すぎて、どうしても解決できません・・・
ご指南のほど宜しくお願いいたします。
↓↓↓ 取り込んだOCXをFormに張り付けた イベントです
//OLE ActiveX
procedure AXSensor1OnEventMsg(ASender: TObject; wParam, lParam: Integer);
var
pBy_Info: OLEVariant;
dwErrID: LongInt;
begin
ErrID := AXSensor1.GetFInfo(pBy_Info);
pBy_Info; // この中身をDBに保存したい。
// この中身をByte型? に変更して?DBにBLOBで保存?
//
//
end;
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
//VBサンプル
Private Sub AXSensor_OnEventMsg(ByVal sender As System.Object, ByVal e As AxSREXFSUXAXLib._DSRexFSUxAXEvents_OnEventMsgEvent) Handles AXSensor.OnEventMsg
Dim pBy_Info() As Byte
Dim dwErrID As Long
' センサー情報データ 1048Byte
ReDim SRexInfo(1048)
' センサー情報取得
dwErrID = AXSensor1.GetFInfo(pBy_Info)
環境
Windows7
Delphi XE Ent
本当に宜しくお願いいたします。
すいません、 記載ミスです
記載ミスがありました
VBサンプル
'× センサー情報データ 1048Byte
ReDim SRexInfo(1048)
'○ センサー情報データ 1048Byte
ReDim pBy_Info(1048)
指南できるほどの知識はありませんので、想像でアドバイスします。間違ってるかもしれません。
> ErrID := AXSensor1.GetFInfo(pBy_Info);
これ、ErrIDの中身でエラー出てないんですか? エラー出てないとすると…バリアント配列を入れて返してる?
VBに倣うなら、最初にこうするのだと思います。これでByteの配列と同様に扱えないでしょうか。
pBy_Info:=VarArrayCreate([0, 1047], varByte);
DBについては知らないので分かりません。
まずヘルプでVarArrayCreateを見た方が良いです。
VarArrayRedimとか、高速アクセス用の?VarArrayLock/VarArrayUnlockもありますね。
カテゴリ別で「バリアントサポートルーチン」、アルファベット順で「V」→ Var… の項目をよく眺めるのも吉。
Harry様 ありがとうございます。
エラーもでないし、中身は正しく入ってようなのですが
Byte扱い出来ず、「V]の項目も色々ためしてみてるのですが
使い方がが間違ってるのか、どれもうまくできず
VC6のサンプルを見ると(DLL版)実際?の中身みたいなのには
typedef struct _PBy_Info{
BYTE Minutiae[1024]; // データ格納バッファ 1024Byte
long lengthMinutiae; // データサイズ
long nMinutiae; // データの特徴数
long Quality; // 特徴点の品質
BYTE DeviceName[8]; // デバイス名
WORD DllMajor; // DLL MaVersion
WORD DllMinor; // DLL MiVersion
} By_Info, *PBy_Info;
DllImport DWORD APIENTRY GetFInfo(By_Info pBy_Info );
こんな感じな様なのですが、すべてVBとかはByteで扱てるのか?
とりあえず、OleVariantの中身をバラしてDBに格納する方法にたどり
着きたいのですが、OleVariantがどうしても理解できません。
宜しくお願いいたします。
ですが、レコード型を定義して、そのポインタをGetFInfoの引数に渡してやれば取れるんじゃ?
編集 削除http://docwiki.embarcadero.com/Libraries/XE2/ja/System.OleVariant
によると、「格納されているデータ型は、相手がデータの扱い方を知っているかどうかを気にせずにプログラム間またはネットワーク経由で渡すことができるということです。」
と書かれているので、OLEVariantを_PBy_Infoでキャストして取り扱ってもおkだと思います。
当てずっぽう様 ありがとうございます。
レコード型を定義して、ポインタにして引数に渡そうとするのですが
OleVariantしか受け付けてくれず・・・
PBy_Infoをキャストしたいのですが、そのキャスト方法がわかりません。
技量が無いので、辿りつけないだけかと思うのですが、何かほかにヒントを
ご存じであれば宜しくお願いいたします。
当てずっぽう さん
>OLEVariantを_PBy_Infoでキャストして取り扱ってもおkだと思います。
いくらなんでもそれはあり得ないです。↓こちらを参照。
Delphi 言語ガイド - メモリ管理 - 内部データ形式(Delphi) - バリアント型
http://docwiki.embarcadero.com/RADStudio/XE5/ja/%E5%86%85%E9%83%A8%E3%83%87%E3%83%BC%E3%82%BF%E5%BD%A2%E5%BC%8F#.E3.83.90.E3.83.AA.E3.82.A2.E3.83.B3.E3.83.88.E5.9E.8B
>32 ビット プラットフォームでは、バリアントは、コードで決められた型の型コードと値(または値への参照)を含む 16 バイト レコードとして格納されます。
Mojicさん
>エラーもでないし、中身は正しく入ってようなのですが
先にも述べましたが、ErrIDの値が気になります。また、中身が正しく入ってると思う理由は何でしょう?
>Byte扱い出来ず、「V]の項目も色々ためしてみてるのですが
ほぼ普通の配列として扱い、値を取り出すときに整数型の変数に入れるかキャストするだけですよ。
pBy_Info:=VarArrayCreate([0, 1047], varByte);
これ↑も試しましたか?
>使い方がが間違ってるのか、どれもうまくできず
(試した数だけ、詳細に)何をやってどうなったか?を伝えてください。お願いします。
エラーが出た場合、メッセージはCtrl+Cで取得できるので、それを提示してください。
>VC6のサンプルを見ると(DLL版)実際?の中身みたいなのには
>typedef struct _PBy_Info{
(以下略)
このBy_Info構造体は、1024+4×3+8+2×2=1048byte となるので、Dimと一致しますね。
>こんな感じな様なのですが、すべてVBとかはByteで扱てるのか?
少なくとも、データを受け取る部分に関してはそうなのでしょう。
そこから先はVBのサンプルコードを見ていけば良いのではと思いますが、どうなってますか?
また、VC6のサンプルはDLLを直に使っているようですが、それと同様にしてはいけないのですか?
------------------------------------------------------------------------------------
フォームにTButtonを2個、TMemoを1個置き、以下のコードで確認してみてください。
・ ボタン1 はバリアントの配列を作らず、いきなりGetFInfoに与えてみます。
・ ボタン2 はVBのようにバリアントの配列を作ってから、GetFInfoに渡します。
結果をお知らせ下さい。(バイナリダンプの部分はほどほどで結構です。)
implementation
{$R *.dfm}
(*
typedef struct _PBy_Info{
BYTE Minutiae[1024]; // データ格納バッファ 1024Byte
long lengthMinutiae; // データサイズ
long nMinutiae; // データの特徴数
long Quality; // 特徴点の品質
BYTE DeviceName[8]; // デバイス名
WORD DllMajor; // DLL MaVersion
WORD DllMinor; // DLL MiVersion
}By_Info, *PBy_Info;
*)
type
long = Longint;
PBy_Info = ^TBy_Info;
TBy_Info = packed record
Minutiae: array[0..1023] of BYTE; // データ格納バッファ 1024Byte
lengthMinutiae: long; // データサイズ
nMinutiae: long; // データの特徴数
Quality: long; // 特徴点の品質
DeviceName: array[0..7] of BYTE; // デバイス名
DllMajor: WORD; // DLL MaVersion
DllMinor: WORD; // DLL MiVersion
end;
procedure TestRecord(AVariant: Variant; AStrings: TStrings);
var
By_Info: PBy_Info;
L, H: Integer;
Str: AnsiString;
I: Integer;
begin
AStrings.Add('');
AStrings.Add('レコード型として調べてみる');
AStrings.Add(StringOfChar('-', 44));
By_Info:=VarArrayLock(AVariant); // バリアント配列のポインタを取得、ロック
L:=Low(By_Info.Minutiae);
H:=High(By_Info.Minutiae);
AStrings.Add(Format('Minutiae: %dbyte', [Length(By_Info.Minutiae)]));
for I:=L to H do begin
Str:=Str+Format('%.2x',[By_Info.Minutiae[I]]);
if ((I-L+1) mod 16)=0 then begin
AStrings.Add(Str);
Str:='';
end else begin
Str:=Str+' ';
end;
end;
if Str<>'' then AStrings.Add(Str);
AStrings.Add(Format('lengthMinutiae: %d', [By_Info.lengthMinutiae]));
AStrings.Add(Format('nMinutiae: %d', [By_Info.nMinutiae]));
AStrings.Add(Format('Quality: %d', [By_Info.Quality]));
SetLength(Str, SizeOf(By_Info.DeviceName));
Str:=StrMove(PAnsiChar(Str), PAnsiChar(@By_Info.DeviceName), SizeOf(By_Info.DeviceName));
AStrings.Add(Format('DeviceName: "%s", Length=%d', [Str, Length(Str)]));
AStrings.Add(Format('DllMajor: %d', [By_Info.DllMajor]));
AStrings.Add(Format('DllMinor: %d', [By_Info.DllMinor]));
VarArrayUnlock(AVariant); // ロック解除
end;
procedure TestVariantArray(AVariant: Variant; AStrings: TStrings);
var
L, H: Integer;
Str: String;
I: Integer;
begin
if VarIsArray(AVariant) then begin
L:=VarArrayLowBound(AVariant, 1);
H:=VarArrayHighBound(AVariant, 1);
AStrings.Add(Format('バリアント配列です。要素数: %d、下: %d、上: %d',[H-L+1, L, H]));
if (VarType(AVariant) and varTypeMask)=varByte then begin // 配列かどうかに関わらず型を判定
AStrings.Add('その型は、Byte型です。');
AStrings.Add(Format('生データ: %dbyte', [H-L+1]));
Str:='';
for I:=L to H do begin
Str:=Str+Format('%.2x',[Byte(AVariant[I])]);
if ((I-L+1) mod 16)=0 then begin
AStrings.Add(Str);
Str:='';
end else begin
Str:=Str+' ';
end;
end;
if Str<>'' then AStrings.Add(Str);
TestRecord(AVariant, AStrings); // Byte型の配列だったら、レコード型にして調べてみる
end else begin
AStrings.Add('その型は、Byte型ではありません。');
end;
end else begin
AStrings.Add('バリアント配列ではありません。');
end;
end;
// いきなりGetFInfoに突っ込んでみる場合
procedure TForm1.Button1Click(Sender: TObject);
var
V1: OLEVariant;
ErrID: Integer;
begin
Memo1.Clear;
V1:=Unassigned; // varEmptyにしておく
ErrID:=AXSensor1.GetFInfo(V1);
Memo1.Lines.Add(Format('ErrID: %d, V1: %s', [ErrID, VarTypeAsText(VarType(V1))]));
TestVariantArray(V1, Memo1.Lines);
end;
// Variantの配列を作ってからGetFInfoに渡してみる場合
procedure TForm1.Button2Click(Sender: TObject);
var
V2: OLEVariant;
ErrID: Integer;
begin
Memo1.Clear;
V2:=VarArrayCreate([0, 1047], varByte);
ErrID:=AXSensor1.GetFInfo(V2);
Memo1.Lines.Add(Format('ErrID: %d, V2: %s', [ErrID, VarTypeAsText(VarType(V2))]));
TestVariantArray(V2, Memo1.Lines);
end;
Harry 様 本当に本当にありがとうございます。
ソースまでご丁寧ねお付け頂き、初心者には本当に感謝です。
で、頂いたソースを組み込んでみたのですが・・・
<FONT COLOR="#CC8000"><b>「 TestVariantArray(V1, Memo1.Lines); 」</b></FONT>ここで (V2)も
*バリアントタイプが不正です* となり TestVariantArrayに
送れません、TestVariantArrayにもブレークポイント設定するのですが
この関数に来る前に、エラーになってるようでダメでした。
※ダメもとでTestVariantArrayのAVariantにOleVariantとしてもダメでした
とりあえず、手前のMemo1へのVarTypeAsTextの結果は次の通りです。
<FONT COLOR="#CC8000"><b>「 ErrID: 0, V2: ByRef Array $0BE0 」</b></FONT>
ErrID=0以外はNGです。 $0BE0の部分は、毎回変わっています。
<FONT COLOR="#CC8000"><b>>>エラーもでないし、中身は正しく入ってようなのですが</b></FONT>
<FONT COLOR="#CC8000"><b>>先にも述べましたが、ErrIDの値が気になります。また、中身が正しく入ってると思う理由は何でしょう?</b></FONT>
とある機器とは指紋認証装置なのですが、CompFInfo(SLevel:Byte; pBy_Info1, pBy_Info2: OleVarinat):Integer (compare比較)があるので
この関数に同じ指だとOK 違う指だとNGとなり、正しく情報は入ってると思っています。
DLLを直接使おうとも思ってたのですが、DLLを呼び出して関数みたいに使うのは
出来るのですが、DLLからの呼び出しのEventの追記が出来ず、OCXを使う方法だと
そのままActiveXコンポーネントのイベントが仕えるので(未熟なので手抜きです)
※サンプル関数を呼んで、機器で指を認証すると、発生するイベントがあります
それで、GetFinfoでOleVariantにもらってきています。
宜しくお願いいたします。
とりあえずいくつか。
なんかHTMLタグが混入してますが、これはMojicさんの仕業ですか? めっちゃ見にくいです。
タグは使用できませんのでよろしく。
>「 ErrID: 0, V2: ByRef Array $0BE0 」
>ErrID=0以外はNGです。 $0BE0の部分は、毎回変わっています。
ErrIDは常に0ということですね?
$0BE0の部分が毎回変わるなら、そこだけ最低10回分くらいは下さい。(謎なので。)
V1の方はどうなりましたか? 書いてもらわないと分かりません。
こうなるとやはりVBのサンプルにおける記述がキーになるかも?しれません。
> dwErrID = AXSensor1.GetFInfo(pBy_Info)
この後、pBy_Infoはどのようなことをされてますか?
具体的なコードがあると分かりやすいです。
OCXの関数などの仕様書は無いのでしょうか。返されるバリアントに関することです。
また、取り込んだタイプライブラリのユニットに定義されている内容がヒントになるかも知れません。
DLLについては了解しました。確かに難しいかも知れませんね。
でも、MSDN程度の資料が公開されていれば可能性はあるとも思います。そこはどうなってますか?
あとこれ、お仕事ですか?
Harry 様 ありがとうございます。
HTMLの犯人は私です・・・汗;
ErrIDは、正しくサンプリング(指を正しく滑らせれば)毎回0が返りますが
雑に指をこすると、0以外になります。
☆は何故か2回エラーが出ます「EVariantBadVarTypeError」
IDEで起動した時とエクスプローラからと結果が違う
サンプリング時のエラー (V1)同じ指
<IDEのDeBUGで実行>
ErrID: 0, V1: ByRef Array $0100 ☆
ErrID: 0, V1: ByRef Array $0CF0 ☆
ErrID: 0, V1: $0C00
ErrID: 0, V1: ByRef Array $0E60 ☆
ErrID: 0, V1: ByRef $0100
ErrID: 0, V1: ByRef $07D8
ErrID: 0, V1: ByRef $0ED0
ErrID: 0, V1: ByRef $05B0
ErrID: 0, V1: ByRef $0040
<コンパイル済みDeBUGを直接>
ErrID: 0, V1: ByRef $0830
ErrID: 0, V1: ByRef $0890
ErrID: 0, V1: ByRef $08C0
ErrID: 0, V1: ByRef $08F0
ErrID: 0, V1: ByRef $0920
ErrID: 0, V1: ByRef $0950
ErrID: 0, V1: ByRef $0980
ErrID: 0, V1: ByRef $09B0
ErrID: 0, V1: ByRef $09E0
ErrID: 0, V1: ByRef $0A10
ErrID: 0, V1: ByRef $0A40
サンプリング時のエラー (V2)同じ指
<IDEのDeBUGで実行>
ErrID: 0, V2: OleStr
ErrID: 0, V2: $0048
ErrID: 0, V2: ByRef $0528
ErrID: 0, V2: $0150
ErrID: 0, V2: Array $0A60 ☆
ErrID: 0, V2: $0630
ErrID: 0, V2: Array $0980 ☆
ErrID: 0, V2: Array $0A00 ☆
ErrID: 0, V2: $0708
ErrID: 0, V2: ByRef $08D8
ErrID: 0, V2: $04F8
<コンパイル済みDeBUGを直接>
ErrID: 0, V2: ByRef $0890
ErrID: 0, V2: ByRef $08F0
ErrID: 0, V2: ByRef $0950
ErrID: 0, V2: ByRef $09B0
ErrID: 0, V2: ByRef $0A10
ErrID: 0, V2: ByRef $0A70
ErrID: 0, V2: ByRef $0AD0
ErrID: 0, V2: ByRef $0B30
ErrID: 0, V2: ByRef $0B90
ErrID: 0, V2: ByRef $0BF0
ErrID: 0, V2: ByRef $0C50
ErrID: 0, V2: ByRef $0CB0
こんな感じでカウントアップしてるのか?なんなのか?
--------------------------------------------------
dwErrID = AXSensor1.GetFInfo(pBy_Info_New) この後ですが
dwErrID = AXSensor1.CompFInfo(1, pBy_Info_New, pBy_Info_Old);
同じ指紋なら ErrIDには0が返り 認証OK
http://www.ratocsystems.com/pdffile/security/srexsdk2.pdf
ちなみに、Callback部分が作れなかったですが、もしかしてと思い
recodeをDLLにGetに入れるとなんらか返ってくるですが
ちゃんと、Callbackを作ってないせいか、CompFInfoで認証できません。
兄の会社の10人ほどのアルバイト管理を頼まれました・・・
去年作った、販売管理にタイムカード+しようとしています。。
自分は数字が好きな事務員です汗;
宜しくお願いいたします。
16進のWORD値だけでなく、ByRef/Arrayも毎回結果がぜんぜん違うじゃないですか(怒)
そういう大事なことは伏せておかないで下さい。一つだけ示されれば、それしかないと思ってしまいます!
他にもいろいろガミガミ言いたいことはありますが、それを言い始めると終わらないので(以下略)
…というか、こりゃーバリアントじゃないですね。タイプライブラリにすっかりだまされました。
SDKマニュアルの方にはバリアントなんて一切書いてないですし。
まあ、VBがバイト型配列なのはナゼ?と思ってたので、可能性はあったんですが。
そして、当てずっぽう さんがこれを予言した形になりました。
50%くらいは当たってます。失礼しました。でも理由は違いますねー。
ですからOleVariantに関することは一切忘れ、昨日の時点にさかのぼって
>PBy_Infoをキャストしたいのですが、そのキャスト方法がわかりません。
この方針で良いと思います。
SDKそのものはライセンスが必要みたいですが、SDKのマニュアルは公開情報なんですね。
ですので、あえてそれをコードに反映させてみます。
マニュアル・セキュリティ製品[RATOC] - ラトックシステム
http://www.ratocsystems.com/services/manual/security.html
Function GetFingerInfo(ByRef pSRexInfo As Object) As Integer
VB.NETではこう書いてありましたが、pSRexInfoはSRexInfoのミスプリじゃないかと思います。
DLL直の引数とか、CompFingerInfoはSRexInfoだ、とか全体の状況証拠的にですけど。
implementation
{$R *.dfm}
type
long = Longint;
// SREX_INFO 指紋情報構造体
PSREX_INFO = ^TSREX_INFO;
TSREX_INFO = packed record
Minutiae: array[0..1023] of BYTE; // データ格納バッファ 1024Byte
lengthMinutiae: long; // データサイズ
nMinutiae: long; // データの特徴数
Quality: long; // 特徴点の品質
DeviceName: array[0..7] of BYTE; // デバイス名
DllMajor: WORD; // DLL MaVersion
DllMinor: WORD; // DLL MiVersion
end;
procedure TestRecordEx(Info: TSREX_INFO; AStrings: TStrings);
var
L, H: Integer;
Str: AnsiString;
I: Integer;
begin
AStrings.Add('');
L:=Low(Info.Minutiae);
H:=High(Info.Minutiae);
AStrings.Add(Format('Minutiae: %dbyte', [Length(Info.Minutiae)]));
for I:=L to H do begin
Str:=Str+Format('%.2x',[Info.Minutiae[I]]);
if ((I-L+1) mod 16)=0 then begin
AStrings.Add(Str);
Str:='';
end else begin
Str:=Str+' ';
end;
end;
if Str<>'' then AStrings.Add(Str);
AStrings.Add(StringOfChar('-', 44));
AStrings.Add(Format('lengthMinutiae: %d', [Info.lengthMinutiae]));
AStrings.Add(Format('nMinutiae: %d', [Info.nMinutiae]));
AStrings.Add(Format('Quality: %d', [Info.Quality]));
SetLength(Str, SizeOf(Info.DeviceName));
Str:=StrMove(PAnsiChar(Str), PAnsiChar(@Info.DeviceName), SizeOf(Info.DeviceName));
AStrings.Add(Format('DeviceName: "%s", Length=%d', [Str, Length(Str)]));
AStrings.Add(Format('DllMajor: %d', [Info.DllMajor]));
AStrings.Add(Format('DllMinor: %d', [Info.DllMinor]));
end;
procedure TForm1.Button1Click(Sender: TObject);
var
ErrID: Integer;
By_Info: TSREX_INFO;
begin
Memo1.Clear;
// ErrID:=AXSensor1.GetFingerInfo(OleVariant(PVarData(@By_Info)^));
ErrID:=AXSensor1.GetFingerInfo(POleVariant(@By_Info)^);
Memo1.Lines.Add(Format('ErrID: %d', [ErrID]));
TestRecordEx(By_Info, Memo1.Lines);
end;
RATOCの指紋センサーなら扱ったことあります。
OCXで簡単に済まそうと思ったのですが、いろいろあってDLLを直接呼んでます。
//デバイスのオープン
SRexOpenDevice: function(): DWORD; stdcall;
//デバイスのクローズ
SRexCloseDevice: function(): DWORD; stdcall;
//サンプル取得開始
SRexStartSampling: function(hWnd: HWND; Count: byte; TimeOut: byte;
hPicture0, hPicture1, hPicture2, hPicture3: HWND): DWORD; stdcall;
//サンプル取得終了
SRexStopSampling: function(): DWORD; stdcall;
//指紋情報取得
SRexGetFingerInfo: function(pSRexInfo: PSREX_INFO): DWORD; stdcall;
//指紋情報比較
SRexCompFingerInfo: function(SecureLevel: byte; pSRexInfo1, pSRexInfo2: PSREX_INFO): DWORD; stdcall;
こんな感じで宣言して
procedure TFingerPrintModule.DataModuleCreate(Sender: TObject);
const
DLL_NAME = 'SRexFSUx.DLL';
begin
try
DLLHandle := LoadLibrary(DLL_NAME);
except
DLLHandle := 0;
Exit;
end;
if DLLHandle = 0 then Exit;
//デバイスのオープン
@SRexOpenDevice := GetProcAddress(DLLHandle, 'SRexOpenDevice');
//デバイスのクローズ
@SRexCloseDevice := GetProcAddress(DLLHandle, 'SRexCloseDevice');
//サンプル取得開始
@SRexStartSampling := GetProcAddress(DLLHandle, 'SRexStartSampling');
//サンプル取得終了
@SRexStopSampling := GetProcAddress(DLLHandle, 'SRexStopSampling');
//指紋情報取得
@SRexGetFingerInfo := GetProcAddress(DLLHandle, 'SRexGetFingerInfo');
//指紋情報比較
@SRexCompFingerInfo := GetProcAddress(DLLHandle, 'SRexCompFingerInfo');
end;
このように動的にリンク。
データの構造体はHarryさんのレスのとおりで
var
FingerInfo: TSREX_INFO;
ret: integer;
begin
ret := SRexGetFingerInfo(@FingerInfo);
end;
これで、データを取得できます。
もっとも、データをとる前にいろいろ処理が必要ですが
直接Delphiとは関係ないので・・
Questさん
なんかこのスレッドがすごく指紋っぽくなってきました(笑)
今初めてSDKマニュアルをちゃんと読んだんですが、4台まで接続して運用できるといっても、APIの仕組み的に
複数台が同一の瞬間にサンプリングを行うことは出来ないような気がします。これはもったいない。
(指紋情報取得の際に機器指定が無い → 台数分のバッファを持ってないからオーバーラップ不能 → 読み取りも逐次受け付けになり同時は不可)
Mojicさん
>DLLを呼び出して関数みたいに使うのは出来るのですが、DLLからの呼び出しのEventの追記が出来ず
ここを読んで勝手にコールバックと勘違いしてましたが、SDKマニュアルを見る限りSRexStartSamplingで
ウインドウハンドルを指定するとそこにWM_USER?(詳細不明)のメッセージが送られてきて、LParamに
SREX_SUCCESSとかのステータスコードが入っているようですね。
(ステータスコードのはずなのに、一覧表などには「通知メッセージ」と表記されてるから紛らわしい。)
プログラミング的には簡単だと思いますよ。論理の組み立てが簡単かどうかは分かりませんが。
Harry 様 ありがとうございます。
頂いたサンプルを理解するのと、問題が生じてたのでご連絡が遅くなり申し訳ございません。
※うまく行かなかったので、自分なりに色々と調べてました「基本他を疑わず、自分を疑うので汗;」
装置から取り込んだTSREX_INFOを下記の感じで保存して、読み込むのですが
function TForm1.SaveData(BBy_Info: TSREX_INFO): Boolean;
var
hFile: THandle;
RetBytesWritten : DWORD;
begin
Result := False;
SaveDialog1.InitialDir := ExtractFileDir(Application.ExeName);
if not SaveDialog1.Execute then Exit;
hFile := Windows.CreateFile(PChar(SaveDialog1.FileName), GENERIC_WRITE, 0, nil, CREATE_ALWAYS, 0, 0);
WriteFile(hFile, &BBy_Info, SizeOf(BBy_Info), RetBytesWritten, nil);
CloseHandle(hFile);
Result := True;
end;
モジュール'oleaut32.dll'のアドレス 757B5091 でアドレス 00B349D0 に対する読み取り違反がおきました。
となり、Fileに保存のしかたが悪いのかとかDBにとか色々試して悩んだのですが 色々みた結果「TSREX_INFO」
に帰ってくる情報が、VBやVCのサンプルプログラムで取り込んだ内容とは、同じはずのDiviceNameや1024byteの
データの詰まり方が全然違うようなので・・・・駄目だとお手上げになりました。
自分には解決ができません>< でした。
※Harry様ほどであれば実機があればこんな問題は問題にもならないかと思いますが、自分にはこれ以上は・・・無理です汗
で、DLLで行きたいのですがWindowsからのメッセージが理解出来てなくて
あ!「Callbackとかややこしいくして申し訳ありません。」
あと、どうしても解決できていないのが、WM_SREXFSUX ? たぶん仰る通りDLLをサンプリング呼び出しした
後に、メッセージがくると思うのでキャッチする部分を作りたくてネット検索するのですが
ファイルのD&DやMouseからのイベントなどの情報で、外部DLLからのメッセージの受け取り方法に至っておりません。。。
どこかにDelphiで使う為のWindowsMessageに関する情報がご存じであれば、ご教授お願いいたします。
Quest 様
情報ありがとうございます。
最初は自分もDLLで作ろうとして、↑↑↑↑こんなカッコいい書き方じゃないですが
※サンプルのVC6用をもじって作ったのですが、どうも・・・WM_の受け取り部分が理解できずに
断念していました。
サンプルVC6の*.hをもじったPAS
unit SRexFSUx;
interface
uses windows, SysUtils, Messages;
(* 通知メッセージ *)
const
WM_SREXFSUX = WM_APP + 2001;
SREX_SUCCESS = $00000000;
SREX_FAILED = $00000001;
SREX_START = $00000002;
SREX_END = $00000003;
SREX_FINGER_DETECT = $00000004;
SREX_NO_FINGER = $00000005;
SREX_TIMEOUT = $00000006;
SREX_TOO_RIGHT = $00000007;
SREX_TOO_LEFT = $00000008;
SREX_TOO_DOWN = $00000009;
SREX_TOO_UP = $00000010;
SREX_BAD_QUALITY = $00000011;
SREX_DIFFERENT = $00000012;
SREX_SLIDE = $00000013;
SREX_NOISE = $00000014;
SREX_SHORT = $00000015;
SREX_BACK = $00000016;
SREX_LARGE = $00000017;
SREX_FAST = $00000018;
SREX_BAD_SWIPE = $00000019;
SREX_PENDING = $00000020;
SREX_STOP = $00000021;
IDD_SDKSAMP = 101;
IDB_INIT = 1000;
IDB_ENROLL = 1001;
IDB_VERIFY = 1002;
IDB_EXIT = 1003;
IDB_STOP = 1004;
IDS_MSG = 1005;
IDP_FINGER1 = 1006;
IDP_FINGER2 = 1007;
IDP_FINGER3 = 1008;
IDP_FINGER4 = 1009;
IDCB_FSU2 = 1010;
type
long = Longint;
// SREX_INFO 指紋情報構造体
PSREX_INFO = ^TSREX_INFO;
TSREX_INFO = packed record
Minutiae: array[0..1023] of BYTE; // データ格納バッファ 1024Byte
lengthMinutiae: long; // データサイズ
nMinutiae: long; // データの特徴数
Quality: long; // 特徴点の品質
DeviceName: array[0..7] of BYTE; // デバイス名
DllMajor: WORD; // DLL MaVersion
DllMinor: WORD; // DLL MiVersion
end;
//var
// PSREX_INFO: TSREX_INFO;
// } SREX_INFO, *PSREX_INFO;
//
function SRexOpenDevice: DWORD; stdcall; external 'SRexFSUx.dll';
function SRexCloseDevice: DWORD; stdcall; external 'SRexFSUx.dll';
function SRexStopSampling: DWORD; stdcall; external 'SRexFSUx.dll';
function SRexRedraw: DWORD; stdcall; external 'SRexFSUx.dll';
function SRexStartSampling(hWnd: HWND; Count: Byte; Timeout: Byte; hPicture0, hPicture1, hPicture2, hPicture3:HWND):DWORD; stdcall; external 'SRexFSUx.dll';
function SRexGetFingerInfo(var pSRexInfo: TSREX_INFO):DWORD; stdcall; external 'SRexFSUx.dll';
function SRexCompFingerInfo(SecureLvl: UCHAR; pSRexInfo1, pSRexInfo2: TSREX_INFO):DWORD; stdcall; external 'SRexFSUx.dll';
function SRexInitFSU2Device(OpenNo: UCHAR):DWORD; stdcall; external 'SRexFSUx.dll' ;
//}
implementation
で、頂いたソースを元に色々してみたのですが全然だめで・・・汗 本当に技量が無いので
WM_ に関して
procedure WM_SREX_EventMsg(hWindow:HWND; uMsg:Uint; wParam, lParam: Integer);message WM_SREXFSUX;
こんな感じのを、書くけどモチロン Errで、どのようにしてメッセージを受け取られてるかお教え願えればと・・・
※サンプリング後、数秒あけてGetFingerInfoではちゃんと受け取ってるので、なんとなく動いてるようですが
WM_からのイベントだともっとスマートなので、ご存じであれば宜しくお願いいたします。
あと、画像っていうかVBとかにあるPictureBoxで表示してる「指紋画像」とかも成功されていますか?僕には皆無です汗;
function SRexStartSampling(hWnd: HWND; Count: Byte; Timeout: Byte; hPicture0, hPicture1, hPicture2, hPicture3:HWND):DWORD; stdcall; external 'SRexFSUx.dll';
とりあえずのことを書きますね。
もうOCX路線はあきらめたようですけど、あまりにも消化不良要因が多いので、ちょっと続けさせてください。
前にも言いましたが、うまくいったことと、どこからダメになったのかを十分に伝えてもらわないと困ります。
ファイル保存など、先に進んだように見えますが…そもそもGetFingerInfoの後でTestRecordExして表示された
生データはどうでしたか?(その確認になると思って、DeviceNameなどを念入りに仕込んでおいたのです。)
そしてCompFingerInfoで照合がOkなら、データ取得/送り出し には成功と見て良いですよね。
この大事な部分の話をすっ飛ばされると、私はどう理解したらいいのか分からなくなります。
メッセージの取り扱いについては、(私は)今は保留します。もう少し落ちついて欲しいので。
> WM_SREXFSUX = WM_APP + 2001;
これは納得。SDKマニュアルにユーザー定義メッセージとあったので「WM_USER?」と思いましたが、やはり。
あと、微妙に気になる点が2つあります。
ひとつは先に挙げた↓これです。
> Function GetFingerInfo(ByRef pSRexInfo As Object) As Integer
ここ、VB.NETのサンプルでGetFingerInfoしてる所はどうなってますか?
使ってる変数の「宣言」はCompFingerInfoと同一で、ポインタじゃないですよね?
もうひとつは構造体。VB6の状況証拠からパックだろうと確信してますが…。
(VCだと #pragma pack(1)とか__unalignedという記述がどこかにありますよね? 私も詳しくないですけど。)
VB.NETではどう宣言されているか確認したいですね。 直前に[StructLayout 〜 があればその行も含めて。
翻訳したヘッダを丸々アップしてますが…。ライセンス契約的に問題ないですか? ないならいいんですが。
ラトックにOkもらえるとやりやすいですね。「DLLとOCXはダメでしょうが、サンプルコードは公開可か?」と。
Harry様
TestRecordExに表示した内容ですが、この内容が一番ライセンスに
触れそうなので避けてます m(。。)m
ただ、 Minutiae: array[0..1023] of BYTE;の部分が
サンプルプログラム VBとかVCでの吐き出された内容の半分ぐらい
数字が入ってるのですが、半分は00埋めされてます(バイナリエディタで確認)
しかし、頂いたOCXソースの ErrID:=AXSensor1.GetFingerInfo(POleVariant(@By_Info)^);
で帰ってくるBy_Info.Minutiae[x]内容は、全部に何らかの16進数が入っています。
DiviceNameも両方とも同じ内容がかえってきますが、16進数でみると
DLLや付属サンプルではバイナリエディタでみると機器の名前になります。
※読めます。Ord?的な感じで
VBでもVB.Netでも同じ変数宣言と使い方みたいです。
Dim SRexInf() As Byte
dwErr = AXSensor1.GetFingerInf(SRexInf)
と最初の方に書き込んだ内容な感じで、すべてByte扱いみたいです。
> 直前に[StructLayout 〜 があればその行も含めて。
そのような感じの部分は有りませんでした。(意味を理解できてないだけかもしれません。)
Headerソースに関して
すいません、ちょっと大ぴらにし過ぎましたので、手遅れですが控えます。
言葉足らずで、本当に申し訳ありませんが宜しくお願いいたします。
指紋データを取得するサンプルをまとめましたが
「ライセンス的にどうよ?」って話もあるので
取り敢えずメッセージを受け取る所だけ。
とあるフォームのPublic宣言のあとに
protected
{ Protected 宣言 }
//メッセージ処理
procedure WndProc(var Msg: TMessage); override;
こんな感じで追加して、実装の方は
procedure TForm1.WndProc(var Msg: TMessage);
begin
if Msg.Msg = WM_SREXFSUX then
SRexFSUxAX1EventMsg(Msg.WParam, Msg.LParam)
else
inherited WndProc(Msg);
end;
こうします。
で、肝心のSRexFSUxAX1EventMsgは
procedure TForm1.SRexFSUxAX1EventMsg(wParam, lParam: Integer);
var
ret: integer;
begin
case lParam of
SREX_SUCCESS:
begin
ret := FingerPrintModule.GetFingerInfo(@FingerDataBuffer);
if ret = 0 then
begin
//情報を取得できた時の処理
//ModalResult := mrOk;
end
else
begin
//取得できなかった時の処理
//ShowMessage('指紋情報取得に失敗しました'#13'エラーコード:$'+IntToHex(ret,2));
//ModalResult := mrCancel;
end;
end;
SREX_FAILED:
;//Label1.Caption := '失敗:$'+IntToHex(wParam,2);
SREX_START:
;//Label1.Caption := '指紋を取得中です';
SREX_END:
;//Label1.Caption := '指紋取得終了';
SREX_STOP:
;
SREX_FINGER_DETECT:
;//Label1.Caption := '指紋を取得中です';
SREX_NO_FINGER:
;//Label1.Caption := '指を置いてください';
SREX_TIMEOUT:
begin
//時間切れの時の処理
//Label1.Caption := '時間切れです';
//ModalResult := mrCancel;
end;
SREX_TOO_RIGHT:
;//Memo1.Lines.Add('右にずれています');
SREX_TOO_LEFT:
;//Memo1.Lines.Add('左にずれています');
SREX_TOO_DOWN:
;//Memo1.Lines.Add('下にずれています');
SREX_TOO_UP:
;//Memo1.Lines.Add('上にずれています');
SREX_BAD_QUALITY:
;//Memo1.Lines.Add('指紋の品質が悪い');
SREX_DIFFERENT:
;//Memo1.Lines.Add('指紋が異なる');
SREX_SLIDE:
;//Memo1.Lines.Add('指を滑らせてください');
SREX_NOISE:
;//Memo1.Lines.Add('ノイズを含んでいます');
SREX_SHORT:
;//Memo1.Lines.Add('短すぎます');
SREX_BACK:
;//Memo1.Lines.Add('滑らす方向が変わりました');
SREX_LARGE:
;//Memo1.Lines.Add('斜めに滑って大きすぎます');
SREX_FAST:
;//Memo1.Lines.Add('速すぎます');
SREX_BAD_SWIPE:
;//Memo1.Lines.Add('滑らせ方が悪い');
SREX_PENDING:
;//Memo1.Lines.Add('コマンドによる強制停止');
end;
end;
こんな感じ。
フォームにラベルやメモを置いてある事を想定しています。
FingerDataBufferはPrivateあたりで
FingerDataBuffer: TSREX_INFO;
などと宣言しておきます。
FingerPrintModuleは以前のレスのDLLの宣言のユニットです。
で、OpenDeviceしてからStartSamplingを呼び出すと
メッセージを受け取れると思います。
たとえば
FingerPrintModule.StartSampling(Form1.Handle, 3, 15, 0, 0, 0, 0);
とすると、1回のタイムアウトが15秒で、3回指紋を読み取ると
SREX_SUCCESSが返ってくると思います。
もしかしたら、VistaやWindows7でUACが有効の場合、管理者権限で実行しないと
メッセージを受け取れないかもしれません。
(自分でロードしたDLLからなら大丈夫だったかな?)
あぁ、それとMinutiae[0..1023]の中身ですが、変数の宣言のしかたによって
最初に初期化しないとゴミ(不定の数値)が入っている場合があります。
正常にデータを取得できたならば、lengthMinutiaeにデータ数が入っているので
Minutiaeの中身で有効なのは、先頭からlengthMinutiaeで示されるバイト数だけです。
また、同じ指紋を読み取ってもこのデータが完全に一致するとは限りません(たぶん)。
読み取った指紋データが保存した指紋データと同一の指紋なのかは
SRexCompFingerInfo関数で確認する必要があります。
って、Delphiの話じゃないですね。スミマセン。