Free Pascal help please

My x64 port of InpOut32
Post Reply
Zaaphod
New User
Posts: 11
Joined: Tue Jul 12, 2016 1:06 am

Free Pascal help please

Post by Zaaphod »

I have an old Turbo Pascal DOS program I am trying to port over to windows using Free Pascal. I have got everything working except control of the parallel port, which used to be so easy, but now I find it nearly impossible. I do not know if ImpOut32 (x64) will help me. I downloaded it and tried to compile a sample unit called dlportio.pas and I just get a lot of errors that I do not understand.

Code: Select all

dlportio.pas(5,10) Error: Found declaration: DlPortReadPortUchar(LongInt):Byte; StdCall;
dlportio.pas(30,10) Error: Calling convention doesn't match forward
I have no experience with using a .DLL with pascal and I'm hoping someone here will be kind enough to get me started. My program is not a 'windows application' with forms and all that. It's just a basic program that uses free pascal graph unit for a simple graphics screen. I'm not using lazerus, I can't get my program to compile with that. I'm using Freepascal with the text IDE, and everything works fine except parallel port. I've managed to get the serial port to work by using a free pascal serial unit by synapse, but it doesn't use any DLLs that I have to deal with.. I just put in uses serial; and I can use it's functions and procedures.

Any help getting this to work would be GREATLY appreciated.
User avatar
phil
Site Admin
Posts: 7611
Joined: Sun Apr 06, 2003 11:12 pm

Re: Free Pascal help please

Post by phil »

As well as showing the errors, t might be a good idea to paste the whole file or provide a link to it (I don't believe there are any pascal samples with InpOut32?!) (NOTE: URL posting s disabled for new users (5 posts to prevent spam bots))....

But from the error, it looks like your using an incorrect calling convention. I've not used Pascal for about 25yrs (back in the DOS days with Turbo Pascal) and it might take me a while to get out of my c++ mindset but generally in Windows, calls to DLLs can use various calling conventions which at a really simplistic level determine how the parameters are pushed onto the stack.

I'll have to grab a copy of free pascal to have a play around (when I get a spare moment!) so if anyone else can help, let me know. Unfortunately this forum is a bit quiet so I don't expect anyone else to help so I will do my best!

Thanks,
Phil
--[ Phil ]--
--[ Administrator & XMBC Author ]--
Logitech G9/G604/M720/MX518, Microsoft Intellimouse, Trust 16341 BT Mouse
Windows 10 x64, AMD Ryzen 5900x, MSI x570 Tomahawk, 32GB DDR4,
nVidia RTX 2070s, Evo 970 1Tb NVME, 2x2TB WD Black (RAID1)
Zaaphod
New User
Posts: 11
Joined: Tue Jul 12, 2016 1:06 am

Re: Free Pascal help please

Post by Zaaphod »

Thank you for any help you can offer. It's the last piece to the puzzle and I will have full functionality again if I can get it to work. Until I'm able to post files, I would he happy to email you the sample I have... I'm not sure where I got it from. There was mention of inpout32 here:

http://wiki.freepascal.org/Hardware_Acc ... or_Windows
but I can't understand the example given.
Zaaphod
New User
Posts: 11
Joined: Tue Jul 12, 2016 1:06 am

Re: Free Pascal help please

Post by Zaaphod »

This isn't really that big, I guess I can just paste it in here. I'm thinking I probably have the syntax wrong, this might be a delphi example, I don't know what the syntax would be for freepascal running in Turbo Pascal compatibility mode with the text based IDE.

Code: Select all

unit DLPortio ;

interface

Function DlPortReadPortUchar(Port:LongInt):byte; stdcall;
Function DlPortReadPortUshort(Port:LongInt):SmallInt; stdcall;
Function DlPortReadPortUlong(Port:LongInt):LongInt; stdcall;

Procedure DlPortReadPortBufferUchar(Port:LongInt;
var Buffer:Pointer; Count:LongInt); stdcall;
Procedure DlPortReadPortBufferUshort(Port:LongInt;
var Buffer:Pointer; Count:LongInt); stdcall;
Procedure DlPortReadPortBufferUlong(Port:LongInt;
var Buffer:Pointer; Count:LongInt); stdcall;

Procedure DlPortWritePortUchar(Port:LongInt; Value:byte); stdcall;
Procedure DlPortWritePortUshort(Port:LongInt; Value:SmallInt); stdcall;
Procedure DlPortWritePortUlong(Port:LongInt; Value:LongInt); stdcall;

Procedure DlPortWritePortBufferUchar(Port:LongInt;
var Buffer:Pointer; Count:LongInt); stdcall;
Procedure DlPortWritePortBufferUshort(Port:LongInt;
var Buffer:Pointer; Count:LongInt); stdcall;
Procedure DlPortWritePortBufferUlong(Port:LongInt;
var Buffer:Pointer; Count:LongInt); stdcall;

implementation

Function DlPortReadPortUchar; external 'inpoutx64.DLL';
Function DlPortReadPortUshort; external 'inpoutx64.DLL';
Function DlPortReadPortUlong; external 'inpoutx64.DLL';

Procedure DlPortReadPortBufferUchar; external 'inpoutx64.DLL';
Procedure DlPortReadPortBufferUshort; external 'inpoutx64.DLL';
Procedure DlPortReadPortBufferUlong; external 'inpoutx64.DLL';

Procedure DlPortWritePortUchar; external 'inpoutx64.DLL';
Procedure DlPortWritePortUshort; external 'inpoutx64.DLL';
Procedure DlPortWritePortUlong; external 'inpoutx64.DLL';

Procedure DlPortWritePortBufferUchar; external 'inpoutx64.DLL';
Procedure DlPortWritePortBufferUshort; external 'inpoutx64.DLL';
Procedure DlPortWritePortBufferUlong; external 'inpoutx64.DLL';

end.

Code: Select all

Errors:

dlportio.pas(29,10) Error: Calling convention doesn't match forward
dlportio.pas(5,10) Error: Found declaration: DlPortReadPortUchar(LongInt):Byte; StdCall;
dlportio.pas(30,10) Error: Calling convention doesn't match forward
dlportio.pas(6,10) Error: Found declaration: DlPortReadPortUshort(LongInt):SmallInt; StdCall;
dlportio.pas(31,10) Error: Calling convention doesn't match forward
dlportio.pas(7,10) Error: Found declaration: DlPortReadPortUlong(LongInt):LongInt; StdCall;
dlportio.pas(33,11) Error: Calling convention doesn't match forward
dlportio.pas(9,11) Error: Found declaration: DlPortReadPortBufferUchar(LongInt;var Pointer;LongInt);
dlportio.pas(34,11) Error: Calling convention doesn't match forward
dlportio.pas(11,11) Error: Found declaration: DlPortReadPortBufferUshort(LongInt;var Pointer;LongInt); 
dlportio.pas(35,11) Error: Calling convention doesn't match forward
dlportio.pas(13,11) Error: Found declaration: DlPortReadPortBufferUlong(LongInt;var Pointer;LongInt);
dlportio.pas(37,11) Error: Calling convention doesn't match forward
dlportio.pas(16,11) Error: Found declaration: DlPortWritePortUchar(LongInt;Byte); StdCall;
dlportio.pas(38,11) Error: Calling convention doesn't match forward
dlportio.pas(17,11) Error: Found declaration: DlPortWritePortUshort(LongInt;SmallInt); StdCall;
dlportio.pas(39,11) Error: Calling convention doesn't match forward
dlportio.pas(18,11) Error: Found declaration: DlPortWritePortUlong(LongInt;LongInt); StdCall;
dlportio.pas(41,11) Error: Calling convention doesn't match forward
dlportio.pas(20,11) Error: Found declaration: DlPortWritePortBufferUchar(LongInt;var Pointer;LongInt);
dlportio.pas(42,11) Error: Calling convention doesn't match forward
dlportio.pas(22,11) Error: Found declaration: DlPortWritePortBufferUshort(LongInt;var Pointer;LongInt);
dlportio.pas(43,11) Error: Calling convention doesn't match forward
dlportio.pas(24,11) Error: Found declaration: DlPortWritePortBufferUlong(LongInt;var Pointer;LongInt);
dlportio.pas(47) Fatal: There were 24 errors compiling module, stopping
dlportio.pas(0) Fatal: Compilation aborted
Zaaphod
New User
Posts: 11
Joined: Tue Jul 12, 2016 1:06 am

Re: Free Pascal help please

Post by Zaaphod »

well I'm maybe making progress... I hope. I did get it to compile! YAY. But I get a runtime error when I try to run my program... Boo! Please forgive me if posting my code inline is against some forum rules.. I'm just so close, yet can't quite get it to work.

I get
The application was unable to start correctly (0xc000007b). click ok to close the application.
then when it comes back into freepascal compiler, I have
Program Exited with exitcode=123
Here's the unit that compiles:

Code: Select all

unit inpoutx64;

interface

Function DlPortReadPortUchar(Port:LongInt):byte;
Function DlPortReadPortUshort(Port:LongInt):SmallInt;
Function DlPortReadPortUlong(Port:LongInt):LongInt;

Procedure DlPortReadPortBufferUchar(Port:LongInt;
var Buffer:Pointer; Count:LongInt);
Procedure DlPortReadPortBufferUshort(Port:LongInt;
var Buffer:Pointer; Count:LongInt);
Procedure DlPortReadPortBufferUlong(Port:LongInt;
var Buffer:Pointer; Count:LongInt);

Procedure DlPortWritePortUchar(Port:LongInt; Value:byte);
Procedure DlPortWritePortUshort(Port:LongInt; Value:SmallInt);
Procedure DlPortWritePortUlong(Port:LongInt; Value:LongInt);

Procedure DlPortWritePortBufferUchar(Port:LongInt;
var Buffer:Pointer; Count:LongInt);
Procedure DlPortWritePortBufferUshort(Port:LongInt;
var Buffer:Pointer; Count:LongInt);
Procedure DlPortWritePortBufferUlong(Port:LongInt;
var Buffer:Pointer; Count:LongInt);

implementation

Function DlPortReadPortUchar; external 'inpoutx64.DLL';
Function DlPortReadPortUshort; external 'inpoutx64.DLL';
Function DlPortReadPortUlong; external 'inpoutx64.DLL';

Procedure DlPortReadPortBufferUchar; external 'inpoutx64.DLL';
Procedure DlPortReadPortBufferUshort; external 'inpoutx64.DLL';
Procedure DlPortReadPortBufferUlong; external 'inpoutx64.DLL';

Procedure DlPortWritePortUchar; external 'inpoutx64.DLL';
Procedure DlPortWritePortUshort; external 'inpoutx64.DLL';
Procedure DlPortWritePortUlong; external 'inpoutx64.DLL';

Procedure DlPortWritePortBufferUchar; external 'inpoutx64.DLL';
Procedure DlPortWritePortBufferUshort; external 'inpoutx64.DLL';
Procedure DlPortWritePortBufferUlong; external 'inpoutx64.DLL';

end.
Here's my programs:

Code: Select all

Program porttest;
Uses inpoutx64;
Var Portnum:integer;
    Portdata,portdata2,portdata3:byte;
Begin
Write('Enter Port Number: ');
Readln(portnum);
portdata:=DlPortReadPortUchar(portnum);
portdata2:=DlPortReadPortUchar(portnum+1);
portdata3:=DlPortReadPortUchar(portnum+2);

writeln('Port ',portnum,': ',Portdata,'     ',Portdata2,'     ',Portdata3);

Write('Enter New Data: ');
readln(portdata);
DlPortWritePortUchar(portnum,portdata);
portdata:=DlPortReadPortUchar(portnum);
portdata2:=DlPortReadPortUchar(portnum+1);
portdata3:=DlPortReadPortUchar(portnum+2);
writeln(Portdata,'     ',Portdata2,'     ',Portdata3);
readln;
end.
I put inpoutx64.dll in the same folder as my source and EXE files. I'm not sure what could be wrong. I tried running it on windows 10 x64 and windows 7 x64 with the same results. Am I missing something fundamental? am I supposed to do something to windows to allow this dll to be used?

Any help is greatly appreciated!
User avatar
phil
Site Admin
Posts: 7611
Joined: Sun Apr 06, 2003 11:12 pm

Re: Free Pascal help please

Post by phil »

Quick question, have you run the Installdriver.exe program supplied with the DLLs? Otherwise, maybe the problem is that the driver failed to install and load.

I don't see any calls to IsInpOutDriverOpen() which will tell you if it successfully managed to load and communicate with the driver?

I also presume your using the right DLL (x64 dll with x64 compiled program)?
According to windows, error 123 means "The filename, directory name, or volume label syntax is incorrect."

Thanks,
Phil
--[ Phil ]--
--[ Administrator & XMBC Author ]--
Logitech G9/G604/M720/MX518, Microsoft Intellimouse, Trust 16341 BT Mouse
Windows 10 x64, AMD Ryzen 5900x, MSI x570 Tomahawk, 32GB DDR4,
nVidia RTX 2070s, Evo 970 1Tb NVME, 2x2TB WD Black (RAID1)
Zaaphod
New User
Posts: 11
Joined: Tue Jul 12, 2016 1:06 am

Re: Free Pascal help please

Post by Zaaphod »

Oh, I think I made a mistake and used X64 but it's an x86 program. It's the program that determines which version you use not the host computer I take it. I switched to inpout32 and now I can compile it AND run it... however I'm still not getting the expected results.

I added isinpoutdriveropen() as you suggested.
IsInpOutDriverOpen and IsXP64Bit both seem to work. I tried running on a different machine and IsInpOutDriverOpen came back false, but then I installed the driver and now it comes back true, I think I must be communicating with the DLL now. I think I may have a little issue with my variable types... I tried my best to match up freepascal types with those in the examples, but I'm not entirely sure about them.

I modified an old turbo pascal program I wrote that simply asked for a port number, displayed the data on the port, asked for new data, then wrote the new data to the port and then read back the port to verify it.

For some reason this is not working when using Freepascal and inpout32. I get all kinds of odd numbers back from the port.. and writing to it seems to have no effect. I'm sure I'm just doing something wrong. I was trying to figure out what's happening, so instead of reading the port once, I read it 20 times, nothing should be changing the port in between the reads, yet I get all kinds of different results. Most of the time I get back $FF but sometimes there are other results.. some 0s, and some other numbers... even from consecutive reads with no write attempted. I can make about 3 attempts to write to the port and then I get a general protection fault.

I am trying to access a standard parallel port at $378, I'm entering it in as hex like I always used to with the Turbo pascal version of this little program. Device manager says I have a parrallel port and it's address is at 378 - 37F. I'm not sure what I am doing wrong. it's probably something dumb. At least it compiles and runs now.. just doesn't do what I want it to yet.

Thank you very much for trying to help me

Here is my current version of inpout32 unit for freepascal

Code: Select all

unit inpout32;

interface
Function IsInpOutDriverOpen:boolean;
Function IsXP64Bit:boolean;

Function  Inp32(Port:SmallInt):Byte;
Procedure Out32(Port:SmallInt; Value:Byte);

Function DlPortReadPortUchar(Port:SmallInt):Byte;
Function DlPortReadPortUshort(Port:SmallInt):Word;
Function DlPortReadPortUlong(Port:SmallInt):Cardinal;

Procedure DlPortWritePortUchar(Port:SmallInt; Value:Byte);
Procedure DlPortWritePortUshort(Port:SmallInt; Value:Word);
Procedure DlPortWritePortUlong(Port:SmallInt; Value:Cardinal);

implementation
Function IsInpOutDriverOpen; external 'inpout32.DLL';
Function IsXP64Bit; external 'inpout32.DLL';

Function Inp32; external 'inpout32.DLL';
Procedure Out32; external 'inpout32.DLL';

Function DlPortReadPortUchar; external 'inpout32.DLL';
Function DlPortReadPortUshort; external 'inpout32.DLL';
Function DlPortReadPortUlong; external 'inpout32.DLL';

Procedure DlPortWritePortUchar; external 'inpout32.DLL';
Procedure DlPortWritePortUshort; external 'inpout32.DLL';
Procedure DlPortWritePortUlong; external 'inpout32.DLL';
end.

Here is my test program:

Code: Select all

Program porttest;
Uses inpout32;
Var IsInpOutOpen,IsXP64:boolean;
    Portnum:smallInt;
    Port_data:byte;

Procedure Readloop;
var
  loop_count:integer;
  port_read:byte;
Begin
  for loop_count:=1 to 2 do
    begin
      port_read:=0;
      port_read:=inp32(portnum);
      {port_read:=DlPortReadPortUchar(portnum);}
      writeln('Port ',portnum,': ',Port_read);
    end;
end;

Begin
  IsInpOutOpen:=IsInpOutDriverOpen;
  IsXP64:=IsXP64Bit;
  writeln('Is InpOut Driver Open: ',IsInpOutOpen,'  Is 64Bit: ',IsXP64);
  Write('Enter Port Number: ');
  Readln(portnum);
  Readloop;
  repeat
    Begin
      Write('Enter New Data: ');
      readln(port_data);
      DlPortWritePortUchar(portnum,port_data);
      {out32(portnum,port_data);}
      readloop;
    end
  Until
   Port_data=$0;
end.
User avatar
phil
Site Admin
Posts: 7611
Joined: Sun Apr 06, 2003 11:12 pm

Re: Free Pascal help please

Post by phil »

Have you tried using Inp32() rather than DLPortIOReadPortUChar() - they should be the same but maybe there is a problem with the later.

What "mode" is your port in? If I recall, the parallel port can have 3 modes and it needs to be in the write mode to read from the port - but its been a long time (>20 years) since I did this myself so my memory is a bit rusty. If your getting random values back, that sounds like floating input to me (i.e. not tied high or low) but could also be that the port is not in 8 bit read/write mode. Back in the day you could set the mode in the BIOS but these days I don't know!

Have you tried using any of my test programs (for example, the VB.NET/C# tests) as they should allow you to read the value of a port - and you could use that to see if you get the same results as you do in your pascal program.

Thanks,
Phil
--[ Phil ]--
--[ Administrator & XMBC Author ]--
Logitech G9/G604/M720/MX518, Microsoft Intellimouse, Trust 16341 BT Mouse
Windows 10 x64, AMD Ryzen 5900x, MSI x570 Tomahawk, 32GB DDR4,
nVidia RTX 2070s, Evo 970 1Tb NVME, 2x2TB WD Black (RAID1)
Zaaphod
New User
Posts: 11
Joined: Tue Jul 12, 2016 1:06 am

Re: Free Pascal help please

Post by Zaaphod »

Phil,

Thank you for the suggestions.

I have tried both inp32() and Out32(), I get identical results.

Perhaps you are on to something with the port mode. The parallel ports I am used to were the old ones that you could write to at any time.. then read back what you wrote, and if you forced high pins to be low when you did the read it would read what was on the pins, not what it thought you wrote. However perhaps the other modes don't work like that, maybe they are just tristate floating pins.

I am using the motherboard build in port so it's quite possible it is in some epp mode or something.. I will check the bios for options. Otherwise perhaps I should get a usb parallel adapter just to see if I can get that to work. as I recall motherboard built on ports were always different somehow than ports on cards.

I did not think to try your test programs.. I see now you have precompiled EXEs in them. Thanks for the idea, I will give it a try!

I'll report back on my progress, and thank you again for your assistance!
User avatar
phil
Site Admin
Posts: 7611
Joined: Sun Apr 06, 2003 11:12 pm

Re: Free Pascal help please

Post by phil »

Warning, InpOut32 does not work with any USB devices as far as I know!
Its all getting a bit old school - there are some PCI/PCIe cards that work (apparently).
--[ Phil ]--
--[ Administrator & XMBC Author ]--
Logitech G9/G604/M720/MX518, Microsoft Intellimouse, Trust 16341 BT Mouse
Windows 10 x64, AMD Ryzen 5900x, MSI x570 Tomahawk, 32GB DDR4,
nVidia RTX 2070s, Evo 970 1Tb NVME, 2x2TB WD Black (RAID1)
Zaaphod
New User
Posts: 11
Joined: Tue Jul 12, 2016 1:06 am

Re: Free Pascal help please

Post by Zaaphod »

I checked my bios settings, my parallel port is set to standard mode (SPP) I'm guessing that should work, it's how I always set my ISA cards. I guess it is getting to be old school, but it was such a convenient way to read a few bits and send out a few bits... no need to program an arduino and severely complicate things.

I tried the demo program, but it just flashes on the my screen and is gone before I can see anything at all.
Zaaphod
New User
Posts: 11
Joined: Tue Jul 12, 2016 1:06 am

Re: Free Pascal help please

Post by Zaaphod »

It just occurred to me that your demo program is a dos command program.. I did get it to work. at first I was getting the same results but I was putting in port $378 using a $ to indicate hex, but then I remembered that's a pascal thing... so I put in 888 for the port (decimal of 0x378) and I'm happy to report your demo program worked great! I was able to write anything I want to the port and then read it back and it was correct. So this proves that inpout32 is working with my motherboard parallel port! My program still doesn't work.. my current version gives me 255 as a result no matter what I do. I am wondering if my port variable is not defined correctly.
Zaaphod
New User
Posts: 11
Joined: Tue Jul 12, 2016 1:06 am

Re: Free Pascal help please

Post by Zaaphod »

I finally got it working!!! Thank you for all your help here. It was a great help to get your demo working, because then I knew my parallel port was working with InpOut32 and that InpOut32 was also working. I got some help from Marc on the freepascal mailing list about calling C libraries from pascal. I had to define them as C libraries, once I did that, everything started working correctly!

Here's a link that explains calling C libraries from pascal http://www.freepascal.org/docs-html/ref/refsu72.html

I also made a small github repository with a FreePascal test program, Just in case anyone searching for a freepascal solution, perhaps they will find it. You have my permission to include my sample pascal program on your web page as well, feel free to modify it as you see fit, It might help someone else.
https://github.com/Zaaphod/FPC-Parallel-Port

I was able to get the following to work correctly:
IsInpOutDriverOpen
IsXP64Bit
Inp32
Out32
DlPortReadPortUchar
DlPortWritePortUchar
DlPortReadPortUshort
DlPortWritePortUshort

The variables between C and Pascal are not defined in the same way, for example a Ushort in C is 16 bits, but in pascal a shortint is only 8 bits, and a smallint is 16bits but signed, so I used a word which is unsigned and 16bits. I could not get DLPortWriteUlong to work correctly although for some reason DLPortReadULong did work if I defined it as a cardinal (4 byte unsigned) It's probably a variable mismatch issue

I also saw in the test C program procedures GetPhysLong and SetPhysLong. I'm not really sure what those are for or how to test them.. I just saw they were defined, but not how they were used.

Thanks Again for your help with this and also Thank you very much for making it work on 64bit machines! My ancient program is saved and I don't need to rewrite the entire thing (19,785 lines of code!) to use modern computers :D :D :D
User avatar
phil
Site Admin
Posts: 7611
Joined: Sun Apr 06, 2003 11:12 pm

Re: Free Pascal help please

Post by phil »

Great news - well done. Sorry I didn't get round to looking at freepascal myself, but I suspect that its was probably a benefit for you to figure it out with the little prompting I did manage.

The problem with DLPortWriteUlong I believe is a bug in the driver - and the only way of fixing it would require the driver be re-signed - which I can not do :( so it has gone unfixed for some time.

To be honest, I cant remember what GetPhysLong and SetPhysLong are for either, I suspect I "borrowed" them from the (now defunct?) WinRing0 project which offered the same sort of thing as InpOut32/x64

Thanks,
Phil
--[ Phil ]--
--[ Administrator & XMBC Author ]--
Logitech G9/G604/M720/MX518, Microsoft Intellimouse, Trust 16341 BT Mouse
Windows 10 x64, AMD Ryzen 5900x, MSI x570 Tomahawk, 32GB DDR4,
nVidia RTX 2070s, Evo 970 1Tb NVME, 2x2TB WD Black (RAID1)
Zaaphod
New User
Posts: 11
Joined: Tue Jul 12, 2016 1:06 am

Re: Free Pascal help please

Post by Zaaphod »

I really don't have a use for DLPortWriteULong anyway. I'm just happy to get it working! Thanks again for your help.
Post Reply