Beginning the Parallel Port in VC++

My x64 port of InpOut32
Post Reply
satiagraha
New User
Posts: 5
Joined: Tue Jul 27, 2010 4:42 am

Beginning the Parallel Port in VC++

Post by satiagraha »

Hello

First of all, I'm working on Win7 64-bit with Visual Studio C++ 2010 (the 2010 shouldn't really be different from any other VC++ after .NET, right?)

Anyways, I've very new at this and from what I understand, to speak to the parallel port on a low-level (a.k.a, to send specific bits to it on command), I need a kernal-mode driver that gives me functions to call to do that. This is where your wonderful kernal-mode driver comes in. My first question is real basic, the driver itself is the .dll file: inpout32.dll, right?

If I'm on a 64-bit OS, but I'm writing 32-bit applications, can I use inpout32.dll and not inpout64.dll?

Also, if I understood correctly, to "install" the driver so that I can call the functions in my program:
  1. I had to download inpout32.dll, inpout32.h, inpout32.lib, and InstallDriver.exe.
  2. I run the InstallDriver.exe (I got a successful installation message).
  3. I put the inpout32.h header file in my program code directory and #include it.
Once those steps have happened, I can call the functions, i.e.:

Code: Select all

bool bDLoad = IsInpOutDriverOpen();
if (bDLoad==true) chkDriver->Checked=1;
So if everything that I've done so far is correct, then I now arrive at compile errors:
Form1.h(201): error C3861: 'IsInpOutDriverOpen': identifier not found
and then a bunch of syntax errors identical to those mentioned in the pinned topic InpOut32.h has syntax errrors.

From reading that topic, and reading up on Microsoft's MSDN, it looks like I'm missing a bunch of typedefs that define what USHORT, UCHAR, etc. mean.
For example, Microsoft says that UCHAR is:

Code: Select all

typedef unsigned char UCHAR, *PUCHAR;
What is the standard header that I should #include to get all of these (so I don't have to write them all myself)?

As a quick "band-aid", I was able to manually typedef all of the data types (ULONG, PBYTE, BOOL, etc.) and the compiler likes it now.

It still, however, does not address the first compile error:
Form1.h(201): error C3861: 'IsInpOutDriverOpen': identifier not found
which sounds like it does not know where the functions declared in inpout32.h are actually defined. Where are the functions actually defined?


Sorry for the super-long post with a large number of questions,
Satiagraha
User avatar
phil
Site Admin
Posts: 7664
Joined: Sun Apr 06, 2003 11:12 pm

Re: Beginning the Parallel Port in VC++

Post by phil »

Hi,

Lets start with VS2010 - it should be fine but I haven't personally tried it. Are you using C++ in .NET more or native mode (the header was written for native mode but I dint know if there is any difference as I have never written .NET C++ code!).

The DLL is not actually the driver. The driver is a .SYS file (as usual) but this is an embedded resource inside the DLL which is extracted to the windows driver folder and installed at runtime. This is why you need InstallDriver, to ensure you have administrative permissions on newer OS's like Vista/7.

If you are writing 32bit applications then you can only use the InpOut32.dll. You can not call a 64bit DLL from 32bit code and visa-versa. Be careful that in .NET (C#/VB.NET) generally if targets "Any CPU" which will run in 64bit on a 64bit OS/CPU. However I believe 2010 has changed the default CPU architecture back to 32bit!

There are sample apps on the original Logix4U InpOut32 page for C++ for example here that should show how to use InpOut32 from C++. NOTE That example uses explicit runtime linking and does not need the header of the lib (and is perhaps easier).

But none of that explains why it cant find IsInpOutDriverOpen(). The functions declared in the header are in the lib, so you must tell the linker to include the InpOut32.lib file. There is an alternative to this dynamic linking - explicit run-time linking (http://en.wikipedia.org/wiki/Dynamic-link_library), this is more like how its don in VB/C# with the DLLImports. Using Explicit linking you don't need to include the header file or link to the lib file.

If your still stuck, I might be able to know up a couple of more modern samples using the dynamic linking (header/lib) and explicit linking although probably not this week - maybe next week. Let me know, but have another try first :)

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)
satiagraha
New User
Posts: 5
Joined: Tue Jul 27, 2010 4:42 am

Re: Beginning the Parallel Port in VC++

Post by satiagraha »

Thank you for your reply,

So the .SYS is the driver, and it is pulled out of the .DLL by InstallDriver.exe and put into Windows' directory. I checked my Windows/System32/Drivers directory and found inpoutx64.sys. It appears as though it installed the 64-bit version of the driver since my operating system is 64-bit. Do I need to have the inpout32.sys driver installed as well since I'm creating a 32-bit program? If so, then how do I get InstallDriver.exe to install that driver instead of the x64 one?

If not, then I guess all is well up to there.

So now I question if I'm linking Visual Studio 2010 correctly to inpout32.lib, so that it knows where the .dll is. I click on the properties of my project and go to Linker>>General and there is a blank field called "Additional Library Dependencies". I add the directory of my source files which also has inpout32.lib in it. Shouldn't the linker now try to link with inpout32.lib and accordingly find inpout32.dll and all of the function definitions inside it?

I think that most of my problems are coming with correctly linking to the inpout32 files. There's a .lib in my source code directory, there's a .dll in my Windows/System32 directory, there's a .sys in my Windows/System32/Drivers directory, and there's a .h added and #included in my project in my source code directory.
User avatar
phil
Site Admin
Posts: 7664
Joined: Sun Apr 06, 2003 11:12 pm

Re: Beginning the Parallel Port in VC++

Post by phil »

No, on a 64bit OS only InpOutx64.sys will work, and the 32bit DLL will talk to that driver.
On 32bit OS, it will use InpOut32.sys (I think thats what its called).

So that is all good. Incidentally, anything using the dll will install the driver as long as it has admin rights. InstallDriver was only created to force admin rights - but that is not really important.

The blank field in the linker settings need the lib not the folder. You need to put InpOut32.lib in there (or the full path to the lib if required). Alternativly you can add the lib to the solution files and I think it will automatically include it, or you can use a #pragma declaration which I cant remember off the top of my head.

Why is the DLL in the system32 directory - its not a system dll. personally I would keep the DLL next to the exe your producing, but it should work in the system32 folder although system32 on x64 is generally for 64bit dlls not 32bit dlls - it might be better in windows\syswow64 which is the 32bit "system32" folder. Thats one reason why its best to keep it in the same folder as the EXE :)


So try this:
Add the .lib to your VS2010 solution (or put the fill path inc file name to it in the linker settings)
Put the DLL in the same folder as your EXE (debug & release)
See if that helps.

NOTE: The location of the DLL does not matter until runtime. if its not compiling/linking then thats not the problem (yet).

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)
satiagraha
New User
Posts: 5
Joined: Tue Jul 27, 2010 4:42 am

Re: Beginning the Parallel Port in VC++

Post by satiagraha »

Alright, so I think I got the Linker to see the .lib and I've put the .dll into the same directory as my code. As a clarification, should the .dll be in the same directory as the output .exe? or the source code (.c, .h, .lib)?

I'm running the code from the tutorial you linked to from Logix4U marked NEW "Inpout32 Test plus Wrapper Module." The good news is that it compiles with only one Warning related to the LoadLibrary. The bad news is that the LoadLibrary fails.

Basically, this is what I've got:

Code: Select all

static HINSTANCE hLib;

int inpout32_init(void)
{
	hLib = LoadLibrary("inpout32.dll");
	if (hLib == NULL) {
		fprintf(stderr,"LoadLibrary Failed.\n");
		return -1;
	}
	**et cetera**
}
I call inpout32_init() in my main function and the LoadLibrary fails, so hLib remains NULL so it prints "LoadLibrary Failed." I've tried several different locations for placing my .dll so that "inpout32.dll" will be the right address, but the program can't seem to find it when it runs.

The warning I get when I compile is (Line 28 is the LoadLibrary line of code):
inpout32.c(28): warning C4133: 'function' : incompatible types - from 'char [13]' to 'LPCWSTR'
User avatar
phil
Site Admin
Posts: 7664
Joined: Sun Apr 06, 2003 11:12 pm

Re: Beginning the Parallel Port in VC++

Post by phil »

The DLL must be in the same folder as the EXE, or somewhere in the system "PATH" environment variable. I tend to prefer keeping it along side the EXE.

If its not there that will explain the LoadLibrary failure.

As for the warning, which is line 28? This may also be the problem causing it to fail to load the library. It seems your using a character set that is different from the example - probably because the defaults have changed in visual studio.

So I think your using wide characters (2 bytes per char) and not single/ansi characters (1 byte per char). You can normally tell by right clicking the function (LoadLibrary in this case) and going to the definition. There are two definitions, LoadLibraryA (single byte char) and LoadLibraryW (multi-byte char) I suspect your using the second one so your input string needs to "wide".

Try this:

Code: Select all

static HINSTANCE hLib;

int inpout32_init(void)
{	
	hLib = LoadLibrary(L"inpout32.dll");
	if (hLib == NULL) 
	{
		DWORD dwError = GetLastError();
		fprintf(stderr,"LoadLibrary Failed. Error %d\n", dwError);
		return -1;
	}
	**et cetera**
}
That way it should compile and work, but if it fails at least it will give you the error code...
You can use the error lookup tool (tools menu) to decode it, e.g. 126 = "The specified module could not be found."

Good luck :)
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)
satiagraha
New User
Posts: 5
Joined: Tue Jul 27, 2010 4:42 am

Re: Beginning the Parallel Port in VC++

Post by satiagraha »

It works! :D Wow!

You were right, I needed the L parameter in the LoadLibrary:

Code: Select all

LoadLibrary(L"inpout32.dll")
It now loads the .dll and my hLib comes back non-NULL. The test example runs great and I can write and read from the port! I've even physically verified it using my multimeter. I get about 50mV for low and 4.8V high. Now I'm going to have to order a bunch of DB25 connectors to start putting on circuit boards!

So, I started with a "Windows Console Application" which means it all runs through the console (printf/scanf, stdin/stdout/stderr). Now I'm trying to get it to work with a "Windows Form Application" so it has a Windows window with buttons and checkboxes and such. So far, the integration has been pretty much the same as with a console app, except I had to add a /CLR:PURE tag when compiling the inpout32.c file.

Is there an easy way to write a function to check if the driver is loaded? Can I make a function int CheckDriverLoaded()? I tried seeing if my hLib handler is non-NULL, but in the form code, it can't reference the hLib variable from inpout32.c, even if it's a global.
User avatar
phil
Site Admin
Posts: 7664
Joined: Sun Apr 06, 2003 11:12 pm

Re: Beginning the Parallel Port in VC++

Post by phil »

Have another look at the header (I know your not using that but there are several funcitons described in that file that might help you).

These are my additions to the base InpOut so the demo C++ app wont show them, but they are very simple and you should be able to work out how to call them yourself (esp. if you look at the definition of inp() and out() n the header compared to how your using it with the "runtime linking methods"....

I cant off the top of my head remeber the names of the funcitons but it should be obvious from the header.

If your struggling, give us another shout and I will see what I can do - but not right now - its a bit late and its been a heavy weekend lol

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)
satiagraha
New User
Posts: 5
Joined: Tue Jul 27, 2010 4:42 am

Re: Beginning the Parallel Port in VC++

Post by satiagraha »

Yep, you were right. I found a IsInpOutDriverOpen() function in your header file. I missed it before because I was using a version of inpout32.h from the VS example from Logix4U mentioned earlier.

So far so good :D
Post Reply