Witam!
Problem dotyczy obsługi biblioteki karty wejść/wyjść - program napisany w c# zgłasza przy próbie zapisu/odczytu (wejść i/lub wyjść karty) następujący błąd: Nastąpiła próba odczytu lub zapisu pamięci chronionej. Często wskazuje to, że inna pamięć jest uszkodzona.
Producent karty dostarczył przykładowe programy w VC, VB, i Delphi. Ponieważ "konwersja" kodu źródłowego do C# nastąpiła właśnie z Delphi przedstawię dla porównana działający kod Delphi oraz C#.
Środowisko programistyczne:
Borland Turbo Delphi
SharpDevelop 2.2
VS2008
Kod programu napisanego w Delphi (istotne fragmenty):
{MODUŁ Driver}
Interface
type
PT_DEVLIST = Record
dwDeviceNum : Longint;
szDeviceName : array [0..49] of char;
nNumOfSubdevices : Smallint;
End;
PT_WritePortWord = Record
port : Smallint;
WordData : Smallint;
End;
Function DRV_DeviceGetNumOfList(Var NumOfDevices : Smallint) : Longint; stdcall;
Function DRV_DeviceGetList(Var DeviceList : PT_DEVLIST;
MaxEntries : Smallint; Var OutEntries : Smallint) : Longint; stdcall;
Function DRV_DeviceOpen(DeviceNum : Longint;
Var DriverHandle : Longint) : Longint; stdcall;
Function DRV_WritePortWord(DriverHandle : Longint;
Var lpWritePortWord : PT_WritePortWord) : Longint; stdcall;
implementation
Function DRV_DeviceGetNumOfList; external 'adsapi32.dll';
Function DRV_DeviceGetList; external 'adsapi32.dll';
Function DRV_DeviceOpen; external 'adsapi32.dll';
Function DRV_WritePortWord; external 'adsapi32.dll';
{ZMIENNE GLOBALNE}
type
lpDevList = ^PT_DEVLIST;
const MaxEntries = 255;
var
DeviceHandle : Longint;
DeviceList : array [0..MaxEntries] of PT_DEVLIST;
ErrCde : Longint;
szErrMsg : string[100];
pszErrMsg : Pchar = @szErrMsg;
bRun : Boolean;
gwPort : Smallint;
dwDeviceNum : Longint;
lpWritePortWord : PT_WritePortWord;
{GŁÓWNE OKNO PROGRAMU}
{procedura buduje listę wszystkich kart I/O producenta zainstalowanych w systemie}
procedure Tfrmstart.FormCreate(Sender: TObject);
var
MaxEntries, OutEntries : Smallint;
NumOfDevice : Smallint;
i, ii : Integer;
tempStr : String;
testRes : boolean;
begin
gwPort := $300;
bRun := False;
{ Here MaxEntries = OutEntries }
ErrCde := DRV_DeviceGetNumOfList(MaxEntries);
If (ErrCde <> 0) Then
begin
DRV_GetErrorMessage(ErrCde, pszErrMsg);
Response := Application.MessageBox(pszErrMsg, 'Error!!', MB_OK);
Exit;
end;
{ Add type of PC Laboratory Card }
ErrCde := DRV_DeviceGetList(DeviceList[0], MaxEntries, OutEntries);
If (ErrCde <> 0) Then
begin
DRV_GetErrorMessage(ErrCde, pszErrMsg);
Response := Application.MessageBox(pszErrMsg, 'Error!!', MB_OK);
Exit;
end;
For i := 0 To (MaxEntries - 1) do
begin
tempStr := '';
For ii := 0 To MaxDevNameLen do
tempStr := tempStr + DeviceList[i].szDeviceName[ii];
lstDevice.Items.Add(tempStr);
end;
labIOAddr.Enabled := False;
txtIOAddr.Enabled := False;
cmdRun.Enabled := False;
end;
{pobranie identyfikatora urządzenia i przejście do formatki sterującej}
procedure Tfrmstart.cmdRunClick(Sender: TObject);
var
I, Code: Integer;
begin
ErrCde := DRV_DeviceOpen(dwDeviceNum, DeviceHandle);
If (ErrCde <> 0) Then
begin
DRV_GetErrorMessage(ErrCde, pszErrMsg);
Response := Application.MessageBox(pszErrMsg, 'Error!!', MB_OK);
Exit;
end;
{ Get text from TEdit control }
Val('$' + txtIOAddr.Text, gwPort, Code);
FormRun.frmRun.Show;
end;
{dwDeviceNum jest ustawiane wybraniu właściwej karty - poniżej fragment kodu}
dwDeviceNum := DeviceList[lstDevice.ItemIndex].dwDeviceNum;
{OKNO STEROWANIA - FormRun}
{Zapis do karty - wysterowanie prekaźników na karcie}
procedure Tfrmrun.cmdWriteWordClick(Sender: TObject);
begin
lpWritePortWord.port := gwPort;
if (DoValue > $FFFF) then
lpWritePortWord.WordData := -1 {-1 in memory is 65535}
else
lpWritePortWord.WordData := DoValue;
ErrCde := DRV_WritePortWord(DeviceHandle, lpWritePortWord);
If (ErrCde <> 0) Then
begin
DRV_GetErrorMessage(ErrCde, pszErrMsg);
Response := Application.MessageBox(pszErrMsg, 'Error!!', MB_OK);
Exit;
end;
end;
Kod niedziałający w C#
public long DeviceHandle;
public class PT_DEVLIST
{
public long dwDeviceNum;
public char[] szDeviceName = new char[50];
public short nNumOfSubdevices;
}
public class PT_WritePortWord
{
public short port;
public short WordData;
}
public int OutEntries;
public static PT_WritePortWord lpWritePortWord;
public PT_DEVLIST[] DeviceList = new PT_DEVLIST[100];
[DllImport("adsapi32.dll")]
private static extern int DRV_WritePortWord(long DriverHandle, ref lpWritePortWord lpWritePortWord);
[DllImport("adsapi32.dll")]
private static extern int DRV_DeviceGetNumOfList(ref int NumeOfDevices);
private static extern int DRV_DeviceGetList( ref PT_DEVLIST DeviceList,
int MaxEntries, ref int OutEntries);
[DllImport("adsapi32.dll")]
private static extern int DRV_DeviceOpen( int DeviceNum, ref long DriverHandle);
{Procedura zapisu danych do karty}
void Button1Click(object sender, EventArgs e)
{
string nazwa = "";
int MaxEntries =100;
int err = DRV_DeviceGetNumOfList(ref MaxEntries);
if (err == 0)
{
PT_DEVLIST DeviceList1 = new PT_DEVLIST();
DeviceList[0] = DeviceList1;
if (err == 0)
{
for (int i= 1; i<49; i++)
{
nazwa+=DeviceList[0].szDeviceName[i].ToString();
//nazwa i dwDeviceNum nie zwraca żadnych wartości [???]
}
DRV_DeviceOpen(0, ref DeviceHandle).ToString();
PT_WritePortWord lpWritePortWord = new PT_WritePortWord();
lpWritePortWord.port = -16384;//0xc000 jest poprawnym adresem portu
lpWritePortWord.WordData = 1;
DRV_WritePortWord( DeviceHandle, ref lpWritePortWord);
//Powyższe zwraca opisany błąd [???]
}
else
MessageBox.Show("Błąd DevicGetList: "+err.ToString());
}
else
MessageBox.Show("Błąd DeviceGetNumeOfList: "+err.ToString());
Rozważałem jako możliwe przyczyny - niewłaściwe typy zmiennych, adres portów etc.
Może komuś coś się rzuci w oczy :-)
Pozdrawiam