我正在尝试创建一个服务来与控制BarCode Scanner(型号为Motorola Symbol LS9208)的COM对象进行通信。
我从安装了扫描仪驱动程序应用程序的ocx创建了TLB单元。
在Delphi中,我创建了一个完成所有工作的DataModule 我在ServiceExecute过程中放置了扫描器的启动和停止代码:
初始化TScanner COM对象(在TLB中声明)
设置一些扫描仪属性,“声明”控件并使用 DataModule 服务中的一个过程设置一个TScanner事件,以便在条形码被重新启动时触发
毕竟,在关闭之前,释放并释放TScanner对象
procedure TInteliPEDCheckService.ServiceExecute(Sender: TService);
begin
debugLog( 'initialization of service thread...' );
CheckInitParams;
//DataModule_Create;
startScanner;
//loopback
while (not Terminated) do
begin
Sleep(100);
ServiceThread.ProcessRequests(False);
end;
debugLog( 'end of service loop...' ); //only reached if stop service before read codbar
stopScanner;
//DataModule_Free;
debugLog( 'finalization of service thread...' );
end;
procedure TInteliPEDCheckService.startScanner;
var HR : HRESULT;
begin
//CoInitialize( nil );
//CoInitializeEx( nil, COINIT_MULTITHREADED );
//CoInitializeEx( nil, COINIT_MULTITHREADED or COINIT_DISABLE_OLE1DDE );
//CoInitializeEx( nil, COINIT_APARTMENTTHREADED );
CoInitializeEx( nil, COINIT_APARTMENTTHREADED or COINIT_DISABLE_OLE1DDE );
// I've tried all options above, but without success
HR := CoInitializeSecurity(
nil, -1, nil, nil,
1, // RPC_C_AUTHN_LEVEL_NONE
1, // RPC_C_IMP_LEVEL_ANONYMOUS
nil,
0, // EOAC_NONE
nil);
debugLog( 'HRESULT of CoInitializeSecurity: ' + IntToStr( HR ) );
// the log always shows 0 as HRESULT
Scanner := TScanner.Create( nil );
Scanner.Open( 'STI_USBSCANNER' );
if Scanner.Claim(0) = 0 then
begin
Scanner.OnDataEvent := ScannerDataEvent;
//Scanner.OnDirectIOEvent := ScannerDirectIOEvent;
Scanner.DeviceEnabled := TRUE;
Scanner.DataEventEnabled := TRUE;
Scanner.FreezeEvents := FALSE;
end
else
begin
Scanner.DeviceEnabled := FALSE;
Scanner.DataEventEnabled := FALSE;
Scanner.FreezeEvents := FALSE;
end;
// Caption := IfThen( Scanner.Claimed, 'OK', 'FAIL' );
end;
procedure TInteliPEDCheckService.stopScanner;
begin
if ( Scanner <> nil ) then
begin
Scanner.Release;
Scanner.Free;
CoUninitialize();
end;
end;
procedure TInteliPEDCheckService.ScannerDataEvent(ASender: TObject; lStatus: Integer);
begin
debugLog( 'will fire...' ); //never reached
debugLog( 'FIRED: ' + Scanner.ScanData );
//Scanner.DeviceEnabled := FALSE;
//Sleep(1000);
Scanner.DeviceEnabled := TRUE;
Scanner.DataEventEnabled := TRUE;
end;
当我创建DataModule 将此代码运行到EXE应用程序中时,一切正常。但现在我正在将这个功能迁移到Windows服务。
作为第一个问题,“CoInitialize not called”的错误被触发并且无效。
所以,我在Application.Initialize之前尝试在服务的DPR中使用CoInitialize(),但是没有解决,并且错误不断增加。
当我在TScanner.Create(nil)之前放置CoInitialize()时,错误才消失,因此扫描仪启动,我可以看到激光准备读取条形码。
现在扫描仪在服务启动时正常启动,并在服务停止时也停止运行。
但是如果我读了一些条形码,并且即将触发事件OnDataEvent,服务就会暂停,并且没有收到数据,(当然)我失去了扫描仪的控制权,需要重新启动服务。
我读了一些关于如何CoInitialize COM对象(https://msdn.microsoft.com/en-us/library/windows/desktop/ff485844(v=vs.85).aspx)的说明,并且发现了一些关于在COM对象和其他线程之间传输数据的编组技术的提及。但我不确定这是不是问题......而且我不知道该怎么做。
当我扫描一些条形码时,服务总是停止。如果没有,启动和停止没有错误,激光在启动时亮,在停止时点亮,显示正常和正确的命令和操作。
请有人帮我解决这个问题吗?
提前致谢!
答案 0 :(得分:0)
我曾经在CoInitialize之后立即调用CoInitializeSecurity解决了NT服务中的COM问题。我写了更多关于它的信息here。除此之外,重要的是使线程正确。因此,请务必调试“普通”应用程序版本,并使用GetCurrentThreadId来自扫描程序的传入数据由您期望的确切线程处理。