drukarka Novitus - obsługa biblioteki NFPDrv.dll poza głównym wątkiem programu

0

Mam dość nietypowy problem z tą biblioteką, który objawia się tym, że nic się nie drukuje.
To czym różni się mój kod od przykładu:
w przykładzie wszystko w głównym wątku i main()
u mnie w moim demo przy uruchomieniu aplikacji rozpocznam połączenie, przy wyłączeniu zamykam połączenie, na żądanie drukuje paragony .itp, każda z operacji w oddzielnym Task.Run() aby nie blokować głównego wątku.

Proste spradzenie stanu zwraca -1 w task.run ale już jak wszystko mam w main() jak w dokumnetacji to działa.
Analogicznie zachowuje się drukowanie paragonów. Oczywiście programy testuję w róznym czasie i nie uruchamiam 2 na raz.
Czy ktoś pracował z bilblioteką NFPDrv.dll? Czy ktoś wie co dzieje się pod spodem w tej dll od Novitus?
Chce uniknąć blokowania głównego wątku. W róznych programach od Novitusa widać jak blokuje się okno gdy się program nie może podłączyć do drukarki fiskalnej i dla mnie to jest zbyt uciążliwe, żeby sobie na to pozwolić.
Ostatecznie zostaje mi przygotowanie oddzielengo procesu.
Poniżej minimum kodu w którym już widać problem. Wyciąłem pokazywanie komunikatów dla użytkownika.


class ApiWrapper 
{
  //...........
  public int checkDLE(ref DLEStatus dle)
  {
      IntPtr intPtr = Marshal.AllocHGlobal(Marshal.SizeOf((object)dle));
      Marshal.StructureToPtr((object)dle, intPtr, fDeleteOld: false);
      Api.ndrv_ioctrl(2, (IntPtr)0, 0, 0);
      if (Api.ndrv_ioctrl(3, intPtr, 1, 0) == 0)
      {
          dle = (DLEStatus)Marshal.PtrToStructure(intPtr, typeof(DLEStatus));
          return 0;
      }
  
      return -1;
  }
}
main()
{
  var wrapper = new ApiWrapper();
  wrapper.init();
  var portParams = new TCPIPPortParameters();
  portParams.host = 192.168.0.2;
  portParams.port = 1234;
  portParams.mTimeout = 10000;
  var openResult = wrapper.openTCPIPEx(portParams);
  var status = new DLEStatus();
  var checkResult = wrapper.checkDLE(ref status);
  Assert.AreEqual(checkResult, 0); //w main dziala
  
}


//usluga
main()
{
  //gdzies na starcie
  Task.Run(() => {
    var wrapper = new ApiWrapper();
    wrapper.init();
    var portParams = new TCPIPPortParameters();
    portParams.host = 192.168.0.2;
    portParams.port = 1234;
    portParams.mTimeout = 10000;
    var result = wrapper.openTCPIPEx(portParams);
  });
  ProcessRequest();
  Task.Run(() => {
    var wrapper = new ApiWrapper();
    wrapper.close();
  });
}

void ProcessRequest(...) {
  Task.Run(() => {
      var wrapper = new ApiWrapper();
      var status = new DLEStatus();
      var result = wrapper.checkDLE(ref status);
      Assert.AreEqual(result, 0); //tutaj juz nie dziala
  });
}
0

Ciekawe jakim cudem kompilujesz to 192.168.1.2
ten kod totalnie nie wzbudza zaufania, albo z powodu recznej modyfikacji przed publikacją zmieniającej sens, ale ma to w sobie natywnie

0

czemu masz trzy razy Task.Run a nie w jednym? Poza tym w każdym Run tworzysz nowy wrapper - przecież to jest całkowicie bez sensu - jak wrapper z ProcessRequest ma cokolwiek zrobić jak nie ma otwartego połączenia (otwarte połączenie ma wrapper z pierwszego taska.
Popatrz sobie na ten kod

main()
{
  var wrapper = new ApiWrapper();
  wrapper.init();
  var portParams = new TCPIPPortParameters();
  portParams.host = 192.168.0.2;
  portParams.port = 1234;
  portParams.mTimeout = 10000;
  var openResult = wrapper.openTCPIPEx(portParams);
  var status = new DLEStatus();
  var checkResult = wrapper.checkDLE(ref status);
  Assert.AreEqual(checkResult, 0); //w main dziala
  
}

wszystko w jednym wątku (nie ważne czy w głównym czy bocznym), na jednym wrapperze a to co wymodziłeś przy użyciu tasków to jakieś strzelanie na ślepo.

0
abrakadaber napisał(a):

czemu masz trzy razy Task.Run a nie w jednym? Poza tym w każdym Run tworzysz nowy wrapper - przecież to jest całkowicie bez sensu - jak wrapper z ProcessRequest ma cokolwiek zrobić jak nie ma otwartego połączenia (otwarte połączenie ma wrapper z pierwszego taska.
Popatrz sobie na ten kod

main()
{
  var wrapper = new ApiWrapper();
  wrapper.init();
  var portParams = new TCPIPPortParameters();
  portParams.host = 192.168.0.2;
  portParams.port = 1234;
  portParams.mTimeout = 10000;
  var openResult = wrapper.openTCPIPEx(portParams);
  var status = new DLEStatus();
  var checkResult = wrapper.checkDLE(ref status);
  Assert.AreEqual(checkResult, 0); //w main dziala
  
}

wszystko w jednym wątku (nie ważne czy w głównym czy bocznym), na jednym wrapperze a to co wymodziłeś przy użyciu tasków to jakieś strzelanie na ślepo.

Są oddzielne task.run bo połączenie jest otwierane tylko na starcie a nie za każdym razem.
Pod przyciskiem mam Process request.

Z tego co widzę po kodzie NFPDrvcs.dll ten wrapper to tylko taka nakładka na dllimport z NFPDrv.dll i stan połączenia nie jest z nim powiązany, równie dobrze mogłaby być statyczna klasa.


public class Api
{
  //...
  [DllImport("NFPDrv.dll", CallingConvention = CallingConvention.Cdecl)]
  public static extern int ndrv_open_tcpip_ex(IntPtr param);
}



public class ApiWrapper
{
  //...
  public int openTCPIPEx(TCPIPPortParameters param)
    {
      IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf((object) param));
      Marshal.StructureToPtr((object) param, ptr, false);
      return Api.ndrv_open_tcpip_ex(ptr);
    }
}


0

super ale pewnie nie sprawdziłeś czy jak będziesz miał wszystko w jednym wątku i z jednym wrapperem to zadziała.
BTW

Są oddzielne task.run bo połączenie jest otwierane tylko na starcie a nie za każdym razem.

ponieważ?

0
abrakadaber napisał(a):

super ale pewnie nie sprawdziłeś czy jak będziesz miał wszystko w jednym wątku i z jednym wrapperem to zadziała.
BTW

Są oddzielne task.run bo połączenie jest otwierane tylko na starcie a nie za każdym razem.

ponieważ?

Sprawdziłem przed chwilą. Używając jednego wątku przez new Thread lub jednego Task.Run zamiast kilku funkcje działają poprawnie.
Moja hipoteza jest taka, że coś ta bilbioteka robi co nie działa z dostępem przez rózne wątki. W każdym razie tego się nie dowiem, bo to jest natywny kod :(

Co do drugiego pytania to zainspirowałem sie aplikacją od Noviusa. U nich są przyciski do łączenia i rozłączenia. Nie trzeba za każdym razem ponownie się łączyć. Masz lepszy pomysł? Uważasz, że źle robię? Tak wygląda ich demo.

Chciałem Task.Run, bo ich aplikacja się zawiesza, nie jest responsywna przez cały timeout np. gdy nie może połaczyć się do drukarki, bo jest wyłączona.

Wyprzedzając Twoje pytanie o logi. W jednym wątku się zapisują a z wielu rożnych Task.Run nawet nie ma śladu w pliku z momentu wystąpenia ww problemów.

screenshot-20230701131237.png

0

Chciałem Task.Run, bo ich aplikacja się zawiesza, nie jest responsywna przez cały timeout np. gdy nie może połaczyć się do drukarki, bo jest wyłączona.

No to masz odpowiedz - działa na głównym wątku. Twój problem jest taki, że robisz różne rzeczy z różnych wątków na tym samym obiekcie - to tak nie zadziała. Możesz albo użyć wątku (nie taska) i oprogramować go tak, żeby był aktywny (ale np. uśpiony jak nie jest potrzebny) przez cały czas i to na nim robić wszystkie operacje albo użyć taska ale łączyć się, drukować i rozłączać w jednym kroku

1 użytkowników online, w tym zalogowanych: 0, gości: 1