UIRT DLL open call hangs with Delphi VCL app

Interested in integrating USB-UIRT support into an application? Look here!

Moderator: jrhees

UIRT DLL open call hangs with Delphi VCL app

Postby roschler » Sun Nov 21, 2004 11:31 pm

Hello Jon,

I saw the other poster's question about Delphi hanging on UUIRTOpen().

I'm also having the same problem but I'm almost positive it is not a calling convention issue. I believe there is a conflict with something your DLL is doing and what the Delphi VCL (Visual Component Library) is doing.

If I make a Delphi Console App (which does not use the VCL), then everything works fine, including UUIRTOpen().

If I make a VCL app, then UUIRTOpen() hangs every time. If I interrupt the program from the debugger, and trace the active thread at the assembly level, there is a thread waiting endlessly for some object (mutex, semaphore, etc.), in NTDLL. It's as if there is a collision going on between message loop handlers.

Hopefully it is something we can resolve, otherwise Delphi users will be locked out of using the UIRT dll if they don't go the extra step and make an out-of-process server to handle the UIRT communications.

Thanks
Robert
RobotsRule Discussion Forum
http://www.robotsrule.com/phpBB2/
roschler
 
Posts: 21
Joined: Fri Nov 19, 2004 1:18 am

Postby roschler » Mon Nov 22, 2004 6:35 pm

Jon,

I found the issue.

It isn't a VCL problem so that is great news.

It's a DLL sharing problem. If I run Girder, or have another app that opens the UIRT DLL, then the "hang" problem occurs upon opening the UIRT.

If I close the app that first grabbed the UIRT DLL down, then the "hanged" app comes back to life and returns an open error.

I'm guessing that the other poster that reported the same problem with Delphi either had: Girder open, or somehow got two instances of his app going, or made two calls to the UIRT open function within his app.

All is well now, I just don't run more than one UIRT app.

Thanks.
Robert
RobotsRule Discussion Forum
http://www.robotsrule.com/phpBB2/
roschler
 
Posts: 21
Joined: Fri Nov 19, 2004 1:18 am

Postby Guest » Mon Nov 22, 2004 7:22 pm

I have a problem with using this in Delphi, but it might be the calling convention messed up on my end. Here is my code for a console app.

The GetDriverInfo call always returns 0 for the return code, as well as the Transmit call. The Open seems to bring back a good handle to operate from (nonzero at least). The VB sample project works fine. Here is my code:

Code: Select all
program Project2;

{$APPTYPE CONSOLE}

uses
  SysUtils, Windows;

  const
    IRFORMAT_PRONTO = $10;

  type

    TUSBUIRTGetDriverInfo = function( var Version : Integer ) : Integer;
    TUSBUIRT_Open = function:Integer;
    TUSBUIRT_Close = function( Handle : Integer):Integer;
    TUSBUIRTTransmitIR = function( Handle : Integer; sIRCode : string; CodeFormat : Integer; RepeatCount : Integer; InactivityWaitTime : Integer; hEvent : Integer; Reserved1 : Integer; Reserved2 : Integer) : Integer;

   var  USBUIRT_Open : TUSBUIRT_Open;
        USBUIRT_Close : TUSBUIRT_Close;
        USBUIRTGetDriverInfo : TUSBUIRTGetDriverInfo;
        USBUIRTTransmitIR : TUSBUIRTTransmitIR;
        hDLL : Cardinal;
        Handle : Integer;
        Res : Integer;
        Version : Integer;
begin

   hDLL:=LoadLibrary(PChar('D:\H2\build\bin\uuirtdrv.dll'));
        if hDLL<>0 then
          begin

            @USBUIRT_Open :=GetProcAddress(hDLL,'UUIRTOpen');
            @USBUIRT_Close :=GetProcAddress(hDLL,'UUIRTClose');

            @USBUIRTTransmitIR :=GetProcAddress(hDLL,'UUIRTTransmitIR');
            @USBUIRTGetDriverInfo               :=GetProcAddress(hDLL,'UUIRTGetDrvInfo');

            Res := USBUIRTGetDriverInfo(Version);

            Handle := USBUIRT_Open;

            Res := USBUIRTTransmitIR(Handle, '0000 006b 0016 0000 0158 00ad 0013 00ac 0013 0056 0013 0056 0013 0056 0013 0056 0013 0056 0013 0056 0013 0056 0013 0056 0013 0056 0013 0056 0013 0056 0013 00ac 0013 00ac 0013 00ac 0013 00ac 0013 0639 0158 0056 0013 0d23 0158 0056 0013 00ad', IRFORMAT_PRONTO, 10, 0, 0, 0, 0);

            USBUIRT_Close(Handle);

          end;
end.
Guest
 

Postby roschler » Mon Nov 22, 2004 8:48 pm

Guest,

I don't use dynamic loading, I use static loading. I have included my Delphi unit for managing the UIRT so you can take a look at it. Obviously a good portion of it is code ported from the VB app.

Note to Jon: Let me know if this post is too long and I'll remove it.

Edited: It looks like the forum is stripping the tabs, don't know how to fix it.

Here's the code:

unit UIRT;

interface

uses SysUtils, Classes, Windows, SyncObjs;

// USB-UIRT DLL API Constants...
const
CRLF: string = '\r\n';

INVALID_HANDLE_VALUE: integer = -1;
ERROR_IO_PENDING: integer = 997;
UUIRTDRV_ERR_NO_DEVICE: integer = $20000001;
UUIRTDRV_ERR_NO_RESP: integer = $20000002;
UUIRTDRV_ERR_NO_DLL: integer = $20000003;
UUIRTDRV_ERR_VERSION: integer = $20000004;

UUIRTDRV_CFG_LEDRX: integer = $1;
UUIRTDRV_CFG_LEDTX: integer = $2;
UUIRTDRV_CFG_LEGACYRX: integer = $4;

UUIRTDRV_IRFMT_UUIRT: integer = $0;
UUIRTDRV_IRFMT_PRONTO: integer = $10;

UUIRTDRV_IRFMT_LEARN_FORCERAW: integer = $100;
UUIRTDRV_IRFMT_LEARN_FORCESTRUC: integer = $200;
UUIRTDRV_IRFMT_LEARN_FORCEFREQ: integer = $400;
UUIRTDRV_IRFMT_LEARN_FREQDETECT: integer = $800;

UUIRTDRV_IRFMT_TRANSMIT_DC: integer = $80;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Structure definitions:

// Define a structure for received IR codes.
// Received IR codes are 12-ASCII bytes longint, and are passed via a callback
// as a null-terminted string. Since VB handles strings differently, we
// define a byte array and convert it to a VB string inside the callback function.
tIRCode = record
codeData: array[0..15] of byte;
end;
TDynamicIRCodeArray = array of tIRCode;

// Define a structure to hold UUINFO data for the UUIRTGetUUIRTInfo function call...
tUuInfo = record
fwVersion: longint;
protVersion: longint;
fwDateDay: byte;
fwDateMonth: byte;
fwDateYear: byte;
end;
TDynamicUuInfoArray = array of tUuInfo;

TUIRTCommThread = class;

TUIRT = class
private
FDrvHandle: longint; // Handle used to communicate with the UIRT.
FUIRTCommThread: TUIRTCommThread;
protected
// Open the UIRT and get version information from it.
procedure openUIRT;
procedure closeUIRT;
public
constructor Create;
destructor Destroy; override;

procedure transmit(IRCode: string);
end;

TUIRTCommThread = class(TThread)
protected
FUIRT: TUIRT;
public
constructor Create(uirt: TUIRT);
procedure Execute; override;
end;

implementation

type
TLongPtr = ^longint;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// USB-UIRT DLL API Function Declarations....

// function UUIRTGetDrvInfo(var uVersion: longint) : longint; stdcall; external 'uuirtdrv.dll' name 'UUIRTGetDrvVersion';
function UUIRTGetDrvInfo(var uVersion: longint) : longint; stdcall; external 'uuirtdrv.dll' name 'UUIRTGetDrvInfo';

function UUIRTGetDrvVersion(var uVersion: longint) : longint; stdcall; external 'uuirtdrv.dll' name 'UUIRTGetDrvVersion';

function UUIRTOpen : longint; stdcall; external 'uuirtdrv.dll' name 'UUIRTOpen';

// function UUIRTOpen : TLongPtr; stdcall; external 'uuirtdrv.dll' name 'UUIRTOpen';

function UUIRTClose(hHandle: longint) : longint; stdcall; external 'uuirtdrv.dll' name 'UUIRTClose';

function UUIRTGetUUIRTInfo(hHandle: longint; var UuInfo: tUuInfo) : longint; stdcall; external 'uuirtdrv.dll' name 'UUIRTGetUUIRTInfo';

function UUIRTGetUUIRTConfig(hHandle: longint; var uConfig: longint) : longint; stdcall; external 'uuirtdrv.dll' name 'UUIRTGetUUIRTConfig';

function UUIRTSetUUIRTConfig(hHandle: longint; uConfig: longint) : longint; stdcall; external 'uuirtdrv.dll' name 'UUIRTSetUUIRTConfig';

function UUIRTTransmitIR(
hHandle: longint;
sIRCode: PChar;
uCodeFormat: longint;
uRepeatCount: longint;
uInactivityWaitTime: longint;
hEvent: longint;
reserved0: longint;
reserved1: longint) : longint; stdcall; external 'uuirtdrv.dll' name 'UUIRTTransmitIR';

function UUIRTLearnIR(
hHandle: longint;
uCodeFormat: longint;
szIRCode: longint;
pProgressProc: longint;
userData: longint;
var pAbort: boolean;
uParam1: longint;
hEvent: longint;
reserved0: longint) : longint; stdcall; external 'uuirtdrv.dll' name 'UUIRTLearnIR';

function UUIRTSetReceiveCallback(
hHandle: longint;
pReceiveProc: longint;
userData: longint) : longint; stdcall; external 'uuirtdrv.dll' name 'UUIRTSetReceiveCallback';


// ---------------------------------------------------------------

constructor TUIRT.Create;
begin
inherited Create;

openUIRT;
end;

destructor TUIRT.Destroy;
begin
closeUIRT;

inherited Destroy;
end;

// ---------------------------------------------------------------

procedure TUIRT.openUIRT;
var
drvAPIVersion: longint;
drvDLLVersion: longint;
res: longint;
dllErr: longint;
sErrMsg: string;
// tlp: TLongPtr;
begin

// Get USB-UIRT *driver* information. Note that this call does not actually
// communicate with the USB-UIRT hardware. Instead, its purpose is solely to
// retrieve version information about the API *driver*. This and GetDrvVersion are
// the only API calls (besides UUIRTOpen) which can be performed without a driver
// handle (prior to opening the driver via UUIRTOpen).
res := UUIRTGetDrvInfo(drvAPIVersion);
if res = 0 then
raise Exception.Create('(TUIRT.open) Unable to retrieve uuirtdrv version!');

// Check the API version. This Application is written to be compatible with
// driver API version 1.0 (0x100)
if drvAPIVersion <> $100 then
raise Exception.Create('(TUIRT.open) Invalid uuirtdrv version!');

// Get the Driver DLL Revision #. This is necessary for this VB app since it this
// app relies on a newer feature of the LearnIR() function which does not block. This
// new non-blocking ability is only available in DLL versions 2.6.1 or later.
// note: This API call does not exist in versions prior to 2.6.1, so we use try/except
// to trap this condition.
res := 0;

try
res := UUIRTGetDrvVersion(drvDLLVersion);
except
On E: Exception do; // Swallow exception.
end;

if (res = 0) or (drvDLLVersion < 2610) then
raise Exception.Create(
'(TUIRT.open) This application requires USB-UIRT API driver DLL (UUIRTDRV.DLL) version 2.6.1 or later. ' +
CRLF +
'Please verify you are running the latest API DLL and that you''re using the latest version of USB-UIRT firmware!' +
CRLF +
'If the problem persists, contact Technical Support!');

// Open a communications link with the USB-UIRT...
// Obtain a handle to the USB-UIRT via the UUIRTOpen call. if successful, a handle
// is returned which we *must* use in all subsequent APi calls.
FDrvHandle := UUIRTOpen();

// FDrvHandle := 0;
// FUIRTCommThread := TUIRTCommThread.Create(Self);

// if Open call failed, we will be returned an INVALID_HANDLE_VALUE and need to look
// at the error to determine what went wrong...
if FDrvHandle = INVALID_HANDLE_VALUE then
begin
// Get the last DLL error using the WIN API GetLastError() call.
dllErr := GetLastError();

if dllErr = UUIRTDRV_ERR_NO_DLL then
sErrMsg := ('Unable to find USB-UIRT Driver. Please make sure driver is Installed!')
else if dllErr = UUIRTDRV_ERR_NO_DEVICE then
sErrMsg := ('Unable to connect to USB-UIRT device! Please ensure device is connected to the computer!')
else if dllErr = UUIRTDRV_ERR_NO_RESP then
sErrMsg := ('Unable to communicate with USB-UIRT device! Please check connections and try again. if you still have problems, try unplugging and reconnecting your USB-UIRT. if problem persists, contact Technical Support!')
else if dllErr = UUIRTDRV_ERR_VERSION then
sErrMsg := ('Your USB-UIRT//s firmware is not compatible with this API DLL. Please verify you are running the latest API DLL and that you//re using the latest version of USB-UIRT firmware! if problem persists, contact Technical Support!')
else
sErrMsg := ('Unable to initialize USB-UIRT (unknown error)!');

raise Exception.Create('(TUIRT.open) ' + sErrMsg);
end
else
begin
// NOTE!!!: Learn function sample code and associated callback usage is not implemented yet.

// if Open was successful, we//ll want to register a receive callback function
// for the USB-UIRT API to call each time an IR code is received.
// res = UUIRTSetReceiveCallback(hDrvHandle, AddressOf IRReceiveCallback, Me);
end;
end;

// ---------------------------------------------------------------

procedure TUIRT.closeUIRT;
begin
if FDrvHandle <> 0 then
UUIRTClose(FDrvHandle);
end;

// ---------------------------------------------------------------

procedure TUIRT.transmit(IRCode: string);
var
res: longint;
IRCodeFormat: longint;
begin

If FDrvHandle = 0 then
raise Exception.Create('(TUIRT.transmit) UIRT communication handle is null.');

IRCodeFormat := UUIRTDRV_IRFMT_UUIRT;
res := UUIRTTransmitIR(FDrvHandle,
PChar(IRCode),
IRCodeFormat,
1,
0,
0,
0,
0);

if res = 0 then
raise Exception.Create('(TUIRT.transmit) UIRT transmit failed.');
end;


Thanks.
Robert
RobotsRule Discussion Forum
http://www.robotsrule.com/phpBB2/
roschler
 
Posts: 21
Joined: Fri Nov 19, 2004 1:18 am

Postby Guest » Mon Nov 22, 2004 9:56 pm

Thank you very much Robert, it worked like a charm. :)
Guest
 

Postby jrhees » Mon Nov 22, 2004 11:58 pm

roschler,

The current version of the API .dll should support sharing of the USB-UIRT just fine. Please make sure:

a) You're running a later version of the API .dll ( get it at www.usbuirt.com/latestAPIDriver.zip )

b) You do *not* have a local copy of the .DLL. All users of the API .DLL need to let Windows find the single copy of the uuirtdrv.DLL located in Windows\System32 folder. If you allow a local copy to be used, sharing will not work since Windows will load two separate instances of the .DLL and assume they are unique.

-Jon
jrhees
Site Admin
 
Posts: 1652
Joined: Tue Jan 28, 2003 11:49 pm

Postby roschler » Tue Nov 23, 2004 2:30 am

Jon,

That explains it. I keep a local copy of the DLL in my Delphi project. Just a habit I developed over the years.

Thanks.
Robert
RobotsRule Discussion Forum
http://www.robotsrule.com/phpBB2/
roschler
 
Posts: 21
Joined: Fri Nov 19, 2004 1:18 am

Postby Guest » Thu Feb 02, 2006 4:53 pm

Hi roschler, thanks for the code. Being a newbie myself, can you tell me how to implement this code --
Is this the right scenario:
1. Fire up Delphi and create new application and form
2. In the form, add your code file in USES clause
3. Use the functions/procedures as needed.

Are there any other issues I need to do, e.g. registering the driver, etc?

Thanks.
Guest
 

Postby danzman » Thu Feb 02, 2006 8:04 pm

Can Oschler's code be written as a COM or ActiveX object?
danzman
 
Posts: 2
Joined: Tue Jan 31, 2006 12:21 am

Postby Guest » Sun Feb 05, 2006 5:59 pm

Jon as you can see this is the third person asking for an ActiveX control,
why don't you answer this questions ?

A simple "I will not develop an activeX control" wouldt do it.
Guest
 

Postby jrhees » Thu Feb 09, 2006 11:44 pm

I started an ActiveX control a while back but my lack of experience regarding ActiveX prevented me from making good progress. My concern is my inability to support (technically) something I don't really understand.

With that said, I would not be a bit surprised if one (or more) ActiveX wrappers (on top of the existing API) already have been developed by others.
-Jon
jrhees
Site Admin
 
Posts: 1652
Joined: Tue Jan 28, 2003 11:49 pm

Postby Guest » Fri Feb 10, 2006 2:45 pm

OK Jon, you are forgiven :)

I got hold of a book on COM programming by Eric Harmon. I will use the guidelines there to create the ActiveX. I just need to understand the variables and functions called for by the UIRT dll. I know you have sent us "some" documentation. Can you expound further on the intricacies of the dll?
Guest
 

Postby jrhees » Tue Feb 14, 2006 1:09 pm

Please contact support@usbuirt.com and request the developer API.

-Jon
jrhees
Site Admin
 
Posts: 1652
Joined: Tue Jan 28, 2003 11:49 pm


Return to Developers

Who is online

Users browsing this forum: No registered users and 27 guests

cron