C# - Possible to use IOCTL
I'm trying to code for a Point Of Sale system which allows for a "Cash Drawer" attachment. Code is provided in the manual for opening the cash drawer (in C++ using IOCTL). Since I am coding in C# .NET, is it possible to perform something similar from within C# or will I have to write some unmanaged code?
Am I able to get a handle to "\\.\ADVANSYS" from within C#? Do I need to use DLLImport?
Would appreciate it if someone could point me in the right direction.
// IOCTL Codes
#define GPD_TYPE 56053
#define ADV_OPEN_CTL_CODE CTL_CODE(GPD_TYPE, 0x920, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define ADV_STATUS_CTL_CODE CTL_CODE(GPD_TYPE, 0x900, METHOD_BUFFERED, FILE_ANY_ACCESS)
void OpenDrawer(UCHAR uWhichDrawer) // uWhichDrawer = 1 => CD#1, uWhichDrawer = 2 => CD#2
{
HANDLE hFile;
BOOL bRet
UCHAR uDrawer = uWhichDrawer;
// Open the driver
hFile 开发者_如何学编程= CreateFile(TEXT("\\\\.\\ADVSYS"),
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (m_hFile == INVALID_HANDLE_VALUE)
{
AfxMessageBox("Unable to open Cash Drawer Device Driver!");
return;
}
// Turn on the Cash Drawer Output (Fire the required solenoid)
bRet = DeviceIoControl(hFile, ADV_CD_OPEN_CTL_CODE,
&uDrawer, sizeof(uDrawer),
NULL, 0,
&ulBytesReturned, NULL);
if (bRet == FALSE || ulBytesReturned != 1)
{
AfxMessageBox("Failed to write to cash drawer driver");
CloseHandle(hFile);
return;
}
CloseHandle(hFile);
}
The C++ is riddled with mistakes, not sure if I got it right. The best thing to do is to declare DeviceIoControl() with altered argument types so that it is easy to call. You also have to P/Invoke CreateFile because FileStream cannot open devices. It ought to look similar to this:
using System;
using System.IO;
using System.ComponentModel;
using System.Runtime.InteropServices;
class Program {
static void Main(string[] args) {
IntPtr hdl = CreateFile("\\\\.\\ADVSYS", FileAccess.ReadWrite,
FileShare.None, IntPtr.Zero, FileMode.Open,
FileOptions.None, IntPtr.Zero);
if (hdl == (IntPtr)(-1)) throw new Win32Exception();
try {
byte drawer = 1;
bool ok = DeviceIoControl(hdl, CTLCODE, ref drawer, 1, IntPtr.Zero,
0, IntPtr.Zero, IntPtr.Zero);
if (!ok) throw new Win32Exception();
}
finally {
CloseHandle(hdl);
}
}
// P/Invoke:
private const uint CTLCODE = 0xdaf52480;
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CreateFile(string filename, FileAccess access,
FileShare sharing, IntPtr SecurityAttributes, FileMode mode,
FileOptions options, IntPtr template
);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool DeviceIoControl(IntPtr device, uint ctlcode,
ref byte inbuffer, int inbuffersize,
IntPtr outbuffer, int outbufferSize,
IntPtr bytesreturned, IntPtr overlapped
);
[DllImport("kernel32.dll")]
private static extern void CloseHandle(IntPtr hdl);
}
You can use Pinvoke;
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
internal static extern bool DeviceIoControl([In] SafeFileHandle hDevice, [In] int dwIoControlCode, [In] IntPtr lpInBuffer, [In] int nInBufferSize, [Out] IntPtr lpOutBuffer, [In] int nOutBufferSize, out int lpBytesReturned, [In] IntPtr lpOverlapped);
This example might also help.
There's loads of code ready for this on pinvoke.net with plenty of examples too.
http://www.pinvoke.net/default.aspx/kernel32.DeviceIoControl
you wrote:
It seemed that the GPD_TYPE 56053 as specified in the documentation that I had was not correct
Can you post proper value of GPD_TYPE ?
Best regadrs!
精彩评论