Disclosure Statement: This site contains affiliate links, which means that I may receive a commission if you make a purchase using these links. As an eBay Partner, I earn from qualifying purchases.
If you find these projects useful please consider becoming a sponsor with Patreon, GitHub or Liberapay.

Threading? issue with PostWebMessageAsString() ...

Post Reply
Paul_Palaszewski
Posts: 4
Joined: Wed Mar 08, 2023 1:58 pm

Threading? issue with PostWebMessageAsString() ...

Post by Paul_Palaszewski »

Hi,

I'm using WebView4Delphi VCL for a POS frontend and experimented with various ways to communicate between local devices and the web application. Works fine to use a hostObject for web -> local comm to print receipts and show things on a customer display. Now I need to add the other way: Listening on a COM-Port and send everything we receive from there to the web server.

browser.PostWebMessageAsString() seems like a good mechanism for that. When triggered in on-button-click-pascal-code, the .html page receives the event with

Code: Select all

<script>
function rcvMsg(e) {
    console.log('got msg '+JSON.stringify(e.data)+'" from '+e.origin);
}
if (typeof chrome.webview != 'undefined')
    chrome.webview.addEventListener("message",rcvMsg,false);
</script>
But when I do the same in the COM-Port listening thread, I don't get any event. WebView2 uses lots of own threads so it should not make a difference, if the message is posted from the VCL UI thread or the COM-Port-listening-thread .. right?
Also checked with the debugger if the com-port-listening-thread has the same TWVBrowser instance ... it does. And it's initialized.

Any ideas, what it might be, that I'm missing here or how to get additional intel?

Kind regards,
Paul

This are (hopefully) the relevant parts of the code in question ...

Code: Select all

type
  TLottoComThread = class(TThread)
    procedure Execute; override;
  end;
  TMainForm = class(TForm)
    WVWindowParent1: TWVWindowParent;
    Timer1: TTimer;
    WVBrowser1: TWVBrowser;
...
  end;
var
  MainForm: TMainForm;

  LottoThread: TLottoComThread;
  LottoComFile: THandle;
  LottoRcvBuf: TBytes;
  LottoBufRead: LongWord;

implementation

procedure TLottoComThread.Execute;
var
  CommTimeouts: TCommTimeouts;
  FEventMask: DWORD;
  ComStat: TComStat;
  CPDCB: TDCB;
  result: Boolean;
begin
  SetLength(LottoRcvBuf, 512);
  while not(Terminated) do begin
    if LottoComFile = INVALID_HANDLE_VALUE then begin // not open?
      LottoComFile := CreateFile(ComPortLotto, GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
      if LottoComFile = INVALID_HANDLE_VALUE then begin
        MessageDlgPos(ComPortLotto + ' (Lotto Terminal) ist nicht verfügbar', TMsgDlgType.mtError, [mbOK], 0, -1, -1);
        exit;        
      end;
      FillChar(CPDCB, SizeOf(TDCB), 0);
      with CPDCB do begin
        DCBlength := SizeOf(TDCB);
        BaudRate := CBR_9600;
        ByteSize := 8;
        Parity := EVENPARITY;
        StopBits := ONESTOPBIT;
        ErrorChar := '?';
        EofChar := chr(13);
      end;
      if SetCommState(LottoComFile, CPDCB) then begin
        SetCommMask(LottoComFile, EV_RXCHAR or EV_ERR);
        with CommTimeouts do begin          // in ms
          ReadIntervalTimeout         := 10;
          ReadTotalTimeoutMultiplier  := 2;
          ReadTotalTimeoutConstant    := 1000;
          WriteTotalTimeoutMultiplier := 2;
          WriteTotalTimeoutConstant   := 1000;
        end;
        SetCommTimeouts(LottoComFile, CommTimeouts);
      end;
    end;
    if LottoComFile <> INVALID_HANDLE_VALUE then begin
      if WaitCommEvent(LottoComFile, FEventMask, nil) then
        if (FEventMask and EV_RXCHAR) > 0 then
          if ReadFile(LottoComFile, LottoRcvBuf[0], 512, LottoBufRead, nil) then begin
            if LottoBufRead > 0 then begin
        // TODO send to browser, make it post a message .. works in Button OnClick-method, but not here
              result := MainForm.WVBrowser1.PostWebMessageAsString('{"lotto":"Hello world"}');
              OutputDebugString(PChar('Received ' + IntToStr(LottoBufRead) + 'b on ' + ComPortLotto + ', posted ' + BoolToStr(result)));
            end;
          end else begin
            OutputDebugString(PChar('Could not read ' + ComPortLotto + ' error ' + IntToStr(GetLastError)));
          end;
    end;
  end;
  if (LottoComFile <> INVALID_HANDLE_VALUE) then begin
    CloseHandle(LottoComFile);
    LottoComFile := INVALID_HANDLE_VALUE;
  end;
end;
User avatar
salvadordf
Posts: 4374
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: Threading? issue with PostWebMessageAsString() ...

Post by salvadordf »

Hi,

The WebView2 documentation doesn't mention anything about calling threads :
https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.1587.40#postwebmessageasstring

I would try to call PostWebMessageAsString inside TThread.Synchronize or TThread.Queue. The BrowserHostAppCommunication demo works fine when you call PostWebMessageAsString from the main application thread so using TThread.Synchronize or TThread.Queue should fix this issue.
Paul_Palaszewski
Posts: 4
Joined: Wed Mar 08, 2023 1:58 pm

Re: Threading? issue with PostWebMessageAsString() ...

Post by Paul_Palaszewski »

Thanks, you're right, adding a Synchronize() fixed the issue.
Post Reply