COM和服务

时间:2015-07-18 06:47:46

标签: delphi service com marshalling

我正在尝试创建一个服务来与控制BarCode Scanner(型号为Motorola Symbol LS9208)的COM对象进行通信。

我从安装了扫描仪驱动程序应用程序的ocx创建了TLB单元。

在Delphi中,我创建了一个完成所有工作的DataModule 我在ServiceExecute过程中放置​​了扫描器的启动和停止代码:

  1. 初始化TScanner COM对象(在TLB中声明)

  2. 设置一些扫描仪属性,“声明”控件并使用 DataModule 服务中的一个过程设置一个TScanner事件,以便在条形码被重新启动时触发

  3. 毕竟,在关闭之前,释放并释放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;
    
  4. 当我创建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对象和其他线程之间传输数据的编组技术的提及。但我不确定这是不是问题......而且我不知道该怎么做。

    当我扫描一些条形码时,服务总是停止。如果没有,启动和停止没有错误,激光在启动时亮,在停止时点亮,显示正常和正确的命令和操作。

    请有人帮我解决这个问题吗?

    提前致谢!

1 个答案:

答案 0 :(得分:0)

我曾经在CoInitialize之后立即调用CoInitializeSecurity解决了NT服务中的COM问题。我写了更多关于它的信息here。除此之外,重要的是使线程正确。因此,请务必调试“普通”应用程序版本,并使用GetCurrentThreadId来自扫描程序的传入数据由您期望的确切线程处理。