2017-06-02 61 views
11

Ilekroć próbuję wykonać JavaScript przez C# przy użyciu CefSharp (Stable 57.0), pojawia się błąd. Po prostu próbuję uruchomić funkcję ostrzegania, aby upewnić się, że działa, a następnie przetestować ją za pomocą mojej własnej funkcji. Jednak wydaje mi się, że dostaję błędy, próbując to zrobić.Wykonywanie JavaScript na C# z CefSharp WPF powoduje błąd

public partial class WebBrowserWindow : Window 
{ 
    public WebBrowserWindow() 
    { 
     InitializeComponent(); 
     webBrowser.MenuHandler = new ContextMenuHandler(); 
     webBrowser.RequestHandler = new RequestHandler(); 
    } 

    //Trying to execute this with either method gives me an error. 
    public void ExecuteJavaScript() 
    { 
     //webBrowser.GetMainFrame().ExecuteJavaScriptAsync("alert('test')"); 

     //webBrowser.ExecuteScriptAsync("alert('test');"); 
    } 
} 

Próbowałem obu sposobów wykonywania skryptu.

Pierwszy:

webBrowser.GetMainFrame().ExecuteJavaScriptAsync("alert('test')"); 

daje mi ten błąd:

enter image description here

Drugi:

webBrowser.ExecuteScriptAsync("alert('test');"); 

daje mi ten błąd:

enter image description here

Moim celem jest stworzenie funkcji C#, która może wykonywać funkcję JavaScript w mojej przeglądarce CefSharp.

Próbowałem wielu linków/referencji i nie było ich zbyt wiele na przepełnieniu stosu. Czytałem również The FAQ for CefSharp i nie mogłem znaleźć żadnych prostych przykładów, które pozwalają mi wykonywać JavaScript w woli za pośrednictwem C#.

Ponadto zweryfikowałem zdarzenia, w których ramka jest załadowana (kończy się ładowanie), i jest ona rozładowywana (nie rozładowuje się), a jeśli przeglądarka internetowa ma wartość NULL (której nie ma), a wiadomość od :

webBrowser.GetMainFrame().ExecuteJavaScriptAsync("alert('test')"); 

nadal powoduje wystąpienie pierwszego błędu.

Testowałem pod GetMainFrame(). Zawsze zwraca wartość null. ZAWSZE. Nie ma znaczenia, jak długo czekam lub jakie warunki czekam.

WAŻNE

zapomniałem dodać jedną ważną informację, mam 2 zestawy w moim projekcie. Obaj kompilacji do oddzielnych plików wykonywalnych:

Helper.exe main.exe

main.exe ma okno „CallUI”, że gdy przycisk zostanie kliknięty, wykonuje sposób stworzyłem „ExecuteJavaScript() ", który znajduje się w moim oknie" BrowserWindow ". Okno CallUI zostało zadeklarowane i zainicjowane w Helper.exe.

Więc w zasadzie próbuję użyć osobnego programu, aby otworzyć okno, kliknij przycisk, który wywołuje metodę i wykonać javascript. Myślę więc, że ponieważ są to różne procesy, oznacza to, że przeglądarka ma zerową wartość. Jednak gdy robię to wszystko w Main.exe, to działa dobrze. Czy istnieje obejście, które pozwala mi użyć oddzielnego procesu do utworzenia okna z pliku Helper.exe i wykonania kodu Javascript z pliku Main.exe?

+0

Czy możesz utworzyć minimalny odtwarzalny przykład (kod źródłowy) na temat interakcji Main.exe i Helper.exe? Bez tego nie jest łatwo dostarczyć rozwiązanie i upewnić się, że działa. –

+0

Hej, mój problem został rozwiązany, okazało się, że muszę wdrożyć sposób, aby procesy mogły ze sobą rozmawiać (patrz moja długa odpowiedź poniżej). Miałem również dodatkowe pytanie dotyczące mojego rozwiązania (w sekcji komentarzy mojej odpowiedzi). – Rafael

Odpowiedz

4

Dotarła do mnie słuchy, że jestem Obchodzenie się problemu w niewłaściwy sposób.

Mój problem, w rzeczywistości, nie istnieje, jeśli jest to pojedynczy proces, w którym cały kod jest ze sobą powiązany. Jednak problem polegał na tym, że mój projekt ma plik wykonywalny, który próbował komunikować się z innym. Właściwie nigdy nie miałem sposobu, aby mój plik helper.exe poprawnie komunikował się z moim plikiem main.exe.

Czego się nauczyłem z tego, że procesy próbowały rozmawiać ze sobą bez jakiegokolwiek dostępu do wspólnego adresu. Żyją w oddzielnych przestrzeniach adresowych, więc za każdym razem, gdy mój helper.exe próbował wykonać tę część javascript należącą do Main.exe, próbował wykonać skrypt w niezainicjowanej wersji przeglądarki, która należała do jego własnej przestrzeni adresowej, a nie do głównej .exe.

Jak więc rozwiązać ten problem? Musiałem dołączyć ważny element, który pozwolił procesowi helper.exe na rozmowę z procesem main.exe. Podczas wyszukiwania w Google, jak procesy mogą ze sobą rozmawiać, dowiedziałem się o MemoryMappedFiles. Dlatego postanowiłem zaimplementować prosty przykład w moim programie, który pozwala Helper.exe na wysyłanie wiadomości do Main.exe.

Oto przykład. Ten plik jest tworzony ja nazywane „MemoryMappedHandler.cs”

public class MemoryMappedHandler 
{ 
    MemoryMappedFile mmf = MemoryMappedFile.CreateOrOpen("mmf1", 512); 
    MemoryMappedViewStream stream; 
    MemoryMappedViewAccessor accessor; 
    BinaryReader reader; 
    public static Message message = new Message(); 

    public MemoryMappedHandler() 
    { 
     stream = mmf.CreateViewStream(); 
     accessor = mmf.CreateViewAccessor(); 
     reader = new BinaryReader(stream); 

     new Thread(() => 
     { 
      while (stream.CanRead) 
      { 
       Thread.Sleep(500); 
       message.MyStringWithEvent = reader.ReadString(); 
       accessor.Write(0, 0); 
       stream.Position = 0; 
      } 
     }).Start(); 

    } 

    public static void PassMessage(string message) 
    { 
     try 
     { 
      using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("mmf1")) 
      { 
       using (MemoryMappedViewStream stream = mmf.CreateViewStream(0, 512)) 
       { 
        BinaryWriter writer = new BinaryWriter(stream); 
        writer.Write(message); 
       } 
      } 
     } 
     catch (FileNotFoundException) 
     { 
      MessageBox.Show("Cannot Send a Message. Please open Main.exe"); 
     } 
    } 
} 

ten jest kompilowany do biblioteki dll, że zarówno main.exe i Helper.exe mogą korzystać.

Helper.exe używa metody PassMessage(), aby wysłać wiadomość do pliku mapowanego z pamięci o nazwie "mmf1". Main.exe, który musi być otwarty przez cały czas, zajmuje się tworzeniem tego pliku, który może odbierać wiadomości od Helper.exe. Wysyłam tę wiadomość do klasy, która przechowuje tę wiadomość i za każdym razem, gdy ją otrzyma, aktywuje wydarzenie.

Oto co klasa Wiadomość wygląda następująco:

[Serializable] 
public class Message 
{ 
    public event EventHandler HasMessage; 

    public string _myStringWithEvent; 

    public string MyStringWithEvent 
    { 
     get { return _myStringWithEvent; } 
     set 
     { 
      _myStringWithEvent = value; 
      if (value != null && value != String.Empty) 
      { 
       if (HasMessage != null) 
        HasMessage(this, EventArgs.Empty); 
      } 
     } 
    } 
} 

Wreszcie miałem zainicjować wiadomość w mojej klasie WebBrowserWindow tak:

public partial class WebBrowserWindow : Window 
{ 
    public WebBrowserWindow() 
    { 
     InitializeComponent(); 
     webBrowser.MenuHandler = new ContextMenuHandler(); 
     webBrowser.RequestHandler = new RequestHandler(); 
     MemoryMappedHandler.message.HasMessage += Message_HasMessage; 
    } 

    private void Message_HasMessage(object sender, EventArgs e) 
    { 
     ExecuteJavaScript(MemoryMappedHandler.message.MyStringWithEvent); 
    } 

    public void ExecuteJavaScript(string message) 
    { 
     //webBrowser.GetMainFrame().ExecuteJavaScriptAsync("alert('test')"); 

     //webBrowser.ExecuteScriptAsync("alert('test');"); 
    } 
} 

A teraz pozwala mi uruchomić JavaScript Potrzebuję, wysyłając wiadomość z Helper.exe do Main.exe.

+0

Jeszcze jedno: chcę ulepszyć mój MemoryMappedFile. W tej chwili ma błąd, w którym jeśli wyślesz tę samą wiadomość z Helper.exe, wykona ją tylko za pierwszym razem (ze względu na sposób ustawienia właściwości wiadomości). Jak mogę wyczyścić strumień odbierający (MemoryMappedViewStream) (wewnątrz konstruktora MemoryMappedHandler)? Próbowałem wielu rzeczy, takich jak "Flush()", pisanie pustej wiadomości do mmf1 (usuwa tylko pierwszy znak wiadomości) itp. – Rafael

+0

Po chwili zastanowienia rozwiązałem problem opisany w moim komentarzu powyżej tego. – Rafael

3

Czy próbowałeś tego linku? Zawiera fragment, który sprawdza, czy przeglądarka jest inicjowana jako pierwsza.

cefsharp execute javascript

private void OnIsBrowserInitializedChanged(object sender, IsBrowserInitializedChangedEventArgs args) 
{ 
    if(args.IsBrowserInitialized) 
    { 
     browser.ExecuteScriptAsync("alert('test');"); 
    } 
} 
+1

Tak, już tego próbowałem. Wersja 57 CefSharp nie korzysta z IsBrowserInitializedChangedEventArgs na zdarzeniu IsBrowserInitializedChanged, korzysta z właściwości zależności. Co więcej, nadal nie jestem w stanie wykonać mojej metody niezależnie po potwierdzeniu, że przeglądarka jest zainicjalizowana/nie jest pusta, podając powyższy komunikat o błędzie. – Rafael

Powiązane problemy