PDA

View Full Version : [C#]Inserire la finestra di un programma esterno al progetto in un altra del progetto


Mattyfog
10-04-2010, 22:10
Salve a tutti,
avete presenti quei programmi nei quali compaiono + finestre? Intendo proprio finestre "classiche" con la crocetta per chiudere, la barretta per rimpicciolire a icona e così via... Ad esempio come in questo pezzetto di un immagine:
http://www.galliprogetti.it/img/pwfines.jpg
Bene, non so se è possibile, ma io vorrei semplicemente far apparire la finestra di firefox all'interno del mio programma.
C'è un modo? Se c'è bene se no pazienza ma mi incuriosiva saperlo :)
Ditemi anche solo cosa cercare su google.

Mattyfog
11-04-2010, 16:30
Come al solito pretendo velocità :asd: scherzo.. comunque :help:

nikel
12-04-2010, 08:37
vuoi aprire una form all'interno di una form? se fosse un form del programma basterebbe dargli dei limiti di coordinate... non credo si posso fare con un programma esterno. (se hai bisogno di aprire pagine internet c'è il controllo webbrowser)

tomminno
12-04-2010, 08:57
Salve a tutti,
avete presenti quei programmi nei quali compaiono + finestre? Intendo proprio finestre "classiche" con la crocetta per chiudere, la barretta per rimpicciolire a icona e così via... Ad esempio come in questo pezzetto di un immagine:
http://www.galliprogetti.it/img/pwfines.jpg
Bene, non so se è possibile, ma io vorrei semplicemente far apparire la finestra di firefox all'interno del mio programma.
C'è un modo? Se c'è bene se no pazienza ma mi incuriosiva saperlo :)
Ditemi anche solo cosa cercare su google.

Quelli a cui ti riferisci te sono i programmi MDI e per integrare firefox lo devi fare come faresti per qualunque altro programma: scaricare l'sdk di firefox e riuscire ad integrarlo (buona fortuna!).

gugoXX
12-04-2010, 09:05
Salve a tutti,
avete presenti quei programmi nei quali compaiono + finestre? Intendo proprio finestre "classiche" con la crocetta per chiudere, la barretta per rimpicciolire a icona e così via... Ad esempio come in questo pezzetto di un immagine:
http://www.galliprogetti.it/img/pwfines.jpg
Bene, non so se è possibile, ma io vorrei semplicemente far apparire la finestra di firefox all'interno del mio programma.
C'è un modo? Se c'è bene se no pazienza ma mi incuriosiva saperlo :)
Ditemi anche solo cosa cercare su google.

Certo che Firefox in C#...
Se fosse internet explorer sarebbe piu' semplice.

Mattyfog
12-04-2010, 14:45
A me interesserebbe solamente aprire firefox, non interagirci.
Guardate qua per esempio: http://bytes.com/topic/c-sharp/answers/557678-resize-exe-i-started-windows-forms-panel la domanda che fa l'utente è un altra ma parte dal presupposto di avere "integrato" il notepad in una form. Sempre che non si riferisca a qualcosa tipo la richtextbox (se si chiama così) o comunque controlli presenti già in visual studio...
Ad ogni modo lui ha fatto così:

ProcessStartInfo psi = new ProcessStartInfo("notepad");
p = Process.Start(psi);
p.WaitForInputIdle();
SetParent(p.MainWindowHandle, uiAppPanel.Handle);
ShowWindow(p.MainWindowHandle, (int)ShowCommands.SW_MAXIMIZE);
int style = GetWindowLong(p.MainWindowHandle, GWL_STYLE);
SetWindowLong(p.MainWindowHandle, GWL_STYLE, style & ~WS_CAPTION);

Non capisco precisamente tutti i comandi, ad ogni modo credete sia giusto?

Mattyfog
12-04-2010, 20:23
ho provato questo codice:

Process p = Process.Start("notepad.exe");
p.WaitForInputIdle();
SetParent(p.MainWindowHandle, panel1.Handle);
MoveWindow(p.MainWindowHandle, 0, 0, panel1.Width, panel1.Height, false);
[DllImport("user32.dll")] static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll")] private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int w, int h, bool repaint);

ma in fase di compilazione ho diversi errori, inoltre non so bene neppure a che serve :D

Mattyfog
13-04-2010, 20:20
:D

astorcas
13-04-2010, 23:14
ho provato questo codice:

Process p = Process.Start("notepad.exe");
p.WaitForInputIdle();
SetParent(p.MainWindowHandle, panel1.Handle);
MoveWindow(p.MainWindowHandle, 0, 0, panel1.Width, panel1.Height, false);
[DllImport("user32.dll")] static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll")] private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int w, int h, bool repaint);

ma in fase di compilazione ho diversi errori, inoltre non so bene neppure a che serve :D

qua vai di interop, cmq che errori ti dà? Il panel1 che vedo fra i parametri lo hai aggiunto alla tua form, vero? :)

Mattyfog
14-04-2010, 18:45
A tal proposito che tipo di panel deve essere panel1? Va bene uno stackpanel? (lavoro in wpf)
Comunque ecco gli errori (sono generati dalla penultima riga di codice):
Errore 1 È previsto il segno }
Errore 2 È prevista una classe, un delegato, un enum, un'interfaccia o uno struct
Errore 3 È prevista una classe, un delegato, un enum, un'interfaccia o uno struct
Errore 4 È previsto un identificatore
Errore 5 È prevista una classe, un delegato, un enum, un'interfaccia o uno struct
Errore 6 È prevista una classe, un delegato, un enum, un'interfaccia o uno struct
Errore 7 È previsto un identificatore
Errore 8 Uno spazio dei nomi non può contenere direttamente membri come campi o metodi
Errore 9 È prevista una classe, un delegato, un enum, un'interfaccia o uno struct
Errore 10 È previsto un identificatore
Errore 11 È prevista una classe, un delegato, un enum, un'interfaccia o uno struct
Errore 12 È previsto un identificatore
Errore 13 È previsto un identificatore
Errore 14 Errore di sintassi, è previsto ']'
Errore 15 È prevista una classe, un delegato, un enum, un'interfaccia o uno struct
Errore 16 È prevista una classe, un delegato, un enum, un'interfaccia o uno struct
Errore 17 È prevista la definizione del tipo o dello spazio dei nomi oppure la fine del file
Errore 18 '[' è un termine non valido nell'espressione
Errore 19 È previsto un punto e virgola (;)
Errore 20 ']' è un termine non valido nell'espressione
Errore 21 È previsto un punto e virgola (;)
Errore 22 È previsto un punto e virgola (;)

astorcas
14-04-2010, 19:48
A tal proposito che tipo di panel deve essere panel1? Va bene uno stackpanel? (lavoro in wpf)
Comunque ecco gli errori (sono generati dalla penultima riga di codice):
Errore 1 È previsto il segno }
Errore 2 È prevista una classe, un delegato, un enum, un'interfaccia o uno struct
Errore 3 È prevista una classe, un delegato, un enum, un'interfaccia o uno struct
Errore 4 È previsto un identificatore
Errore 5 È prevista una classe, un delegato, un enum, un'interfaccia o uno struct
Errore 6 È prevista una classe, un delegato, un enum, un'interfaccia o uno struct
Errore 7 È previsto un identificatore
Errore 8 Uno spazio dei nomi non può contenere direttamente membri come campi o metodi
Errore 9 È prevista una classe, un delegato, un enum, un'interfaccia o uno struct
Errore 10 È previsto un identificatore
Errore 11 È prevista una classe, un delegato, un enum, un'interfaccia o uno struct
Errore 12 È previsto un identificatore
Errore 13 È previsto un identificatore
Errore 14 Errore di sintassi, è previsto ']'
Errore 15 È prevista una classe, un delegato, un enum, un'interfaccia o uno struct
Errore 16 È prevista una classe, un delegato, un enum, un'interfaccia o uno struct
Errore 17 È prevista la definizione del tipo o dello spazio dei nomi oppure la fine del file
Errore 18 '[' è un termine non valido nell'espressione
Errore 19 È previsto un punto e virgola (;)
Errore 20 ']' è un termine non valido nell'espressione
Errore 21 È previsto un punto e virgola (;)
Errore 22 È previsto un punto e virgola (;)

non conosco bene wpf ma credo che lo stackpanel possa andare bene, alla fine ne prende le dimensioni, quindi basta che abbia una proprietà Weight e un'altra Height. Quegli errori sembrano derivare dal fatto che hai schiaffato il codice a casaccio. :fagiano:

questa roba


[DllImport("user32.dll")] static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll")] private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int w, int h, bool repaint);



devi metterla all'interno di una dichiarazione della classe mentre


Process p = Process.Start("notepad.exe");
p.WaitForInputIdle();
SetParent(p.MainWindowHandle, panel1.Handle);
MoveWindow(p.MainWindowHandle, 0, 0, panel1.Width, panel1.Height, false);



va messa all'interno di un metodo

Mattyfog
14-04-2010, 21:06
Ops :D
Senti ancora un problema ma cosa devo includere nel progetto?
Intendo using ecc ecc perchè ciò che ho messo io non va.. Mi riferisco a ciò che serve per importare la dll

astorcas
14-04-2010, 23:17
Ops :D
Senti ancora un problema ma cosa devo includere nel progetto?
Intendo using ecc ecc perchè ciò che ho messo io non va.. Mi riferisco a ciò che serve per importare la dll

L'attributo DllImport si trova in System.Runtime.InteropServices (http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.aspx)

Mattyfog
15-04-2010, 14:03
Non trovo il tipo di panel giusto da usare... Ho provato:
Canvas
DockPanel
Grid
StackPanel
ToolBarOverflowPanel
UniformGrid
VirtualizingPanel
VirtualizingStackPanel
WrapPanel
E nessuno funziona...

tomminno
15-04-2010, 14:32
Non trovo il tipo di panel giusto da usare... Ho provato:
Canvas
DockPanel
Grid
StackPanel
ToolBarOverflowPanel
UniformGrid
VirtualizingPanel
VirtualizingStackPanel
WrapPanel
E nessuno funziona...

Scusa ma hai idea di cosa stai facendo?
Hai copiato il codice da qualche parte?
Sarà che il codice che hai copiato è per WinForms mentre te stai usando WPF?
Che vuol dire nessuno funziona? Che errori hai? Che codice hai scritto?

Mattyfog
15-04-2010, 15:08
Appunto non so che ipo di panel usare su wpf......

tomminno
15-04-2010, 15:30
Appunto non so che ipo di panel usare su wpf......

Si ma ripeto:
Che vuol dire nessuno funziona? Che errori hai? Che codice hai scritto?

Mattyfog
15-04-2010, 15:50
panel1 è di tipo StackPanel ed ecco gli errori:
Errore 1 'System.Windows.Controls.StackPanel' non contiene una definizione di 'Handle' e non è stato trovato alcun metodo di estensione 'Handle'che accetta un primo argomento di tipo 'System.Windows.Controls.StackPanel'. Probabilmente manca una direttiva using o un riferimento a un assembly. 133 50
Errore 2 La corrispondenza migliore del metodo di overload per 'Mattyfog_Music_Youtuber.Window1.MoveWindow(System.IntPtr, int, int, int, int, bool)' presenta alcuni argomenti non validi 134 13
Errore 3 Argomento '4': impossibile convertire da 'double' a 'int' 134 50
Errore 4 Argomento '5': impossibile convertire da 'double' a 'int' 134 64
Mentre in un metodo ho scritto questo:
Process p = Process.Start("notepad.exe");
p.WaitForInputIdle();
SetParent(p.MainWindowHandle, panel1.Handle);
MoveWindow(p.MainWindowHandle, 0, 0, panel1.Width, panel1.Height, false);
}

e fuori da metodi ho scritto, nella stessa classe del metodo:

[DllImport("user32.dll")] static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll")] private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int w, int h, bool repaint);

tomminno
15-04-2010, 16:04
panel1 è di tipo StackPanel ed ecco gli errori:
Errore 1 'System.Windows.Controls.StackPanel' non contiene una definizione di 'Handle' e non è stato trovato alcun metodo di estensione 'Handle'che accetta un primo argomento di tipo 'System.Windows.Controls.StackPanel'. Probabilmente manca una direttiva using o un riferimento a un assembly. 133 50
Errore 2 La corrispondenza migliore del metodo di overload per 'Mattyfog_Music_Youtuber.Window1.MoveWindow(System.IntPtr, int, int, int, int, bool)' presenta alcuni argomenti non validi 134 13
Errore 3 Argomento '4': impossibile convertire da 'double' a 'int' 134 50
Errore 4 Argomento '5': impossibile convertire da 'double' a 'int' 134 64
Mentre in un metodo ho scritto questo:
Process p = Process.Start("notepad.exe");
p.WaitForInputIdle();
SetParent(p.MainWindowHandle, panel1.Handle);
MoveWindow(p.MainWindowHandle, 0, 0, panel1.Width, panel1.Height, false);
}



Che è ovvio visto che i controlli WPF non sono realizzati tramite finestre Win32 ma disegnati su una scena 2d.
Non esiste alcun Handle di finestra se non quello della finestra principale che può essere recuperato cosi: http://www.codeproject.com/KB/WPF/MessageBox.aspx.

Mattyfog
22-04-2010, 18:59
Quindi io ho scritto così:

Process p = Process.Start("notepad.exe");
p.WaitForInputIdle();
SetParent(new WindowWrapper(p.MainWindowHandle), panel1.Handle);
MoveWindow(new WindowWrapper(p.MainWindowHandle), 0, 0, panel1.Width, panel1.Height, false);

e questa classe:

public class WindowWrapper : System.Windows.Forms.IWin32Window
{
public WindowWrapper(IntPtr handle)
{
_hwnd = handle;
}

public IntPtr Handle
{
get { return _hwnd; }
}

private IntPtr _hwnd;
}

ma ho diversi errori:
Errore 1 'System.Windows.Controls.StackPanel' non contiene una definizione di 'Handle' e non è stato trovato alcun metodo di estensione 'Handle'che accetta un primo argomento di tipo 'System.Windows.Controls.StackPanel'. Probabilmente manca una direttiva using o un riferimento a un assembly. 133 69
Errore 2 La corrispondenza migliore del metodo di overload per 'Mattyfog_Music_Youtuber.Window1.MoveWindow(System.IntPtr, int, int, int, int, bool)' presenta alcuni argomenti non validi 134 13
Errore 3 Argomento '1': impossibile convertire da 'WindowWrapper' a 'System.IntPtr' 134 24
Errore 4 Argomento '4': impossibile convertire da 'double' a 'int' 134 69
Errore 5 Argomento '5': impossibile convertire da 'double' a 'int' 134 83

tomminno
22-04-2010, 22:53
panel1 non ha una proprietà Handle perchè lo StackPanel non è una finestra Win32.

Inoltre te hai wrappato un oggetto Win32 nella classe WindowWrapper che in realtà converte da un Handle WPF a uno Win32

Mattyfog
23-04-2010, 18:34
Ma quindi come posso fare?

tomminno
23-04-2010, 20:40
Ma quindi come posso fare?

Prova a vedere qui (http://www.drdobbs.com/windows/197003872;jsessionid=U2RRMWG4CD2WPQE1GHRSKH4ATMY32JVN?pgno=2)

Mattyfog
30-04-2010, 19:51
Raga potrei usare un windows host form in cui inserire un panel per integrare l'exe esterno?
Però non ho capito, anche se ho guardato l'esempio che mi avete linkato, come ricavare l'handle della finestra principale del process.

Mattyfog
02-05-2010, 11:58
:D

tomminno
02-05-2010, 19:56
Raga potrei usare un windows host form in cui inserire un panel per integrare l'exe esterno?
Però non ho capito, anche se ho guardato l'esempio che mi avete linkato, come ricavare l'handle della finestra principale del process.

Cos'è uno scherzo? Il codice per recuperare l'Handle del processo ce l'hai già, è quello che hai postato te.

Mattyfog
02-05-2010, 20:53
Ho creato un windowshostform con all'interno un panel e scritto questo codice:

System.Windows.Forms.Panel panel1 = this.FindName("panel1") as System.Windows.Forms.Panel;
Process p = Process.Start(@"D:\Program Files (x86)\Mozilla Firefox\firefox.exe");
p.WaitForInputIdle();
SetParent(p.MainWindowHandle, panel1.Handle);
MoveWindow(p.MainWindowHandle, 0, 0, panel1.Width, panel1.Height, false);

file xaml:
<Window x:Class="Mattyfog_Music_Youtuber.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wfi="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
Title="Window1" Height="700" Width="800">

...

<WindowsFormsHost Name="windowsFormsHost_firefox" Height="250" Width="250">
<wf:Panel Name="panel1" Height="245" Width="245"/>
</WindowsFormsHost>

però firefox si apre fuori dalla finestra del programma e in più visual studio mi indica questo errore:
Impossibile creare un'istanza di 'Window1' definita nell'assembly 'Mattyfog Music Youtuber, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Eccezione generata dalla destinazione di una chiamata. Errore nel file di markup 'Window1.xaml', riga 1, posizione 9.

Mattyfog
03-05-2010, 19:04
modificando il codice .xaml così non ricevo errori ma la finestra di firefox compare sempre fuori dal mio software:

<WindowsFormsHost Name="windowsFormsHost_firefox" Height="250" Width="250">
<wf:Panel x:Name="panel1" Height="245" Width="245"/>
</WindowsFormsHost>

Mattyfog
06-05-2010, 18:39
Non riesco a risolvere...

tomminno
07-05-2010, 00:29
Non riesco a risolvere...

Non risolvi perchè ti ostini ad usare codice pensato per le Windows Form in un contesto WPF.
Panel non ti serve a niente.

Hai creato una classe ereditando da HwndHost?
Devi inserire il codice di creazione del processo esterno nel metodo BuildWindowCore.
Fatto questo puoi aggiungere la tua classe come child di qualunque controllo wpf.

Ma se anche tu arrivassi alla soluzione del problema (fattibilissimo), ti ritrovi nell'impossibilità di far passare gli eventi mouse e tastiera al programma integrato.
Una volta creata la tua classe derivata da HwndHost devi lavorare di hook per catturare gli eventi e rimbalzarli verso il processo ospitato tramite SendMessage.

E detto questo perchè non usi il webbrowser wpf?

Mattyfog
07-05-2010, 10:26
Mi viene più utile firefox perchè mi è più facile individuare dei file temporanei.
Credevo bastasse integrare il panel in un windowshostform. :(
Oggi proverò a guardare ciò che mi hai consigliato...

EDIT: credo che ci rinuncerò è al di fuori della mia portata. In ogni caso ci proverò.

tomminno
07-05-2010, 11:31
Mi viene più utile firefox perchè mi è più facile individuare dei file temporanei.
Credevo bastasse integrare il panel in un windowshostform. :(
Oggi proverò a guardare ciò che mi hai consigliato...

EDIT: credo che ci rinuncerò è al di fuori della mia portata. In ogni caso ci proverò.

Non hai comunque modo di interagire con firefox, come ti avevo detto fin dal principio. Ma questo è valido per qualunque software. Ovvero l'unico modo che hai per navigare è andare a colpi di kill e start (o installi l'hook)

E poi a che ti servono i file temporanei? Generalmente un browser si usa per la visualizzazione dei dati.

Mattyfog
07-05-2010, 22:39
Ho guardato un po' su internet (http://msdn.microsoft.com/en-us/library/ms752055.aspx) e ho provato a fare qualcosa, il codice viene compilato ed eseguito senza errori, ma la finestra di firefox non appare.
Come noterete il l'hook non è ancora stato implementato.
File Window1.xaml.cs (quello principale del progetto)

IntPtr hwnd_firefox;
Mattyfog_Music_Youtuber.ControlHost controlHost;
System.Windows.Application app_firefox;
Window window_firefox;

[DllImport("user32.dll")] static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll")] private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int w, int h, bool repaint);

private void On_UIReady(object sender, EventArgs e)
{
app_firefox = System.Windows.Application.Current;
window_firefox = app_firefox.MainWindow;
window_firefox.SizeToContent = SizeToContent.WidthAndHeight;
controlHost = new ControlHost(ControlHostElement.ActualHeight, ControlHostElement.ActualWidth);
ControlHostElement.Child = controlHost;
controlHost.MessageHook += new HwndSourceHook(ControlMsgFilter);
hwnd_firefox = controlHost.hwndPanel;
Process p = Process.Start(@"D:\Program Files (x86)\Mozilla Firefox\firefox.exe");
p.WaitForInputIdle();
SetParent(p.MainWindowHandle, controlHost.Handle);
MoveWindow(p.MainWindowHandle, 0, 0, 300, 300, false);
}

private IntPtr ControlMsgFilter(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
return IntPtr.Zero;
}


[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Unicode)]
internal static extern int SendMessage(IntPtr hwnd,
int msg,
IntPtr wParam,
IntPtr lParam);

[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Unicode)]
internal static extern int SendMessage(IntPtr hwnd,
int msg,
int wParam,
[MarshalAs(UnmanagedType.LPWStr)] StringBuilder lParam);

[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Unicode)]
internal static extern IntPtr SendMessage(IntPtr hwnd,
int msg,
IntPtr wParam,
String lParam);

Classe ControlHost.cs

#region Using directives

using System;
//using System.Drawing;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using System.Runtime.InteropServices;

#endregion


namespace Mattyfog_Music_Youtuber
{
public class ControlHost : HwndHost
{
IntPtr hwndControl;
IntPtr hwndHost;
int hostHeight, hostWidth;

public ControlHost(double height, double width)
{
hostHeight = (int)height;
hostWidth = (int)width;
}
protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
hwndControl = IntPtr.Zero;
hwndHost = IntPtr.Zero;

hwndHost = CreateWindowEx(0, "static", "",
WS_CHILD | WS_VISIBLE,
0, 0,
hostWidth, hostHeight,
hwndParent.Handle,
(IntPtr)HOST_ID,
IntPtr.Zero,
0);

hwndControl = CreateWindowEx(0, "panel", "",
WS_CHILD | WS_VISIBLE | LBS_NOTIFY
| WS_VSCROLL | WS_BORDER,
0, 0,
hostWidth, hostHeight,
hwndHost,
(IntPtr)PANEL_ID,
IntPtr.Zero,
0);

return new HandleRef(this, hwndHost);
}
protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
handled = false;
return IntPtr.Zero;
}

protected override void DestroyWindowCore(HandleRef hwnd)
{
DestroyWindow(hwnd.Handle);
}
public IntPtr hwndPanel
{
get { return hwndControl; }
}
//PInvoke declarations
[DllImport("user32.dll", EntryPoint = "CreateWindowEx", CharSet = CharSet.Unicode)]
internal static extern IntPtr CreateWindowEx(int dwExStyle,
string lpszClassName,
string lpszWindowName,
int style,
int x, int y,
int width, int height,
IntPtr hwndParent,
IntPtr hMenu,
IntPtr hInst,
[MarshalAs(UnmanagedType.AsAny)] object pvParam);
[DllImport("user32.dll", EntryPoint = "DestroyWindow", CharSet = CharSet.Unicode)]
internal static extern bool DestroyWindow(IntPtr hwnd);
internal const int
WS_CHILD = 0x40000000,
WS_VISIBLE = 0x10000000,
LBS_NOTIFY = 0x00000001,
HOST_ID = 0x00000002,
PANEL_ID = 0x00000001,
WS_VSCROLL = 0x00200000,
WS_BORDER = 0x00800000;
}
}

file xaml:

<StackPanel Grid.Row="2">
<Border Name="ControlHostElement" Height="400" Width="400">

</Border>
</StackPanel>

tomminno
08-05-2010, 17:44
In BuildWindowCore ci devi mettere il codice per far avviare firefox, non creare una finestra Win32 ex-novo.

Tutto il codice di interazione Win32 rimane confinato nella classe derivata da HwndHost.
Non hai bisogno nemmeno dell'evento On_UIReady, in qualunque punto del codice scriverai:

ControlHostElement.Child = ControlHost;

Mattyfog
09-05-2010, 17:10
Quindi in BuildWindowCore dovrebbe bastare scrivere

Process p = Process.Start(@"D:\Program Files (x86)\Mozilla Firefox\firefox.exe");
p.WaitForInputIdle();
SetParent(p.MainWindowHandle, hwndParent.Handle);
MoveWindow(p.MainWindowHandle, 0, 0, 300, 300, false);

return new HandleRef(this, hwndHost);

Eppure non va quindi non ho capito qualcosa. Non va nel senso che il codice non dà errori nè in fase di compilazione nè in fase di esecuzione però non accade niente. Firefox non viene avviato neanche esternamente alla finestra.

ps:
credo che tu intendessi ControlHostElement.Child = controlHost; vero? Perchè con C maiuscola non va...

tomminno
09-05-2010, 22:54
Eppure non va quindi non ho capito qualcosa. Non va nel senso che il codice non dà errori nè in fase di compilazione nè in fase di esecuzione però non accade niente. Firefox non viene avviato neanche esternamente alla finestra.


A me questo codice funziona:

private IntPtr hwndHost;

protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
Process ff = Process.Start(@"C:\Program Files\Mozilla Firefox\firefox.exe");
ff.WaitForInputIdle();
hwndHost = ff.MainWindowHandle;

int oldStyle = GetWindowLong(hwndHost, GWL_STYLE);
SetWindowLong(hwndHost, GWL_STYLE, oldStyle | WS_CHILD);

SetParent(hwndHost, hwndParent.Handle);

return new HandleRef(this, hwndHost);
}


E sul costruttore della Window WPF:

hwndPlaceholder.Child = new FirefoxHost();


Mi raccomando di non avere già un firefox aperto altrimenti ottieni una bella eccezione, dato che il processo che viene avviato termina all'istante.

Mattyfog
10-05-2010, 18:27
Ho questo errore durante l'esecuzione:
BuildWindowCore non ha restituito l'handle della finestra figlio ospitata.

IntPtr hwndControl;
IntPtr hwndHost;
int hostHeight, hostWidth;

public FirefoxHost(double height, double width)
{
hostHeight = (int)height;
hostWidth = (int)width;
}
protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
/*hwndControl = IntPtr.Zero;
hwndHost = IntPtr.Zero;

Process p = Process.Start(@"D:\Program Files (x86)\Mozilla Firefox\firefox.exe");
p.WaitForInputIdle();
SetParent(p.MainWindowHandle, hwndParent.Handle);
MoveWindow(p.MainWindowHandle, 0, 0, 300, 300, false);

return new HandleRef(this, hwndHost);*/


Process ff = Process.Start(@"D:\Program Files (x86)\Mozilla Firefox\firefox.exe");
ff.WaitForInputIdle();
hwndHost = ff.MainWindowHandle;

int oldStyle = GetWindowLong(hwndHost, GWL_STYLE);
SetWindowLong(hwndHost, GWL_STYLE, oldStyle | WS_CHILD);

SetParent(hwndHost, hwndParent.Handle);

return new HandleRef(this, hwndHost);

}
protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
handled = false;
return IntPtr.Zero;
}

protected override void DestroyWindowCore(HandleRef hwnd)
{
DestroyWindow(hwnd.Handle);
}
public IntPtr hwndPanel
{
get { return hwndControl; }
}
//PInvoke declarations
[DllImport("user32.dll", EntryPoint = "CreateWindowEx", CharSet = CharSet.Unicode)]
internal static extern IntPtr CreateWindowEx(int dwExStyle,
string lpszClassName,
string lpszWindowName,
int style,
int x, int y,
int width, int height,
IntPtr hwndParent,
IntPtr hMenu,
IntPtr hInst,
[MarshalAs(UnmanagedType.AsAny)] object pvParam);
[DllImport("user32.dll", EntryPoint = "DestroyWindow", CharSet = CharSet.Unicode)]
internal static extern bool DestroyWindow(IntPtr hwnd);
internal const int
WS_CHILD = 0x40000000,
WS_VISIBLE = 0x10000000,
LBS_NOTIFY = 0x00000001,
HOST_ID = 0x00000002,
PANEL_ID = 0x00000001,
WS_VSCROLL = 0x00200000,
WS_BORDER = 0x00800000,
GWL_STYLE = -16;

[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll")]
private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int w, int h, bool repaint);
[DllImport("user32.dll", SetLastError = true)]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

tomminno
10-05-2010, 19:22
Ho questo errore durante l'esecuzione:
BuildWindowCore non ha restituito l'handle della finestra figlio ospitata.


Avevi per caso una finestra di firefox già aperta?
Hai provato in debug?

Mattyfog
10-05-2010, 21:34
Il punto è che (scusa se non te l'ho detto) che firefox si avvia per conto suo al di fuori della finestra.
Tu hai provato? Puoi allegare il tuo progetto completo?

Mattyfog
12-05-2010, 22:17
heilaa :P
:)

Mattyfog
14-05-2010, 14:41
UP ;)

Mattyfog
15-05-2010, 11:40
please :)

tomminno
16-05-2010, 10:17
Il codice è lo stesso che ti ho postato precedentemente:

public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
InitPanel();
}

private void InitPanel()
{
hwndPlaceholder.Child = new FirefoxHost();
}
}

class FirefoxHost : HwndHost
{
#region Win32
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", SetLastError = true)]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("User32", ExactSpelling = true)]
private static extern int SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter,
int x, int y, int cx, int cy, uint uFlags);
[DllImport("user32.dll", SetLastError = true)]
static extern bool DestroyWindow(IntPtr hWnd);
[DllImport("coredll")]
static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);

const int GWL_STYLE = -16;
const int GWL_EXSTYLE = -20;

const uint SWP_NOSIZE = 0x0001;
const uint SWP_NOMOVE = 0x0002;
const uint SWP_NOZORDER = 0x0004;
const uint SWP_NOREDRAW = 0x0008;
const uint SWP_NOACTIVATE = 0x0010;
const uint SWP_FRAMECHANGED = 0x0020;
const uint SWP_SHOWWINDOW = 0x0040;
const uint SWP_HIDEWINDOW = 0x0080;
const uint SWP_NOCOPYBITS = 0x0100;
const uint SWP_NOOWNERZORDER = 0x0200;
const uint SWP_NOSENDCHANGING = 0x0400;

// Window Styles
const int WS_OVERLAPPED = 0;
const uint WS_POPUP = 0x80000000;
const int WS_CHILD = 0x40000000;
const int WS_MINIMIZE = 0x20000000;
const int WS_VISIBLE = 0x10000000;
const int WS_DISABLED = 0x8000000;
const int WS_CLIPSIBLINGS = 0x4000000;
const int WS_CLIPCHILDREN = 0x2000000;
const int WS_MAXIMIZE = 0x1000000;
const int WS_CAPTION = 0xC00000;
const int WS_BORDER = 0x800000;
const int WS_DLGFRAME = 0x400000;
const int WS_VSCROLL = 0x200000;
const int WS_HSCROLL = 0x100000;
const int WS_SYSMENU = 0x80000;
const int WS_THICKFRAME = 0x40000;
const int WS_GROUP = 0x20000;
const int WS_TABSTOP = 0x10000;
const int WS_MINIMIZEBOX = 0x20000;
const int WS_MAXIMIZEBOX = 0x10000;
const int WS_TILED = WS_OVERLAPPED;
const int WS_ICONIC = WS_MINIMIZE;
const int WS_SIZEBOX = WS_THICKFRAME;

// Extended Window Styles
const int WS_EX_DLGMODALFRAME = 0x0001;
const int WS_EX_NOPARENTNOTIFY = 0x0004;
const int WS_EX_TOPMOST = 0x0008;
const int WS_EX_ACCEPTFILES = 0x0010;
const int WS_EX_TRANSPARENT = 0x0020;
const int WS_EX_MDICHILD = 0x0040;
const int WS_EX_TOOLWINDOW = 0x0080;
const int WS_EX_WINDOWEDGE = 0x0100;
const int WS_EX_CLIENTEDGE = 0x0200;
const int WS_EX_CONTEXTHELP = 0x0400;
const int WS_EX_RIGHT = 0x1000;
const int WS_EX_LEFT = 0x0000;
const int WS_EX_RTLREADING = 0x2000;
const int WS_EX_LTRREADING = 0x0000;
const int WS_EX_LEFTSCROLLBAR = 0x4000;
const int WS_EX_RIGHTSCROLLBAR = 0x0000;
const int WS_EX_CONTROLPARENT = 0x10000;
const int WS_EX_STATICEDGE = 0x20000;
const int WS_EX_APPWINDOW = 0x40000;
const int WS_EX_OVERLAPPEDWINDOW = (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
const int WS_EX_PALETTEWINDOW = (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST);
const int WS_EX_LAYERED = 0x00080000;
const int WS_EX_NOINHERITLAYOUT = 0x00100000;
const int WS_EX_LAYOUTRTL = 0x00400000;
const int WS_EX_COMPOSITED = 0x02000000;
const int WS_EX_NOACTIVATE = 0x08000000;

const uint WM_CLOSE = 0x0010;
#endregion

private IntPtr hwndHost;

protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
Process notePadProc = Process.Start(@"C:\Program Files\Mozilla Firefox\firefox.exe");

notePadProc.WaitForInputIdle();

hwndHost = notePadProc.MainWindowHandle;

int oldStyle = GetWindowLong(hwndHost, GWL_STYLE);
SetWindowLong(hwndHost, GWL_STYLE, oldStyle | WS_CHILD);
SetParent(hwndHost, hwndParent.Handle);

return new HandleRef(this, hwndHost);
}



protected override void DestroyWindowCore(HandleRef hwnd)
{
HandleRef handleRef = new HandleRef(this, hwndHost);
SendMessage(handleRef.Handle, WM_CLOSE, 0, 0);
DestroyWindow(hwnd.Handle);
}

}



Come precisato per farlo funzionare non devi avere un'altra istanza di firefox aperta.

Mattyfog
18-05-2010, 19:20
Non va ancora... Potresti allegarmi i file dell'intero progetto?

tomminno
18-05-2010, 19:29
Non va ancora... Potresti allegarmi i file dell'intero progetto?

Guarda non credo che con il progetto intero risolveresti niente.
Hai provato in debug?
Hai provato ad aggiungere un pò di ritardo dopo WaitForInputIdle?

Mattyfog
18-05-2010, 20:30
Io sono sempre in debug...
Senti ma quindi dovrei fermare (per un attimo) il Thread principale del mio software? Come faccio a farlo al di fuori della classe Window1? Perchè non so da dove ricavare il Thread principale del mio software...
Poi devo usareil metodo Sleep() giusto?

tomminno
18-05-2010, 22:32
Io sono sempre in debug...
Senti ma quindi dovrei fermare (per un attimo) il Thread principale del mio software? Come faccio a farlo al di fuori della classe Window1? Perchè non so da dove ricavare il Thread principale del mio software...
Poi devo usareil metodo Sleep() giusto?

Non è che ti sei imbarcato in un'impresa troppo ardua?

Il ritardo a cui mi riferivo era ovviamente uno Sleep per dare il tempo a Firefox di avviarsi.
Io non ne ho bisogno per far funzionare quel codice ma ho visto in giro esempi che utilizzano lo sleep proprio dopo WaitForInputIdle (o al suo posto).

Io più di così non so come aiutarti.

Mattyfog
19-05-2010, 19:07
Tommy ti stimoooooooooooooooooooooooooo!
Ora va!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Stragrazie strainfiniteeeeee!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Senti ancora un'ultima cosa, ma a cosa mi dovrebbe servire l'hook?
Io con firefox riesco a interagirci (lato utente posso usarlo tranquillamente). Quindi non serve?

tomminno
19-05-2010, 19:16
Tommy ti stimoooooooooooooooooooooooooo!
Ora va!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Stragrazie strainfiniteeeeee!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Senti ancora un'ultima cosa, ma a cosa mi dovrebbe servire l'hook?
Io con firefox riesco a interagirci (lato utente posso usarlo tranquillamente). Quindi non serve?

A me ad esempio il funzionamento della tastiera è del tutto aleatorio e in ogni caso l'invio non mi funziona, ho problemi di focus ecc.

Mattyfog
19-05-2010, 21:31
Emm si effettivamente la tastiera non va :D Beh a questo vedo di pensarci dopo...
Senti, quando chiudo l'applicazione, in modalità debug mi viene segnalato un errore: Impossibile caricare la DLL 'coredll': Impossibile trovare il modulo specificato. (Eccezione da HRESULT: 0x8007007E).

//codice che fa parte della classe per integrare firefox
protected override void DestroyWindowCore(HandleRef hwnd)
{
HandleRef handleRef = new HandleRef(this, hwndHost);
SendMessage(handleRef.Handle, WM_CLOSE, 0, 0); //genera l'errore DestroyWindow(hwnd.Handle);
}


Infatti in background rimane aperto il processo di firefox...

tomminno
19-05-2010, 22:03
Perchè ho sbagliato a scrivere DllImport:

[DllImport("user32.dll")]
static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);


Per quanto riguarda gli eventi della tastiera ho trovato questo articolo: http://blogs.msdn.com/nickkramer/archive/2005/07/18/439680.aspx
E' molto vecchio e per C++/CLI però qualche problema potrebbe risolverlo. O forse no visto che parte da un CreateWindowEx e non da un processo esterno.

Mattyfog
19-05-2010, 22:10
Ok grazie domani guardo.