Biblioteka DLL - skaner kodów kreskowych

0

Witam,

Tworzę bibliotekę DLL pozwalający na połączenie funkcji w mojej aplikacji z funkcjami skanera kodów kreskowych firmy Zebra poprzez wykorzystanie sterownika urządzenia. Narzędzie w jakim piszę sterownik to Turbo Delphi.

Czy ktoś wie jak sterownik skanera Zebra mogę dodać do projektu? Firma Zebra w paczce SDK oraz w dokumentacji opisuje jak wykorzystać skaner w kodzie biblioteki DLL poprzez wykorzytanie połączenia COM. Rozumiem to, jednak w Trubo Delphi nie jestem w stanie (lub robię coś nie tak) dodać Referencji COM tak jak np. w C# poprzez wybór z listy. Jest jeszcze sterownik ZebraScannerSO.dll (który w Visual Studio znalazłem w referencjach), ale do niego nie znalazłem dokumentacji zawierającej nazw funkcji i sposobu ich wywoływania.

void Open(
int reserved, 
System.Array sfTypes, 
short lengthOfTypes, 
out int status);

Zastanawiam się też czy w ogóle jest sens wykorzystywania sterownika .DLL danej firmy. A może jest jakiś uniwersalny sterownik do skanerów? Czy może lepszym sposobem jest utworzenie wątku w bibliotece przechwytywania wciśniętego klawisza lub wykorzystania plików systemowych, które skaner wykorzystuje jako domyślne: kbdclass.sys i kbdhid.sys. Niestety nie wiem jak można te pliki wywołać w Turbo Delphi i czy to pomoże.

Bardzo proszę o pomoc jak mogę to zrobić, aby to działało, bo mój wykładowca nie chce mi nic pomóc ;/.
Z góry dziękuję za pomoc ;)

2

W załączniku potrzebne unity, obsługa wygląda mniej więcej tak

uses
	JvHidControllerClass

private
	FHID: TJvHidDeviceController;
  FHIDDev: TJvHidDevice;
		
form.create
	FHIDDev := nil;
  FHID := TJvHidDeviceController.Create(nil);
  FHID.OnDeviceChange := HidChange;
  FHID.OnEnumerate := HidEnumerate;
end;
	
form.destroy
	if FHIDDev <> nil then
	begin
		FHIDDev.OnData := nil;
		FHIDDev.Free;
	end;
	FHID.Free;
end;
	
function form.HidEnumerate(HidDev: TJvHidDevice; const Index: Integer): Boolean;
begin
  if SameText(Trim(HidDev.ProductName), Trim("nazwa skanera z menadżera urządzeń"))  then
  begin
    FHID.CheckOutByIndex(FHIDDev, Index);
    FHIDDev.NumInputBuffers := 128;
    FHIDDev.NumOverlappedBuffers := 128;
    FHIDDev.OnData := HidData;
  end;
  Result := True;
end;

procedure form.HidChange(Sender: TObject);
begin
  if FHIDDev <> nil then
  begin
    FHIDDev.OnData := nil;
    FHIDDev.Free;
    FHIDDev := nil;
  end;
  FHID.Enumerate;
end;

procedure form.HidData(HidDev: TJvHidDevice; ReportID: Byte;
  const Data: Pointer; Size: Word);
var
  kod: string
begin
  kod := Trim(PChar(Data));  //tu masz zeskanowany kod
end;
0

A czemu w załączniku potrzebne Unity? Przepraszam, jeśli będę zadawał pytania, na które odpowiedź może być dla Was oczywista. Po prostu muszę się jeszcze duuuuuuuużo nauczyć ;)

2

Mój post pokazuje jak dobrać się do skanera kodów kreskowy, który jest podłączony przez USB i działa w trybie USB, nie emulacji RS232 (COM) czy klawiatury. Unity są w załączniku bo tam ich miejsce (przecież nie będę zbędnego dla pytania kodu w poście wklejał). A są w ogóle bo jest w nich kod potrzebny do dobrania się do urządzenia HID.

Powiem szczerze, że nie bardzo wiem z czym masz problem bo piszesz o skanerze kodów kreskowych ale ani nie wiadomo jaki to model ani jak jest podłączony ani jak jest ustawiony. Większość "zwykłych" ręcznych skanerów podłączanych przez USB może pracować w kilku trybach - emulacja portu RS232 (wtedy po podłączeniu masz w systemie dodatkowy port COM, którym komunikujesz się ze skanerem i cała obsługa sprowadza się do instalacji jednego komponentu, położenia go na formę, skonfigurowania i tyle. Bez linijki kodu), emulacja klawiatury - wtedy nic nie trzeba - efekt jest taki jakbyś ten kod wpisał z klawiatury. Ostatni tryb to USB Handheld Scanner - do tego potrzebujesz dobrać się przez urządzenie HID.

0

abrakadaber a czy robiłeś jakieś próby jak to ogarnąć pod androidem + firemonkey ?

0

ale co?? Zacznij może podawać jakiekolwiek konkrety bo jak na razie to nic nie wiadomo

0

ja jestem za emulacją klawiatury, po kiego się męczyć? Poza tym, w ten sposób blokujesz swojej aplikacji korzystanie ze skanerów innych producentów. Być może chodzi ci o to że chciałbyś rozpoznać czy kod został wpisany z klawiatury czy też zeskanowany i inaczej zareagować w aplikacji.Są na to sposoby, albo doporogramowanie STX i ETX w skanerze i wtedy sprawa prosta bo po odczytaniu pierwszego znaku jako STX, magazynujesz znaki do czasu pojawienia się ETX i wtedy reagujesz w zamierzony sposób (wada, klient musi umieć programować skanery a to wcale nie jest takie oczywiste) lub pomiar czasu od pojawienia się pierwszego znaku do ostatniego, ustalasz czas na np. 100 ms (po eksperymentach) i już wiesz że te 8 czy 13 znaków nikt w tak krótkim czasie nie wpisał z klawiatury. Acha, te rozwiązania bez problemu można użyć z FireMonkey na Androidzie np.

0

wszytko ok, tylko co jak akurat focus jest w złej kontrolce i kod wpisze się nie tam gdzie trzeba. Albo np. ktoś zeskanuje kod i zacznie na klawiaturze pisać (wbrew pozorom skaner wysyła kod ean13 ok 2-3 sekund jeśli działa jak klawiatura). Jak masz na rs232 (lub w trybie emulacji) to input ze skanera dostajesz w zupełnie innym miejscu niż z klawiatury i niczym się nie przejmujesz

0
abrakadaber napisał(a):

wszytko ok, tylko co jak akurat focus jest w złej kontrolce i kod wpisze się nie tam gdzie trzeba. Albo np. ktoś zeskanuje kod i zacznie na klawiaturze pisać (wbrew pozorom skaner wysyła kod ean13 ok 2-3 sekund jeśli działa jak klawiatura). Jak masz na rs232 (lub w trybie emulacji) to input ze skanera dostajesz w zupełnie innym miejscu niż z klawiatury i niczym się nie przejmujesz

aż mnie zaintrygowałeś i sprawdziłem czas wpisywania kodu ean13 do edtia. W przypadku mojego skanera (Metrologic Eclipse M95145) trwa to 0.25 sekundy ale nawet jakby to było 500 ms to i tak nie jest to czas możliwy do wpisania ręcznie przez użytkownika.
Jak mierzyłem? Ano tak jak poniżej. Mój skaner ma akurat zaprogramowane STX (#2) na początku i ETX (#3) na końcu

procedure TForm1.edt1KeyPress(Sender: TObject; var Key: Char);
var startTick, delta: DWord;

begin
  if Key = #2 then
    startTick:=GetTickCount;
   
  if key = #3 then
  begin
    delta := GetTickCount - startTick;
    ShowMessage('Operacja trwała: ' + FloatToStr(delta / 1000) + ' s');
  end;
end;

Co do braku fokusa, oczywiście że masz rację, dlatego na formie z innymi kontrolkami edycyjnymi można zawsze użyć prefiksu STX i już. Rozwiązanie ze skanerem na porcie RS232, czy USB są ok ale jednak uciążliwe czy wręcz niewykonalne w aplikacjach FM pod androida czy też iso. Zresztą nawet nie wiem czy warto kruszyć kopie o takie proste sprawy?

ps.
sprawdziłem skaner podpięty pod port USB 2.0, czas taki sam 250 ms.

ps2.
a wiesz że przypominam sobie skanery które w notatniku wpisywały kod cyfra po cyfrze. Ale to były odległe dzieje, one miały coś nie tak z emulacją. Teraz takich problemów już nie ma a jak coś jest nie tak to należy sprawdzić zaprogramowanie skanera (zacząć od resetu).

0

Skaner to Zebra Symbol LS2208 - SR20007R-UR, jednak wykładowca mówił mi, że chce mieć możliwość użycia dowolnego skanera.
Jeśli chodzi o umieszczanie zeskanowanego kodu w polu input to miałem też taki pomysł, jednak otrzymałem wymagania, że dane mają zostać przechwycone poprzez wykorzystanie sterownika urządzenia - czyli robię Aplikację, do której tworzę sterownik DLL w nim robię komunikację z elementami aplikacji, a w sterowniku podpinam sterownik urządzenia, importuję interfejsy i funkcje i implementuję je ze swoimi funkcjami, które wyświetlają dane ze skanera w polach aplikacji (o_0) Mam nadzieję, że to jakoś wyjaśniłem.

Aplikacja -> DLL z moimi funkcjami -> połączona z sterownikiem DLL Zebra (którego nie mogę znaleźć) -> pobiera zeskanowany kod -> wyświetla poprzez funkcje z mojej DLL dane w polach aplikacji

0

Na wykładowcę nie ma rady. Chce przez dll to musisz tak zrobić. Jedyne czego sobie nie wyobrażam to "jednak wykładowca mówił mi, że chce mieć możliwość użycia dowolnego skanera" - jak ty to zrobisz to nie mam pojęcia bo wydaje mi się że dll-ki od zebry nie do końca będą działały z metrologikiem czy też motorolą?

Ale powodzenia :)

0

W firemonkey to trochę nieciekawie wygląda obsługa KeyPress na formie bo jej normalnie nie ma :/ jest keydown/keyup ale też nie ma keypreview.

1
robertz68 napisał(a):

Na wykładowcę nie ma rady. Chce przez dll to musisz tak zrobić. Jedyne czego sobie nie wyobrażam to "jednak wykładowca mówił mi, że chce mieć możliwość użycia dowolnego skanera" - jak ty to zrobisz to nie mam pojęcia bo wydaje mi się że dll-ki od zebry nie do końca będą działały z metrologikiem czy też motorolą?

A np. tak:
https://stackoverflow.com/questions/3156418/windows-global-keyboard-hook-delphi :-)

Czyli zakładamy globalnego hook'a na klawiaturę w DLL.
Kod obsługi jest w DLL, korzysta z przechwytywania klawiatury, a to zadziała z dowolnym skanerem.
Spełnia warunki? :D

Ale powodzenia :)

Jemu też :)

0

@abrakadaber: Sorki że odgrzebuję starocia ale męczę się niemiłosiernie z podłączeniem skanera kodów kreskowych do mojej aplikacji. Utworzyłem sobie maluszka do testowania (w załączniku), listuję urządzenia HID ale za diabli nie mogę wpisać tego co odczytał skaner do zmiennej kod.
Tak wygląda unit:

unit Umain;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  JvComponentBase, JvHidControllerClass, Vcl.StdCtrls;

type
  Tmain = class(TForm)
    FHID: TJvHidDeviceController;
    lblkod: TLabel;
    lsturzadzenia: TListBox;
    lblmonitorowane: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    function HIDEnumerate(HidDev: TJvHidDevice; const Idx: Integer): Boolean;
    procedure HIDChange(Sender: TObject);
    procedure HIDData(HidDev: TJvHidDevice; ReportID: Byte; const Data: Pointer; Size: Word);
  private
    FHIDDev: TJvHidDevice;
    { Private declarations }
  public
    { Public declarations }
  end;

var
  main: Tmain;

implementation

{$R *.dfm}

procedure Tmain.HIDChange(Sender: TObject);
begin
  if FHIDDev <> nil then
  begin
    FHIDDev.OnData := nil;
    FHIDDev.Free;
    FHIDDev := nil;
  end;
  FHID.Enumerate;
end;

procedure Tmain.HIDData(HidDev: TJvHidDevice; ReportID: Byte; const Data: Pointer; Size: Word);
var
  kod: string;
begin
  kod := Trim(PChar(Data));  //tu masz zeskanowany kod
  lblkod.Caption := 'Kod kreskowy: ' + kod;
end;

function Tmain.HIDEnumerate(HidDev: TJvHidDevice; const Idx: Integer): Boolean;
begin
  lsturzadzenia.Items.Add(Format('%.4x / %.4x / %s', [HidDev.Attributes.VendorID, HidDev.Attributes.ProductID, HidDev.ProductName]));
  if SameText(Trim(HidDev.ProductName), Trim('Metrologic Scanner')) then
  begin
    FHID.CheckOutByIndex(FHIDDev, Idx);
    FHIDDev.NumInputBuffers := 128;
    FHIDDev.NumOverlappedBuffers := 128;
    FHIDDev.OnData := HidData;
    lblmonitorowane.Caption := 'Podłączony skaner: ' + HidDev.ProductName;
  end;
  Result := True;
end;

procedure Tmain.FormCreate(Sender: TObject);
begin
  FHIDDev := nil;
  FHID := TJvHidDeviceController.Create(nil);
  FHID.OnDeviceChange := HidChange;
  FHID.OnEnumerate := HidEnumerate;
end;

procedure Tmain.FormDestroy(Sender: TObject);
begin
  if FHIDDev <> nil then
  begin
    FHIDDev.OnData := nil;
    FHIDDev.Free;
  end;
  FHID.Free;
end;

end.

Mógłbyś troszkę pomóc?

1

no ale co się dzieje? W ogóle masz zainstalowany skaner (masz wgrane sterowniki?), skaner jest ustawiony w trybie USB, nie emulacji RS232 (COM) czy klawiatury. W lsturzadzenia masz wylistowany skaner? Nazwa (PEŁNA) to na pewno Metrologic Scanner? Postaw breakpointa tu FHID.CheckOutByIndex(FHIDDev, Idx); i zobacz czy w ogóle tutaj wchodzi. Postaw breakpointa tu kod := Trim(PChar(Data)); i zobacz czy w ogóle wchodzi a jak wchodzi to co masz w zmiennej Data.
BTW nikt CI tego nie przetestuje u siebie bo nie ma Twojego skanera ani Twojej konfiguracji.

0
  1. Skaner mam oczywiście podłączony, Windows sam go rozpoznał, zresztą żadnych sterowników do niego nie ma.
  2. Na liście urządzeń HID jest mój skaner (ostatni na liście)
    screenshot-20191229230623.png
  3. Brakepoint ustawiony w enumeracji oczywiście daje wynik pozytywny (zresztą dlatego właśnie wyświetliłem na labelku nazwę skanera aby mieć pewność że nie pomyliłem nazwy).
  4. Kompletnie nie wskakuje w procedurkę HidData. Jest tam pusto.

Teraz w zasadzie najważniejsze, piszesz o przestawieniu skanera w tryb USB, oczywiście mój skaner nie jest tak ustawiony i nie chciałbym aby tak było. W aplikacji której chcę zrobić odpowiednik zwykły skaner USB (działający jako emulacja klawiatury) obsługiwany jest poprzez interfejs HID (wybiera się go z listy poprzez VendorID/ProductID) i to działa. Czyli poza aplikacją skaner jest obsługiwany jako klawiaturowy.
Mam nadzieję że tak się da zrobić?
Jako że nie jestem leniwy, oczywiście jutro przestawię skaner w tryb USB (instrukcji papierowej potrzebuję) i jeszcze raz wszystko sprawdzę.

Problemem jest jednak brak ładowania danych i szczerze nie do końca rozumiem jak miało by się to odbywać? Samo przypisanie:

FHIDDev.OnData := HidData;

w enumeracji wystarczy? Nie trzeba do tego jakiegoś zdarzenia które na bieżąco sprawdzałoby czy nie pojawiły się jakieś dane w interfejsie HID?

Byłbym wdzięczny za pomoc.

1 użytkowników online, w tym zalogowanych: 0, gości: 1