如何使用Delphi 2009调用Microchip PIC USB DLL
不是问题,只是一个声明,旨在帮助其他可能花费数小时让 Microchip PIC USB DLL 与 Unicode 正常工作的人。
它需要几个字符串,虽然这些是简单的 PAnsiChar
,但获得 DLL 调用约定的正确组合花了我很长时间。 网上有很多人使用 Delphi(非 Unicode)和这个 DLL 并逃脱了谋杀。
unit UArtPic32USBDriver;
interface
uses
Windows,
SysUtils,
UArtGeneralHwDefs;
type
EArtPic32Usb = class( EArtGeneralHw );
function Pic32Usb_GetDllVersion : integer;
// Returns a number representing the DLL version.
function Pic32Usb_GetDeviceCount( const AVendorProductID : string ) : integer;
// Returns the number of devices with this vendor ID
function Pic32Usb_Open(
AInstance : DWORD;
const AVendorProductID, AEndpointID : string;
ADirectionCode : integer;
ARaise : boolean ) : THANDLE;
// Opens an endpoint. Can raise an exception if no valid handle is returned.
procedure Pic32Usb_Close( AHandle : THandle );
// Closes the device
function Pic32Usb_Write(
AHandle : THANDLE;
ABufferPtr : pointer;
ALengthBytes : integer ) : DWORD;
// Performs a write using this handle. Returns the number of bytes written
function Pic32Usb_Read(
AHandle : THANDLE;
ABufferPtr : pointer;
ALengthBytes : integer ) : DWORD;
// Performs a Read using this handle. Returns the number of bytes read
const
MP_WRITE = 0;
MP_READ = 1;
implementation
var
_MPUSBGetDLLVersion : function () :DWORD; cdecl stdcall;
// Number of vid & pid matching USB Devices
_MPUSBGetDeviceCount : function( pVID_PID : PAnsiChar ) : DWORD; cdecl;
_MPUSBOpen : function ( instance : DWORD;
pVID_PID : PAnsiChar;
pEP : PAnsiChar;
dwDir : DWORD;
dwReserved : DWORD ) : THANDLE; cdecl;
_MPUSBClose : function ( handle :THANDLE ) : DWORD; cdecl;
_MPUSBRead : function ( handle : THANDLE;
pData : pointer;
dwLen : DWORD;
var pLength : DWORD;
dwMilliseconds : DWORD ) : DWORD; cdecl;
_MPUSBReadInt : function ( handle : THANDLE;
var pData : pointer;
dwLen : DWORD;
var pLength : PDWORD;
dwMilliseconds : DWORD ) : DWORD; cdecl;
_MPUSBWrite : function ( handle : THANDLE;
pData : pointer;
dwLen : DWORD;
var pLength : DWORD;
dwMilliseconds : DWORD ) : DWORD; cdecl;
UsbDllHandle : THandle = 0;
const
MillisecondPollingInterval = 100; //Represents 1 ms is hardware
CharBufSize = 64;
type
TAnsiCharBuf64 = array[0..CharBufSize-1] of AnsiChar;
function LoadDLL : THandle;
var
S : string;
begin
S := 'mpusbapi.dll';
UsbDllHandle := LoadLibrary( PChar(S) );
If UsbDllHandle = 0 then
Raise EArtPic32Usb.CreateFmt(
'The usb library is required but cannot be loaded. Check that it is installed. (%s)',
[S]
);
@_MPUSBGetDLLVersion := GetProcAddress(UsbDllHandle,'_MPUSBGetDLLVersion');
Assert(@_MPUSBGetDLLVersion <> nil);
@_MPUSBGetDeviceCount := GetProcAddress(UsbDllHandle,'_MPUSBGetDeviceCount');
Assert(@_MPUSBGetDeviceCount <> nil);
@_MPUSBOpen := GetProcAddress(UsbDllHandle,'_MPUSBOpen');
Assert(@_MPUSBOpen <> nil);
@_MPUSBClose := GetProcAddress(UsbDllHandle,'_MPUSBClose');
Assert(@_MPUSBClose <> nil);
@_MPUSBRead := GetProcAddress(UsbDllHandle,'_MPUSBRead');
Assert(@_MPUSBRead <> nil);
@_MPUSBReadInt := GetProcAddress(UsbDllHandle,'_MPUSBReadInt');
Assert(@_MPUSBReadInt <> nil);
@_MPUSBWrite := GetProcAddress(UsbDllHandle,'_MPUSBWrite');
Assert(@_MPUSBWrite <> nil);
Result := UsbDllHandle;
end;
procedure NeedDLL;
begin
If UsbDllHandle = 0 then
LoadDll;
end;
function Pic32Usb_GetDllVersion : integer;
// Returns a number representing the DLL version.
begin
NeedDLL;
Result := _MPUSBGetDLLVersion();
end;
function Pic32Usb_GetDeviceCount( const AVendorProductID : string ) : integer;
// Returns the number of devices with this vendor ID
var
bufVendorProductID : TAnsiCharBuf64;
begin
NeedDLL;
StrPCopy( bufVendorProductID, AnsiString(AVendorProductID) );
Result := _MPUSBGetDeviceCount( @bufVendorProductID );
end;
function Pic32Usb_Open(
AInstance : DWORD;
const AVendorProductID, AEndpointID : string;
ADirectionCode : integer;
ARaise : boolean ) : THANDLE;
// Opens an endpoint. Can raise an exception if no valid handle is returned.
var
bufVendorProductID, bufEndpointID : TAnsiCharBuf64;
begin
NeedDLL;
StrPCopy( bufVendorProductID, AnsiString(AVendorProductID) );
StrPCopy( bufEndpointID, AnsiString(AEndpointID) );
Result := _MPUSBOpen(
AInstance,
@bufVendorProductID,
@bufEndpointID,
DWORD(ADirectionCode),
0 );
if Result = 0 then
If ARaise then
Raise EArtPic32Usb.CreateFmt(
'Unable to open USB device "%s", endpoint "%s"', [AVendorProductID, AEndpointID]);
end;
procedure Pic32Usb_Close( AHandle : THandle );
begin
If UsbDllHandle <> 0 then
_MPUSBClose( AHandle );
end;
function Pic32Usb_Write(
AHandle : THANDLE;
ABufferPtr : pointer;
ALengthBytes : integer ) : DWORD;
// Performs a write using this handle. Returns the number of bytes written
var
I : integer;
begin
I := _MPUSBWrite(
AHandle,
ABufferPtr,
DWORD( ALengthBytes ),
Result,
MillisecondPollingInterval );
if I <> 1 then
Raise EArtPic32Usb.CreateFmt( 'Error performing USB write', []);
end;
function Pic32Usb_Read(
AHandle : THANDLE;
ABufferPtr : pointer;
ALengthBytes : integer ) : DWORD;
// Performs a Read using this handle. Returns the number of bytes read
var
I : integer;
begin
I := _MPUSBRead(
AHandle,
ABufferPtr,
DWORD( ALengthBytes ),
Result,
MillisecondPollingInterval );
if I <> 1 then
Raise EArtPic32Usb.CreateFmt( 'Error performing USB read', []);
end;
initialization
finalization
If UsbDllHandle <> 0 then
FreeLibrary(UsbDllHandle)
end.
Not a question, just a statement to help anyone else who might spend hours getting the Microchip PIC USB DLL to work properly with Unicode.
It expects several strings, and although these are simple PAnsiChar
, getting the right combination of DLL call convention took me ages. There are a lot of people on the 'net using Delphi (non-Unicode) with this DLL and getting away with murder.
unit UArtPic32USBDriver;
interface
uses
Windows,
SysUtils,
UArtGeneralHwDefs;
type
EArtPic32Usb = class( EArtGeneralHw );
function Pic32Usb_GetDllVersion : integer;
// Returns a number representing the DLL version.
function Pic32Usb_GetDeviceCount( const AVendorProductID : string ) : integer;
// Returns the number of devices with this vendor ID
function Pic32Usb_Open(
AInstance : DWORD;
const AVendorProductID, AEndpointID : string;
ADirectionCode : integer;
ARaise : boolean ) : THANDLE;
// Opens an endpoint. Can raise an exception if no valid handle is returned.
procedure Pic32Usb_Close( AHandle : THandle );
// Closes the device
function Pic32Usb_Write(
AHandle : THANDLE;
ABufferPtr : pointer;
ALengthBytes : integer ) : DWORD;
// Performs a write using this handle. Returns the number of bytes written
function Pic32Usb_Read(
AHandle : THANDLE;
ABufferPtr : pointer;
ALengthBytes : integer ) : DWORD;
// Performs a Read using this handle. Returns the number of bytes read
const
MP_WRITE = 0;
MP_READ = 1;
implementation
var
_MPUSBGetDLLVersion : function () :DWORD; cdecl stdcall;
// Number of vid & pid matching USB Devices
_MPUSBGetDeviceCount : function( pVID_PID : PAnsiChar ) : DWORD; cdecl;
_MPUSBOpen : function ( instance : DWORD;
pVID_PID : PAnsiChar;
pEP : PAnsiChar;
dwDir : DWORD;
dwReserved : DWORD ) : THANDLE; cdecl;
_MPUSBClose : function ( handle :THANDLE ) : DWORD; cdecl;
_MPUSBRead : function ( handle : THANDLE;
pData : pointer;
dwLen : DWORD;
var pLength : DWORD;
dwMilliseconds : DWORD ) : DWORD; cdecl;
_MPUSBReadInt : function ( handle : THANDLE;
var pData : pointer;
dwLen : DWORD;
var pLength : PDWORD;
dwMilliseconds : DWORD ) : DWORD; cdecl;
_MPUSBWrite : function ( handle : THANDLE;
pData : pointer;
dwLen : DWORD;
var pLength : DWORD;
dwMilliseconds : DWORD ) : DWORD; cdecl;
UsbDllHandle : THandle = 0;
const
MillisecondPollingInterval = 100; //Represents 1 ms is hardware
CharBufSize = 64;
type
TAnsiCharBuf64 = array[0..CharBufSize-1] of AnsiChar;
function LoadDLL : THandle;
var
S : string;
begin
S := 'mpusbapi.dll';
UsbDllHandle := LoadLibrary( PChar(S) );
If UsbDllHandle = 0 then
Raise EArtPic32Usb.CreateFmt(
'The usb library is required but cannot be loaded. Check that it is installed. (%s)',
[S]
);
@_MPUSBGetDLLVersion := GetProcAddress(UsbDllHandle,'_MPUSBGetDLLVersion');
Assert(@_MPUSBGetDLLVersion <> nil);
@_MPUSBGetDeviceCount := GetProcAddress(UsbDllHandle,'_MPUSBGetDeviceCount');
Assert(@_MPUSBGetDeviceCount <> nil);
@_MPUSBOpen := GetProcAddress(UsbDllHandle,'_MPUSBOpen');
Assert(@_MPUSBOpen <> nil);
@_MPUSBClose := GetProcAddress(UsbDllHandle,'_MPUSBClose');
Assert(@_MPUSBClose <> nil);
@_MPUSBRead := GetProcAddress(UsbDllHandle,'_MPUSBRead');
Assert(@_MPUSBRead <> nil);
@_MPUSBReadInt := GetProcAddress(UsbDllHandle,'_MPUSBReadInt');
Assert(@_MPUSBReadInt <> nil);
@_MPUSBWrite := GetProcAddress(UsbDllHandle,'_MPUSBWrite');
Assert(@_MPUSBWrite <> nil);
Result := UsbDllHandle;
end;
procedure NeedDLL;
begin
If UsbDllHandle = 0 then
LoadDll;
end;
function Pic32Usb_GetDllVersion : integer;
// Returns a number representing the DLL version.
begin
NeedDLL;
Result := _MPUSBGetDLLVersion();
end;
function Pic32Usb_GetDeviceCount( const AVendorProductID : string ) : integer;
// Returns the number of devices with this vendor ID
var
bufVendorProductID : TAnsiCharBuf64;
begin
NeedDLL;
StrPCopy( bufVendorProductID, AnsiString(AVendorProductID) );
Result := _MPUSBGetDeviceCount( @bufVendorProductID );
end;
function Pic32Usb_Open(
AInstance : DWORD;
const AVendorProductID, AEndpointID : string;
ADirectionCode : integer;
ARaise : boolean ) : THANDLE;
// Opens an endpoint. Can raise an exception if no valid handle is returned.
var
bufVendorProductID, bufEndpointID : TAnsiCharBuf64;
begin
NeedDLL;
StrPCopy( bufVendorProductID, AnsiString(AVendorProductID) );
StrPCopy( bufEndpointID, AnsiString(AEndpointID) );
Result := _MPUSBOpen(
AInstance,
@bufVendorProductID,
@bufEndpointID,
DWORD(ADirectionCode),
0 );
if Result = 0 then
If ARaise then
Raise EArtPic32Usb.CreateFmt(
'Unable to open USB device "%s", endpoint "%s"', [AVendorProductID, AEndpointID]);
end;
procedure Pic32Usb_Close( AHandle : THandle );
begin
If UsbDllHandle <> 0 then
_MPUSBClose( AHandle );
end;
function Pic32Usb_Write(
AHandle : THANDLE;
ABufferPtr : pointer;
ALengthBytes : integer ) : DWORD;
// Performs a write using this handle. Returns the number of bytes written
var
I : integer;
begin
I := _MPUSBWrite(
AHandle,
ABufferPtr,
DWORD( ALengthBytes ),
Result,
MillisecondPollingInterval );
if I <> 1 then
Raise EArtPic32Usb.CreateFmt( 'Error performing USB write', []);
end;
function Pic32Usb_Read(
AHandle : THANDLE;
ABufferPtr : pointer;
ALengthBytes : integer ) : DWORD;
// Performs a Read using this handle. Returns the number of bytes read
var
I : integer;
begin
I := _MPUSBRead(
AHandle,
ABufferPtr,
DWORD( ALengthBytes ),
Result,
MillisecondPollingInterval );
if I <> 1 then
Raise EArtPic32Usb.CreateFmt( 'Error performing USB read', []);
end;
initialization
finalization
If UsbDllHandle <> 0 then
FreeLibrary(UsbDllHandle)
end.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我会将其作为临时答案发布。 @Brian Frost 可以发布完整的代码。
这个故事的要点是,当您处理需要它的驱动程序时,使用单字节 ANSI 字符串。
I'll post this as temporary answer. @Brian Frost can post the full code.
The gist of the story is to use single byte ANSI string when you are dealing with a driver that expects it.