C#(.Net) 配合WQL实现并口读写
最近做开发,要对POS打印机就进行编程,说白了,也就是一个端口读写,再根据打印机说明实现几个POS指令就OK了,但是遇到了一个困难的问题,因为是无人系统,一个打印机打印客户单据,一个打印历史单据,这个还不是最要命的,最要命的是一个是串口的,一个是并口的,对于串口还好办,因为.Net里有现成的SerialPort类,可是并口就难了。
搜了一下网上的资料,不外乎两种方法。
第一种是用win32 API来实现。见
http://support.microsoft.com/kb/823179/zh-cn
另一种方式是用第三方的动态连接库inpout32.dll
http://www.codeproject.com/KB/vb/Inpout32_read.aspx
两种方式,各有优劣。
如果用win32 API的话,操作固然方便,但是有一个死穴,就是无法读并口的数据。
如果用inpout32呢,到是能读能写,但是并口的地址(0x378,0x379,0x37a)并不是一个固定值。
参见文档
http://www.cnblogs.com/thunderdanky/articles/795010.html
但是客户要求能实时检测打印机状态 。。 这个问题可是难住了一天。
怎么办?让客户自己到设备管理器里去找并口基址?MS有点太土了。
后来看了一些资料,突然发现WQL好像可以实现查找串口基址的功能,实验了一下,还真实现了,嘿嘿
好了,现在就贴代码
1
using System;2
using System.Collections.Generic;3
using System.Text;4
using System.Runtime.InteropServices;5
using System.Management;6

7
namespace SFTech.POSPrint8


{9

/**//// <summary>10
/// 串口类,IPort是抽像的端口类11
/// </summary>12
public class ParallelPort : IPort ,IDisposable13

{14

15

inpout32相关#region inpout32相关16
[DllImport("inpout32.dll", EntryPoint = "Out32")]17
public static extern void Output(uint adress, int value);18

19
[DllImport("inpout32.dll", EntryPoint = "Inp32")]20
public static extern int Input(uint adress); 21
[StructLayout(LayoutKind.Sequential)]22
private struct OVERLAPPED23

{24
int Internal;25
int InternalHigh;26
int Offset;27
int OffSetHigh;28
int hEvent;29
}30
#endregion31

32

win32 API#region win32 API33
[DllImport("kernel32.dll ")]34
private static extern int CreateFile(35
string lpFileName,36
uint dwDesiredAccess,37
int dwShareMode,38
int lpSecurityAttributes,39
int dwCreationDisposition,40
int dwFlagsAndAttributes,41
int hTemplateFile42
);43
[DllImport("kernel32.dll ")]44
private static extern bool WriteFile(45
int hFile,46
byte[] lpBuffer,47
int nNumberOfBytesToWrite,48
ref int lpNumberOfBytesWritten,49
ref OVERLAPPED lpOverlapped50
);51
[DllImport("kernel32.dll ")]52
private static extern bool CloseHandle(53
int hObject54
);55
[DllImport("kernel32.dll ")]56
private static extern bool ReadFile(57
int hFile,58
out byte[] lpBuffer,59
int nNumberOfBytesToRead,60
ref int lpNumberOfBytesRead,61
ref OVERLAPPED lpOverlapped62
); 63

64
private int iHandle;65

66
private bool _isWork;67
68
private const uint GENERIC_READ = 0x80000000;69
private const uint GENERIC_WRITE = 0x40000000;70
#endregion71

IPort 成员#region IPort 成员72

73

74
private bool _IsOpen;75
public bool IsOpen76

{77
get78

{79
return _IsOpen;80
}81
private set82

{83
_IsOpen = value;84
}85
}86

87
private string _Name;88
public string Name89

{90
get91

{92
return _Name;93
}94
set95

{96
_Name = value;97
}98
}99

100
public bool WriteData(byte[] Data)101

{102
//for (int i = 0; i < Data.Length; i++)103
// Output(BasePort, Data[i]); 这里原来也想用inpout32实现,但是从字节到int转换比较麻烦,试了几次没达到效果104
//return true;105

106
if (iHandle != -1)107

{108
OVERLAPPED x = new OVERLAPPED();109
int i = 0;110
WriteFile(iHandle, Data, Data.Length,111
ref i, ref x);112
return true;113
}114
else115

{116
//throw new Exception("不能连接到打印机! ");117
return false;118
}119
}120

121

122

/**//// <summary>123
/// 读状态124
/// 用inpout32125
/// </summary>126
/// <param name="Len"></param>127
/// <returns></returns>128
public byte[] ReadData(int Len)129

{130
byte[] result ;//= new byte[Len];131
result = new byte[Len];132
for (int i = 0; i < result.Length; i++)133
result[i] = (byte)Input(BasePort + 1);134
return result;135
}136

137

138

/**//// <summary>139
/// 打开端口140
/// </summary>141
public void Open()142

{143
iHandle = CreateFile(Name, 0x40000000, 0, 0, 3, 0, 0);144
if (iHandle != -1)145

{146
this.IsOpen = true;147
}148
else149

{150
this.IsOpen = false;151
}152

153
this.IsOpen = true;154
_isWork = true;155
//开一个线程检测状态口状态156
new System.Threading.Thread(new System.Threading.ThreadStart(ReadState)).Start();157
}158

159

160

/**//// <summary>161
/// 关闭端口162
/// </summary>163
public void Close()164

{165
this.IsOpen = !CloseHandle(iHandle);166
_isWork = false;167
}168

169

/**//// <summary>170
/// 端口基址171
/// </summary>172

private uint BasePort
{ get; set; }173
internal ParallelPort(String portName)174

{175
this.Name = portName;176
iHandle = -1;177

178

/**////用wql查询串口基址179
ManagementObjectSearcher search2 =180
new ManagementObjectSearcher(181
"ASSOCIATORS OF {Win32_ParallelPort.DeviceID='" + this.Name + "'}");182
//本来最佳的wql是ASSOCIATORS OF {Win32_ParallelPort.DeviceID='" + this.Name + "'} WHERE ASSCICLASS = Win32_PortResource183
//但是不知道为什么不返回结果,所以就做一个简单的遍历吧184
foreach (var i in search2.Get())185

{186

187
if (i.ClassPath.ClassName == "Win32_PortResource")188

{189
//得到串口基址 大多数是0x378H190
this.BasePort = System.Convert.ToUInt32( i.Properties["StartingAddress"].Value.ToString());191

192
break;193
}194

195

196
}197
if (BasePort == 0)198
throw new Exception("不是有效端口");199
IsOpen = false;200
}201

202
#endregion203

204

IPort Members#region IPort Members205

206
public event PortStateChanged StateChanged;207

208
public event PortDataReceived DataReceive;209

210
public System.Windows.Forms.Form Parent211

{212
get213

{214
throw new NotImplementedException();215
}216
set217

{218
throw new NotImplementedException();219
}220
}221

222

private int a
{ get; set; }223

224

/**//// <summary>225
/// 检测线程,当状态改变时,引发事件226
/// </summary>227
private void ReadState()228

{229

230
a = 0;231
int lastRead =a;232
while (_isWork)233

{234
lastRead = a;235
a = Input(BasePort + 1);236
if (a != lastRead)237

{238
if (this.StateChanged != null)239

{240
PortChangedEvntAvrgs e = new PortChangedEvntAvrgs();241
e.PortStatusByte = a;242
this.StateChanged(this, e);243
}244
245
}246
System.Threading.Thread.Sleep(500);247
248
}249
}250
#endregion251

252

IDisposable Members#region IDisposable Members253

254
public void Dispose()255

{256
this.Close();257
}258

259
#endregion260

261

IPort Members#region IPort Members262

263

264
public void Update()265

{266
a = 0;267
}268

269
#endregion270
}271
}272



浙公网安备 33010602011771号