Wywołanie dll'ki C++

0

Witam.
Próbuję wywołać metody biblioteki napisanej w C++ w swojej aplikacji C# (.NET 4.0).
Mam problem z konwersją parametru wywołania, mianowicie:
W dll'ce mam zdefiniowaną metodę:

 void* __stdcall POS_SetDeviceParam  ( void*  hDevice,  unsigned long  paramCode,  void *  paramValue )  

Przykładowy kod źródłowy w C++ wywołuje tą metodę następująco:

void *hDevice=NULL;
string comparams="COM1,9600,8,N,1,H";
POS_SetDeviceParam(hDevice,POSNET_DEV_PARAM_COMSETTINGS,(void*)comparams.c_str());

Mam problem z parametrem "paramValue" w C#. Próbuje zadeklarować tą metodę jako StringBuilder:

[DllImport("libposcmbth.dll", EntryPoint = "POS_SetDeviceParam", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern uint POS_SetDeviceParam(IntPtr hDevice, uint paramCode, StringBuilder paramValue);

Ale przy takiej deklaracji wygląda to tak jakby przekazywane było tylko pierwszy znak ze stringa.
W jaki sposób mam zadeklarować wywołanie tej metody w C#.
Z góry dziękuję za pomoc.

0

Witam,
Pewnie Ty już rozwiązałeś ten problem, ale może innym się przyda.
Poprawna deklaracja funkcji to:

[DllImport("libposcmbth.dll", EntryPoint = "POS_SetDeviceParam", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern uint POS_SetDeviceParam(IntPtr hDevice, uint paramCode, IntPtr paramValue);

A wywołać funkcję można w poniższy sposób:

var wynik=POS_SetDeviceParam( handle, 0x00020001, Marshal.StringToHGlobalAnsi("COM3,9600,8,N,1,H"));

Pozdrawiam i życzę sukcesów
Krzysiek

0

Dzięki za podpowiedź.
Rzeczywiście poradziłem sobie z problemem. Moje rozwiązanie jest następujące:

        [DllImport("libposcmbth.dll", EntryPoint = "POS_SetDeviceParam", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
        public static extern uint POS_SetDeviceParam(IntPtr hDevice, uint paramCode, IntPtr paramValue);

uint POSNET_DEV_PARAM_COMSETTINGS = 131073
uint err = POS_SetDeviceParam(_hDevice, POSNET_DEV_PARAM_COMSETTINGS, System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi("COM3,9600,8,N,1,H"));

Dzięki za podpowiedź.

0

Wojtku, a czy Tobie w trakcie tworzenia paragonu pojawiał się błąd o numerze 4392914?

Poniżej przesyłam kod który wykonuję, dodam że gdy wykonuje np. komendę odczytu czasu rctget to wszystko jest ok.

IntPtr hLocalDevice = new IntPtr(0);
IntPtr handle = new IntPtr(0);
IntPtr hRequest = new IntPtr(0);

uint type = 0x0001;
handle = POS_CreateDeviceHandle(type);

uint tt = 0x00020001;
POS_SetDeviceParam(handle, tt, Marshal.StringToHGlobalAnsi("COM5,9600,8,N,1,H"));

hLocalDevice = POS_OpenDevice(handle);

hRequest = POS_CreateRequest(hLocalDevice, Marshal.StringToHGlobalAnsi("trinit"));
POS_PushRequestParam(hRequest, Marshal.StringToHGlobalAnsi("bm"), Marshal.StringToHGlobalAnsi("0"));

byte mode = 0x00;
POS_PostRequest(hRequest,mode );
POS_WaitForRequestCompleted(hRequest, 5000);

var result = POS_GetRequestStatus(hRequest);
if (result != POSNET_STATUS_OK)
{                    
	throw new Exception("Nastąpił błąd w trakcie tworzenia paragonu");
}
POS_DestroyRequest(hRequest);

Z góry dziękuje za pomoc i życzę miłego dnia.

1
KrzysztofM18 napisał(a):
var wynik=POS_SetDeviceParam( handle, 0x00020001, Marshal.StringToHGlobalAnsi("COM3,9600,8,N,1,H"));

Masz wyciek, bo pointer zwracany przez Marshal.StringToHGlobalAnsi() trzeba zwolnić za pomocą Marshal.FreeHGlobal().

0
KrzysztofM18 napisał(a):

Wojtku, a czy Tobie w trakcie tworzenia paragonu pojawiał się błąd o numerze 4392914?

Poniżej przesyłam kod który wykonuję, dodam że gdy wykonuje np. komendę odczytu czasu rctget to wszystko jest ok.

IntPtr hLocalDevice = new IntPtr(0);
IntPtr handle = new IntPtr(0);
IntPtr hRequest = new IntPtr(0);

uint type = 0x0001;
handle = POS_CreateDeviceHandle(type);

uint tt = 0x00020001;
POS_SetDeviceParam(handle, tt, Marshal.StringToHGlobalAnsi("COM5,9600,8,N,1,H"));

hLocalDevice = POS_OpenDevice(handle);

hRequest = POS_CreateRequest(hLocalDevice, Marshal.StringToHGlobalAnsi("trinit"));
POS_PushRequestParam(hRequest, Marshal.StringToHGlobalAnsi("bm"), Marshal.StringToHGlobalAnsi("0"));

byte mode = 0x00;
POS_PostRequest(hRequest,mode );
POS_WaitForRequestCompleted(hRequest, 5000);

var result = POS_GetRequestStatus(hRequest);
if (result != POSNET_STATUS_OK)
{                    
	throw new Exception("Nastąpił błąd w trakcie tworzenia paragonu");
}
POS_DestroyRequest(hRequest);

Z góry dziękuje za pomoc i życzę miłego dnia.

Nie pamiętam jaki błąd dostawałem, ale dostawałem jakiś błąd w tym miejscu gdy drukarkę miałem podłączoną poprzez kabel USB. Z konsultacji z producentem wyszło że winą jest kabel USB, który przerywa połączenia. Po zmianie kabla na lepszy, przełączeniu go z gniazda na przodzie komputera na tylne problem zniknął. Można też przełączyć drukarkę na port COM i wtedy problem nie występuje. Taki sam błąd występował gdy puszczałem wydruki z programu testowego producenta dll'ki. Dlatego należy stosować dobry kabel USB, wpinać go zawsze w tylne porty USB lub korzystać z portu COM drukarki. Jeżeli w komputerze nie masz portu COM to można zastosować przejściówkę COM -> USB i też to rozwiąże problem.
Niestety port USB w drukarkach jest bardzo wrażliwy na wszelkie zakłócenia, czego nie miał port COM. Przyszłość programistów obsługujących drukarki fiskalne rysuje się w czarnych barwach, gdyż nikt nie chce uwierzyć że problem leży w USB a nie w naszym kodzie.

0

Dzięki za poradę.

Biorę się za testy.

Pozdrawiam
Krzysiek

0

Cześć,
mam problem ze sprawdzeniem statusu drukarki.
Wysyłam polecenie POS_GetPrnDeviceStatus i przekazuje do tej funkcji parametry takie jak: globalStatus oraz printerStatus. Problem jest w tym, że funkcja powinna mi zwrócić statusy w tych dwóch parametrach, a one cały czas mają wartość 0. Dodatkowo funkcja zwraca 0 czyli brak błedu

Według dokumentacji:

POSNET_API POSNET_STATUS __stdcall POS_GetPrnDeviceStatus ( POSNET_HANDLE hLocalDevice, const char statusMode, long * globalStatus, long * printerStatus )
Pobranie statusu drukarki. Drukarka jest periodycznie odpytywana o status i rezultat tej operacji jest przechowywany. Funkcja jest blokująca jeśli wykonywane jest odpytywanie.

Parametry
hLocalDevice Lokalny uchwyt urządzenia
statusMode Sposób uzyskania statusu - 0 - zwróć ostatni status automatyczny , 1 - odpytaj urządzenie jeśli brak statusu - blokujące!
globalStatus Status urządzenia zwracany przez rozkaz sdev (-1 jeśli nie odpytano)
printerStatus Status mechanizmu drukującego (nieistotny jeśli sdev=-1)
Zwraca
Funkcja zwraca status wykonania rozkazu, oraz wypełnia pola parametrów globalStatus i printerStatus

Mój przykład:

    [DllImport("libposcmbth.dll", EntryPoint = "POS_GetPrnDeviceStatus")]
      public static extern IntPtr POS_GetPrnDeviceStatus(IntPtr localHandle, byte[] mode, IntPtr globalStatus, IntPtr printerStatus);

 public void GetPrnDeviceStatus()
      {
          byte[] statusMode = new byte[1];
          statusMode[0] = 1;
          IntPtr globalStatus = new IntPtr();
          IntPtr printerStatus = new IntPtr();
          var result= PosnetProtocolLib.POS_GetPrnDeviceStatus(LocalDeviceHandle, statusMode, globalStatus, printerStatus);
      }

Macie jakis pomysl?

0

statusMode na pewno nie powinno być byte[], bo w C to jest jeden bajt a nie tablica, czyli daj byte statusMode.

globalStatus i printerStatus spróbuj dać jako out int globalStatus i wywal te wszystkie IntPtry.

Prosiłem cię o definicję POSNET_STATUS, której nadal nie podałeś. Zgaduję że to też powinien być int w takim razie.

0
Azarien napisał(a):

statusMode na pewno nie powinno być byte[], bo w C to jest jeden bajt a nie tablica, czyli daj byte statusMode.

globalStatus i printerStatus spróbuj dać jako out int globalStatus i wywal te wszystkie IntPtry.

Prosiłem cię o definicję POSNET_STATUS, której nadal nie podałeś. Zgaduję że to też powinien być int w takim razie.

Cześć,
tak POSNET_STATUS to int. Zwracana jest liczba która symbolizuje błąd. POSNET_STATUS=0 - OK

Zrobiłem zmiany o których pisałeś i nadal jest tak, że globalStatus oraz printerStatus zwraca 0 mimo, że drukarka fiskalna jest w trakcie transakcji. A funkcja zwraca POSNET_STATUS = 0.

Już nie mam pojęcia co jest nie tak. W c++ jest przykład:

long globalStatus=0,printerStatus=0;
PrintStatus(POS_GetPrnDeviceStatus(hLocalDevice,1,&globalStatus,&printerStatus));

Obecny kod:

    [DllImport("libposcmbth.dll", EntryPoint = "POS_GetPrnDeviceStatus")]
    public static extern int POS_GetPrnDeviceStatus(int localHandle, byte mode,out int globalStatus,out int printerStatus);

    public void GetPrnDeviceStatus()
    {
        byte statusMode = 1;
        int result = PosnetProtocolLib.POS_GetPrnDeviceStatus(int.Parse(LocalDeviceHandle.ToString()), statusMode, out int globalStatus, out int printerStatus);
    }
0

Skąd bierzesz to LocalDeviceHandle?
To (prawdopodobnie) powinno pozostać IntPtr. Jeśli mówiłem „wywal wszystkie IntPtry” to miałem na myśli wszystkie oprócz tego :D

0

nadal jest tak, że globalStatus oraz printerStatus zwraca 0 mimo, że drukarka fiskalna jest w trakcie transakcji. A funkcja zwraca POSNET_STATUS = 0.

a jak to sprawdzasz?

    int globalStatus, int printerStatus;
    int result = PosnetProtocolLib.POS_GetPrnDeviceStatus(LocalDeviceHandle, statusMode, out globalStatus, out printerStatus);

ile teraz dostajesz w globalStatus, printerStatus i result?
czy LocalDeviceHandle nie jest null?

0
Azarien napisał(a):

nadal jest tak, że globalStatus oraz printerStatus zwraca 0 mimo, że drukarka fiskalna jest w trakcie transakcji. A funkcja zwraca POSNET_STATUS = 0.

a jak to sprawdzasz?

    int globalStatus, int printerStatus;
    int result = PosnetProtocolLib.POS_GetPrnDeviceStatus(LocalDeviceHandle, statusMode, out globalStatus, out printerStatus);

ile teraz dostajesz w globalStatus, printerStatus i result?
czy LocalDeviceHandle nie jest null?

LocalDeviceHandle posiada uchwyt - w chwili obecnej jego wartość wynosi 88014600
w globalStatus dostaje wartość 0. To samo z Printer status... tez 0.
Dodatkowo w zmiennej result zwracana jest wartość 0 - czyli OK.

Nie mam pojęcia dlaczego te 2 wartości (globalStatus oraz printerStatus) cały czas posiadają wartość 0....

0
Azarien napisał(a):

Skąd bierzesz to LocalDeviceHandle?
To (prawdopodobnie) powinno pozostać IntPtr. Jeśli mówiłem „wywal wszystkie IntPtry” to miałem na myśli wszystkie oprócz tego :D

Dobra mistrzu. Działa. Jednak ta metoda nie sprawdza czy transakcja jest stworzona itp. Ta metoda sprawdza tylko status sprzętowy.
Otworzyłem drukarke i uruchomiłem aplikację z próbą wydrukowania paragonu.
W zmiennych zostały mi zwrócone wartości globalStatus=3 oraz printerStatus=5.
Co więcej Twoje rozwiązanie mi pomogło.
**Dzięki wielkie za chęć pomocy! **

0

Witam,
czy może ktoś udostępnić fragment kodu, który od początku do końca zadziała?
Próbuję wykonać wydruk faktury na drukarce fiskalnej, niestety bez powodzenia.

Z góry dziękuję za pomoc.

Pozdrawiam,
Łukasz

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