2009-04-16 41 views
58

Tôi đã đọc rất nhiều về cách kích hoạt một ứng dụng từ bên trong một chương trình C# (Process.Start()), nhưng tôi đã không thể tìm thấy bất kỳ thông tin nào về cách ứng dụng mới này chạy trong một bảng điều khiển của tôi Chương trình C#. Ví dụ, tôi muốn một nút bấm để mở một notepad.exe WITHIN ứng dụng của tôi, không phải bên ngoài.Làm cách nào để chạy một ứng dụng khác trong bảng điều khiển của chương trình C#?

Trả lời

12

Tôi không biết nếu điều này vẫn là điều được khuyến khích sử dụng nhưng khung "Liên kết đối tượng và nhúng" cho phép bạn nhúng các đối tượng/điều khiển nhất định trực tiếp vào ứng dụng của bạn. Điều này có thể sẽ chỉ hoạt động đối với một số ứng dụng nhất định, tôi không chắc liệu Notepad có phải là một trong số đó hay không. Đối với những thứ thực sự đơn giản như notepad, có thể bạn sẽ có thời gian dễ dàng hơn khi làm việc với các điều khiển hộp văn bản được cung cấp bởi bất kỳ phương tiện nào bạn đang sử dụng (ví dụ: WinForms).

Dưới đây là một liên kết đến thông tin OLE để bắt đầu:

http://en.wikipedia.org/wiki/Object_Linking_and_Embedding

-1
ngắn Trả lời:

Không

hơi ngắn Trả lời:

Chỉ khi ứng dụng khác được thiết kế để cho phép nó, bằng cách cung cấp linh kiện cho bạn để thêm vào ứng dụng của riêng bạn.

+2

@PaulSonier - ngay cả khi câu trả lời ngắn là hoàn toàn sai? ;-) Câu trả lời ngắn gọn là Có –

1

Nếu bạn muốn chạy notepad bên trong ứng dụng của bạn, bạn có lẽ sẽ tốt hơn với một thành phần soạn thảo văn bản. Rõ ràng là một hộp văn bản cơ bản đi kèm với WinForms, nhưng tôi nghi ngờ các thành phần nâng cao cung cấp chức năng Notepad (hoặc tốt hơn) có thể được tìm thấy trên interweb.

+0

Notepad chỉ là một ví dụ cho mục đích thử nghiệm! –

1

Tôi biết điều này là có thể nếu ứng dụng khác có thể đính kèm chính nó vào một cửa sổ win32 xử lý. Ví dụ, chúng ta có một ứng dụng C# riêng biệt lưu trữ một ứng dụng DirectX bên trong một trong các cửa sổ của nó. Tôi không quen với các chi tiết chính xác về cách thực hiện điều này, nhưng tôi nghĩ rằng chỉ cần chuyển win32 Handle của bảng điều khiển của bạn sang ứng dụng khác là đủ để ứng dụng đó đính kèm bề mặt DirectX của nó.

86

Sử dụng API win32 có thể "ăn" một ứng dụng khác. Về cơ bản bạn nhận được cửa sổ trên cùng cho ứng dụng đó và đặt nó là cha mẹ để trở thành tay cầm của bảng bạn muốn đặt nó vào. Nếu bạn không muốn hiệu ứng kiểu MDI, bạn cũng phải điều chỉnh kiểu cửa sổ để làm cho nó tối đa và loại bỏ thanh tiêu đề.

Dưới đây là một số mẫu mã đơn giản, nơi tôi có một hình thức với một nút và một bảng điều khiển:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using System.Diagnostics; 
using System.Runtime.InteropServices; 
using System.Threading; 

namespace WindowsFormsApplication2 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
      Process p = Process.Start("notepad.exe"); 
      Thread.Sleep(500); // Allow the process to open it's window 
      SetParent(p.MainWindowHandle, panel1.Handle); 
     } 

     [DllImport("user32.dll")] 
     static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); 
    } 
} 

Tôi chỉ thấy một ví dụ khác, nơi họ gọi là WaitForInputIdle thay vì ngủ. Vì vậy, các mã sẽ là như thế này:

Process p = Process.Start("notepad.exe"); 
p.WaitForInputIdle(); 
SetParent(p.MainWindowHandle, panel1.Handle); 

Dự án Mã có một bài viết tốt một toàn bộ quá trình: Hosting EXE Applications in a WinForm project

+14

Siêu hữu ích! liên kết không hiển thị dll nhập khẩu cho các chức năng của họ vì vậy tôi nghĩ id chia sẻ chúng ở đây [DllImport ("user32.dll")] static extern IntPtr SetParent (IntPtr hWndChild, IntPtr hWndNewParent); [DllImport ("user32.dll")] static extern int SetWindowLong (IntPtr hWnd, int nIndex, int dwNewLong); [DllImport ("user32.dll")] static extern bool MoveWindow (Xử lý IntPtr, int x, int y, int w, int h, bool repaint); – hrh

+0

mã này cũng chạy trong wpf –

+0

Khi tôi sử dụng mã này với IE hoặc Chrome, phần trên cùng của trình duyệt hiển thị dưới dạng màu đen. Có cách nào để thay đổi điều này thành minh bạch để nó hiển thị màu của cửa sổ chính của tôi không? – user21479

2
  • Thêm một số giải pháp trong trả lời .. **

này mã đã giúp tôi để dock một số thực thi trong các hình thức cửa sổ. như NotePad, Excel, từ, trình đọc Acrobat n nhiều hơn nữa ...

Nhưng nó sẽ không hoạt động đối với một số ứng dụng. Đôi khi khi bạn bắt đầu quá trình của một số ứng dụng .... chờ đợi cho thời gian nhàn rỗi ... và cố gắng để có được mainWindowHandle của nó ....cho đến khi cửa sổ xử lý chính trở nên vô .....

vì vậy tôi đã thực hiện một thủ thuật để giải quyết này

Nếu bạn nhận được xử lý cửa sổ chính là null ... sau đó tìm kiếm tất cả các quá trình runnning trên sytem và tìm thấy bạn xử lý ... sau đó nhận được các hadle chính của quá trình và bảng điều khiển thiết lập như là cha mẹ của nó.

 ProcessStartInfo info = new ProcessStartInfo(); 
     info.FileName = "xxxxxxxxxxxx.exe"; 
     info.Arguments = "yyyyyyyyyy"; 
     info.UseShellExecute = true; 
     info.CreateNoWindow = true; 
     info.WindowStyle = ProcessWindowStyle.Maximized; 
     info.RedirectStandardInput = false; 
     info.RedirectStandardOutput = false; 
     info.RedirectStandardError = false; 

     System.Diagnostics.Process p = System.Diagnostics.Process.Start(info); 

     p.WaitForInputIdle(); 
     Thread.Sleep(3000); 

     Process[] p1 ; 
    if(p.MainWindowHandle == null) 
    { 
     List<String> arrString = new List<String>(); 
     foreach (Process p1 in Process.GetProcesses()) 
     { 
      // Console.WriteLine(p1.MainWindowHandle); 
      arrString.Add(Convert.ToString(p1.ProcessName)); 
     } 
     p1 = Process.GetProcessesByName("xxxxxxxxxxxx"); 
     //p.WaitForInputIdle(); 
     Thread.Sleep(5000); 
     SetParent(p1[0].MainWindowHandle, this.panel2.Handle); 

    } 
    else 
    { 
    SetParent(p.MainWindowHandle, this.panel2.Handle); 
    } 
1

Tôi nhận thấy rằng tất cả các câu trả lời trước đều sử dụng các hàm thư viện người dùng Win32 cũ hơn để thực hiện việc này. Tôi nghĩ rằng điều này sẽ hoạt động trong hầu hết các trường hợp, nhưng sẽ hoạt động kém đáng tin cậy hơn theo thời gian.

Bây giờ, không thực hiện việc này, tôi không thể cho bạn biết nó hoạt động tốt như thế nào, nhưng tôi biết rằng công nghệ Windows hiện tại có thể là giải pháp tốt hơn: Desktop Windows Manager API.

DWM là công nghệ tương tự cho phép bạn xem bản xem trước hình thu nhỏ trực tiếp của ứng dụng bằng thanh tác vụ và trình chuyển đổi tác vụ nhiệm vụ. Tôi tin rằng nó liên quan chặt chẽ đến các dịch vụ Remote Terminal.

Tôi nghĩ rằng một vấn đề có thể xảy ra khi bạn buộc ứng dụng là một cửa sổ cha mẹ không phải là cửa sổ máy tính để bàn là một số nhà phát triển ứng dụng sẽ đưa ra giả định về bối cảnh thiết bị (DC), con trỏ (chuột) vị trí, chiều rộng màn hình, vv, có thể gây ra hành vi thất thường hoặc có vấn đề khi nó được "nhúng" trong cửa sổ chính. Tôi nghi ngờ rằng bạn có thể loại bỏ phần lớn các vấn đề này bằng cách dựa vào DWM để giúp bạn quản lý các bản dịch cần thiết để có cửa sổ ứng dụng được trình bày một cách đáng tin cậy và tương tác với bên trong cửa sổ vùng chứa của ứng dụng khác.

Tài liệu giả định lập trình C++, nhưng tôi đã tìm thấy một người đã sản xuất những gì mà anh ấy tuyên bố là thư viện trình bao bọc C# nguồn mở: https://bytes.com/topic/c-sharp/answers/823547-desktop-window-manager-wrapper. Bài đăng cũ, và nguồn không nằm trên một kho lưu trữ lớn như GitHub, bitbucket hoặc sourceforge, vì vậy tôi không biết nó hiện tại như thế nào.

1

Một giải pháp thú vị để Luch một ứng dụng exeternal với một container WinForm là sau:

[DllImport("user32.dll")] 
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); 


private void Form1_Load(object sender, EventArgs e) 
{ 
    ProcessStartInfo psi = new ProcessStartInfo("notepad.exe"); 
    psi.WindowStyle = ProcessWindowStyle.Minimized; 
    Process p = Process.Start(psi); 
    Thread.Sleep(500); 
    SetParent(p.MainWindowHandle, panel1.Handle); 
    CenterToScreen(); 
    psi.WindowStyle = ProcessWindowStyle.Normal; 
} 

Các bước để ProcessWindowStyle.Minimized từ ProcessWindowStyle.Normal loại bỏ sự chậm trễ gây phiền nhiễu.

enter image description here

Các vấn đề liên quan