Paul E. Schoen
2009-11-29 09:27:57 UTC
I have been working on an application which sends and receives information
directly via a USB connection, using a generic interface (rather than the
CDC, which emulates a COM port). The USB device enumerates properly and I
can communicate with it using a DLL which is provided by Microchip. I found
some demo code which requested information via a DLL call and displayed it
in a MessageBox. But when I instead tried to add the same string to a TMemo
I got an AV, and when I used the debugger the Memo1 component was not
accessible. When I clicked another button which performed other functions,
the Memo updated normally with no AV and the debugger showed the component
normally. Here are some code fragments:
procedure TForm1.btInfoClick(Sender: TObject);
var S: String;
begin
send_buf[0]:= READ_VERSION;
send_buf[1]:= 4; // Expected length of the result
Memo1.Lines.Add('Hello from Info'); // This is OK
RecvLength:=4;
if(SendReceivePacket(send_buf,1,receive_buf,RecvLength,100,100) = 1) then
begin
S := IntToStr(receive_buf[0])+IntToStr(receive_buf[1]);
ShowMessage(S); // This is OK
if(receive_buf[0] = READ_VERSION) then begin
ShowMessage('Firmware version : '+ IntToStr(receive_buf[3])+'.'+
IntToStr(receive_buf[2])); end;
Memo1.lines.add(S); end // This causes an AV
else begin
ShowMessage('USB Error'); end;
Memo1.Lines.Add('Goodbye from Info'); // This causes an AV
end;
procedure TForm1.btConnectClick(Sender: TObject);
var
i: Integer;
begin // Read Firmware version
selection:=_MPUSBGetDLLVersion;
Memo1.lines.add(Format('%0.8x',[selection])); // This is OK
selection := 0;
for i := 0 to length(ComboBox1.Text) do
vid_pid[i] := ComboBox1.Text[i+1];
if (_MPUSBGetDeviceCount(vid_pid)=0) then begin // This is OK
Memo1.lines.add(Format('- Device %s not connected', [vid_pid]) );
exit;
end
else
Memo1.lines.add(Format('Device %s connected!', [vid_pid]) );
end;
The prototype for the function in the DLL is:
function _MPUSBRead(handle:THANDLE;var pData:PBYTE;
dwLen:DWORD;var pLength:DWORD;
dwMilliseconds:DWORD):DWORD;stdcall;
external 'mpusbapi.dll';
I have the source code for the DLL in Borland C++ and I didn't see anything
suspicious. But sometimes the AV seems to occur in a thread and not in the
Delphi code. The DLL uses asynchronous IO with a ReadFile(),
WaitForSingleObject and GetOverlappedResult, with a 100 mSec timeout as set
in the SendReceivePacket call above.
I even added a second Memo and an Edit box and it has the same problem. It
seems that once the DLL executes, the components in the form go out of
scope and do not return until the btInfoClick procedure exits.
I was able to do this:
const fm_UpdateMemo = wm_User + 1; //message constant
message fm_UpdateMemo;
In the btInfoClick handler:
PostMessage(Form1.Handle, fm_UpdateMemo, 0, LParam(0));
which called fmUpdateMemo which has the line
procedure TForm1.fmUpdateMemo(var Message: TMessage);
begin
Memo1.Lines.Add('Goodbye from Info');
end;
If I used btInfo as the LParam I got an AV.
Any ideas? Thanks!
Paul
directly via a USB connection, using a generic interface (rather than the
CDC, which emulates a COM port). The USB device enumerates properly and I
can communicate with it using a DLL which is provided by Microchip. I found
some demo code which requested information via a DLL call and displayed it
in a MessageBox. But when I instead tried to add the same string to a TMemo
I got an AV, and when I used the debugger the Memo1 component was not
accessible. When I clicked another button which performed other functions,
the Memo updated normally with no AV and the debugger showed the component
normally. Here are some code fragments:
procedure TForm1.btInfoClick(Sender: TObject);
var S: String;
begin
send_buf[0]:= READ_VERSION;
send_buf[1]:= 4; // Expected length of the result
Memo1.Lines.Add('Hello from Info'); // This is OK
RecvLength:=4;
if(SendReceivePacket(send_buf,1,receive_buf,RecvLength,100,100) = 1) then
begin
S := IntToStr(receive_buf[0])+IntToStr(receive_buf[1]);
ShowMessage(S); // This is OK
if(receive_buf[0] = READ_VERSION) then begin
ShowMessage('Firmware version : '+ IntToStr(receive_buf[3])+'.'+
IntToStr(receive_buf[2])); end;
Memo1.lines.add(S); end // This causes an AV
else begin
ShowMessage('USB Error'); end;
Memo1.Lines.Add('Goodbye from Info'); // This causes an AV
end;
procedure TForm1.btConnectClick(Sender: TObject);
var
i: Integer;
begin // Read Firmware version
selection:=_MPUSBGetDLLVersion;
Memo1.lines.add(Format('%0.8x',[selection])); // This is OK
selection := 0;
for i := 0 to length(ComboBox1.Text) do
vid_pid[i] := ComboBox1.Text[i+1];
if (_MPUSBGetDeviceCount(vid_pid)=0) then begin // This is OK
Memo1.lines.add(Format('- Device %s not connected', [vid_pid]) );
exit;
end
else
Memo1.lines.add(Format('Device %s connected!', [vid_pid]) );
end;
The prototype for the function in the DLL is:
function _MPUSBRead(handle:THANDLE;var pData:PBYTE;
dwLen:DWORD;var pLength:DWORD;
dwMilliseconds:DWORD):DWORD;stdcall;
external 'mpusbapi.dll';
I have the source code for the DLL in Borland C++ and I didn't see anything
suspicious. But sometimes the AV seems to occur in a thread and not in the
Delphi code. The DLL uses asynchronous IO with a ReadFile(),
WaitForSingleObject and GetOverlappedResult, with a 100 mSec timeout as set
in the SendReceivePacket call above.
I even added a second Memo and an Edit box and it has the same problem. It
seems that once the DLL executes, the components in the form go out of
scope and do not return until the btInfoClick procedure exits.
I was able to do this:
const fm_UpdateMemo = wm_User + 1; //message constant
message fm_UpdateMemo;
In the btInfoClick handler:
PostMessage(Form1.Handle, fm_UpdateMemo, 0, LParam(0));
which called fmUpdateMemo which has the line
procedure TForm1.fmUpdateMemo(var Message: TMessage);
begin
Memo1.Lines.Add('Goodbye from Info');
end;
If I used btInfo as the LParam I got an AV.
Any ideas? Thanks!
Paul