2011-01-14 9 views
7

Mam Exe konsoli C++, który robi pewne programowanie. Teraz chciałem napisać C# GUI, który wykonuje niektóre z programów, które robi program w C++. Myślałam o kilku podejściach,Pisanie C# GUI nad C++ lub C++ exe

  1. Wpisz C# GUI z wszystkich programów w C++ wykonane od podstaw. (Nie chcę to zrobić dla ilości przeróbek to pociąga za sobą)
  2. Budowanie C dll ++ który robi programowanie i czy zostało zaimportowane w aplikacji GUI. (Teraz tutaj mam obawy.Jak przechwytywać wyjście z procedur w dll C++ i wyświetlać go w GUI? Powinienem zwrócić wynik jako ciąg dla każdej procedury, że aplikacja Ponieważ nie wiem, zarządzam C++ iam będzie budować niezarządzaną bibliotekę C++.)
+0

Czy za dodanie interfejsu COM? Ponieważ IMHO, przekazywanie argumentów i danych programu z kontenerami COM może być rozwiązaniem. –

Odpowiedz

7

Budowanie biblioteki dll C++/CLI naprawdę nie jest takie trudne. Zasadniczo korzystasz z niezarządzanego kodu C++, z wyjątkiem tego, że definiujesz "public ref class", który zawiera funkcje, które chcesz zobaczyć w kodzie C#.

Jakie dane wracasz? Pojedyncze liczby, macierze liczb, złożone obiekty?

AKTUALIZACJA: Ponieważ wyjaśniono, że "dane wyjściowe" to iostreams, here is a project demonstrują przekierowanie cout do aplikacji .NET wywołującej bibliotekę. Przekierowanie clog lub cerr wymagałoby po prostu garstki dodatkowych linii w DllMain wzorowanych na istniejącym przekierowaniu.

The zip file zawiera pliki projektu VS2010, ale kod źródłowy powinien również pracować w roku 2005 lub 2008.

Funkcja przechwytywania iostreams jest zawarty w poniższym kodzie:

// compile this part without /clr 
class capturebuf : public std::stringbuf 
{ 
protected: 
    virtual int sync() 
    { 
     // ensure NUL termination 
     overflow(0); 
     // send to .NET trace listeners 
     loghelper(pbase()); 
     // clear buffer 
     str(std::string()); 
     return __super::sync(); 
    } 
}; 

BOOL WINAPI DllMain(_In_ HANDLE _HDllHandle, _In_ DWORD _Reason, _In_opt_ LPVOID _Reserved) 
{ 
    static std::streambuf* origbuf; 
    static capturebuf* altbuf; 
    switch (_Reason) 
    { 
    case DLL_PROCESS_ATTACH: 
     origbuf = std::cout.rdbuf(); 
     std::cout.rdbuf(altbuf = new capturebuf()); 
     break; 
    case DLL_PROCESS_DETACH: 
     std::cout.rdbuf(origbuf); 
     delete altbuf; 
     break; 
    } 

    return TRUE; 
} 

// compile this helper function with /clr 
void loghelper(char* msg) { Trace::Write(gcnew System::String(msg)); } 
+0

Chcę wyświetlić komunikaty dziennika, które pochodzą z biblioteki DLL C++ w C# GUI. – excray

+0

@ user97642: Więc DLL C++ pisze do 'std :: clog' i chcesz wysłać to wyjście do C#? –

+0

Tak zapychać lub cout lub cerr. – excray

3

Po prostu chcesz wywołać bibliotekę C++ z zarządzanego kodu .net?

Następnie trzeba albo zbudować obiekt COM, albo bibliotekę, której nie można dokonać w języku C++. Każde podejście ma swoje wady i zalety w zależności od potrzeb biznesowych. Musiałbyś przekazać dane konsumentowi. W obu koncepcjach jest mnóstwo ton materiału.

0

Można po prostu napisać wrapper C# GUI (jak sugerujesz w opcji 2) i odrodzić proces C++; jednakże będzie to trochę powolne (nie wiem, czy to ma znaczenie).

Aby uruchomić swój plik exe C++ i przechwycić dane wyjściowe, można użyć zestawu ProcessRunner. Oto podstawowe użytkowanie:

using CSharpTest.Net.Processes; 
partial class Program 
{ 
    static int Main(string[] args) 
    { 
     ProcessRunner run = new ProcessRunner("svn.exe", "update"); 
     run.OutputReceived += new ProcessOutputEventHandler(run_OutputReceived); 
     return run.Run(); 
    } 

    static void run_OutputReceived(object sender, ProcessOutputEventArgs args) 
    { 
     Console.WriteLine("{0}: {1}", args.Error ? "Error" : "Output", args.Data); 
    } 
} 
+0

Iam szuka sposobu, aby dowiedzieć się drugą opcję. Interfejs graficzny w języku C# z biblioteką C++. – excray

0

prawdopodobnie najlepszym sposobem, aby przejść tutaj jest wykorzystanie P/Invoke lub Platform Invoke. W zależności od struktury lub interfejsu C++ dll możesz zawinąć go w czysty interfejs C; jest najłatwiejszy, jeśli twój interfejs używa tylko typów blittable. Jeśli ograniczysz interfejs dll do typów blittable (Int32, Single, Boolean, Int32 [], Single [], Double [] - podstawy) nie będziesz musiał wykonywać żadnych złożonych połączeń danych między zarządzanym (C#) i niezarządzanych (C) pamięci.

Na przykład w kodzie C# definiujesz dostępne połączenia w bibliotece dll C/C++ za pomocą atrybutu DllImport.

[DllImport, "ExactDllName.dll"] 
static extern boolean OneOfMyCoolCRoutines([In] Double[] x, [In] Double[] y, [Out] Double result) 

Małych [In] i [Out] nie są ściśle wymagane, ale mogą przyspieszyć rzeczy. Teraz dodając "ExactDllName.dll" jako odniesienie do projektu C#, możesz wywołać swoją funkcję C/C++ z kodu C#.

fixed(Double *x = &x[0], *y = &y[0]) 
{ 
    Boolean returnValue = OneOfMyCoolCRoutines(x, y, r); 
} 

Zauważ, że zasadniczo przekazuję wskaźniki z powrotem i czwarte pomiędzy moją biblioteką dll i kodem C#. To może spowodować błędy w pamięci, ponieważ lokalizacje tych tablic mogą zostać zmienione przez zbieracz śmieci CLR, ale biblioteka dll C/C++ nic o tym nie wie. Aby się tego zabezpieczyć, po prostu poprawiłem te wskaźniki w moim C#, a teraz nie będą one poruszać się w pamięci, podczas gdy moja biblioteka dll działa na tych tablicach. To jest teraz niebezpieczny kod i będę musiał skompilować mój kod C# z/tą flagą.

Istnieje wiele drobnych szczegółów, które mogą współdziałać z językiem, ale to powinno spowodować, że się toczysz. Trzymanie się bezpaństwowego interfejsu C typów blittable to świetna polityka, jeśli to możliwe. Dzięki temu twój kod interopowy będzie najczystszy.

Powodzenia

Paul