2012-03-02 34 views
12

Đôi khi bạn muốn ứng dụng của mình mở ứng dụng mặc định cho một tệp. Ví dụ, để mở một tập tin PDF, bạn có thể sử dụng:Ứng dụng có được liên kết với tiện ích mở rộng đã cho không?

System.Diagnostics.Process.Start("Filename.pdf"); 


Để mở một hình ảnh, bạn chỉ muốn sử dụng cùng mã với một tên tập tin khác nhau:

System.Diagnostics.Process.Start("Filename.gif"); 


Một số phần mở rộng (Ví dụ, .gif) chỉ là về luôn luôn có một trình xử lý mặc định, ngay cả trong một cài đặt Windows cơ sở. Tuy nhiên, một số tiện ích mở rộng (ví dụ: .pdf) thường không có ứng dụng được cài đặt để xử lý chúng.

Trong những trường hợp này, bạn nên xác định xem ứng dụng có được liên kết với phần mở rộng của tệp mà bạn muốn mở trước khi thực hiện cuộc gọi tới Process.Start (tên tệp) hay không.

Tôi đang tự hỏi làm thế nào bạn có thể thực hiện tốt nhất cái gì đó như thế này:

static bool ApplicationAssociated(string extension) 
{ 
    var extensionHasAssociatedApplication = false; 

    var condition = // Determine if there is an application installed that is associated with the provided file extension.; 
    if (condition) 
    { 
     extensionHasAssociatedApplication = true; 
    } 

    return extensionHasAssociatedApplication; 
} 
+0

Đó là một nơi nào đó trong trình chỉnh sửa đăng ký. Cùng với các bộ xử lý cho nam châm :, mailto :, call: schemes vv Nó gần như ở gốc nếu tôi nhớ chính xác – f2lollpll

Trả lời

25

tôi sẽ giới thiệu theo những lời khuyên trong David's answer NHƯNG kể từ khi bạn cần để phát hiện một hiệp hội:

Để kiểm tra xem một tập tin có một hiệp hội bạn có thể sử dụng có nguồn gốc chức năng FindExecutable mà về cơ bản là những gì Windows Explorer sử dụng trong nội bộ ... nó đưa ra một mã lỗi tốt (SE_ERR_NOASSOC) nếu không có sự liên kết. Sau khi thành công, nó đưa ra một đường dẫn đến tệp thực thi tương ứng.

Ngài DllImport cho nó là

[DllImport("shell32.dll")] 
static extern int FindExecutable(string lpFile, string lpDirectory, [Out] StringBuilder lpResult); 

Một lựa chọn khác sẽ được đi bộ registry ví dụ (không khuyến khích từ phức tạp do một số aspets như WOW64, vv):

Kết hợp thực được lưu trữ trong khóa HKEY_CLASSES_ROOT\.pdf trỏ đến - trong trường hợp của tôi AcroExch.Document, vì vậy, chúng tôi thanh toán HKEY_CLASSES_ROOT\AcroExch.Document. Ở đó bạn có thể thấy (và thay đổi) lệnh nào sẽ được sử dụng để khởi chạy loại tệp đó:

HKEY_CLASSES_ROOT\AcroExch.Document\shell\open\command 
5

Trong một tình huống như thế phương pháp tốt nhất này là cố gắng để mở tài liệu và phát hiện thất bại. Cố gắng để dự đoán có hay không một hiệp hội tập tin được đặt ra chỉ dẫn đến bạn reimplementing các API thực thi shell. Rất khó để có được điều đó đúng và không cần thiết vì chúng đã tồn tại!

+0

Tôi đồng ý điều này là đơn giản nhất. Tuy nhiên, một vấn đề lớn với cách tiếp cận này, là bạn phải bằng cách nào đó ẩn tài liệu bạn đang mở - bạn không thực sự muốn người dùng nhìn thấy nó. – zmbq

+0

Cảm ơn nhận xét mang tính xây dựng. Tôi cũng thích cách tiếp cận đó. Tôi không thể, vì những lý do tôi sẽ không làm bạn chán nản. Thông số kỹ thuật rất cụ thể và trong khi tôi không đồng ý với lý do, tôi có một công việc cần làm. –

+0

@zmbq Nếu bạn không muốn người dùng xem tài liệu thì bạn chỉ đơn giản là không mở nó. –

1

Bạn cũng sẽ xem quá trình đăng ký để nhận thông tin đó.

Bạn có thể làm theo từ:

HKEY_CLASSES_ROOT\.extension 

và nó thường dẫn đến một cái gì đó giống như HKEY_CLASSES_ROOT\extfile\Shell\Open\Command

và bạn sẽ đến với các lệnh để mở loại tệp.

Tùy thuộc vào những gì bạn đang làm, nó có thể là lý tưởng để chỉ yêu cầu sự tha thứ (có nghĩa là, chỉ cần mở file và xem)

+0

Bạn có chắc là đủ không? Visual Studio một số loại ma thuật voodoo, nơi các tập tin .sln có một biểu tượng khác nhau dựa trên phiên bản Visual Studio đã tạo ra chúng. Điều này là ma quái, và có lẽ không được lưu trữ nơi bạn nói. – zmbq

+0

@zmbq - Nếu bạn thấy 'HKEY_CLASSES_ROOT', bạn sẽ thấy các định dạng khác nhau cho một tệp sln, được xử lý bởi phiên bản khác nhau của VS. Biểu tượng được xác định trong 'DefaultIcon'. Về cơ bản, tất cả các thông tin là có. http://stackoverflow.com/questions/4693562/how-does-windows-know-what-version-of-visual-studio-a-sln-file-relates-to – manojlds

1

Tất cả các thông tin mà sống trong registry .. bạn có thể điều hướng đến HKEY_CLASSES_ROOT , tìm phần mở rộng và đi từ đó để tìm trình xử lý mặc định. Nhưng tùy thuộc vào loại tập tin và bộ xử lý liên quan (s), bạn sẽ cần phải lội vào CLSIDs và whatnot ... bạn có lẽ tốt hơn off bắt một ngoại lệ thay thế.

1

Thông tin này nằm trong sổ đăng ký. Ví dụ:

# Mount the HKCR drive in powershell 
ps c:\> new-psdrive hkcr registry hkey_classes_root 
ps c:\> cd hkcr:\.cs 

# get default key for .cs 
PS hkcr:\.cs> gp . "" 
(default) : VisualStudio.cs.10.0 
... 

# dereference the "open" verb 
PS hkcr:\.cs> dir ..\VisualStudio.cs.10.0\shell\open 

    Hive: hkey_classes_root\VisualStudio.cs.10.0\shell\open 

Name       Property 
----       -------- 
Command      (default) : "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe" /dde 
ddeexec      (default) : Open("%1") 
4

@Yahia gật đầu. Tôi đang đăng giải pháp nhanh chóng của tôi cho hậu thế để bạn có thể xem những gì tôi đã làm. Có rất nhiều cải tiến có thể cho mã này, nhưng điều này sẽ cung cấp cho bạn ý tưởng:

public static bool HasExecutable(string path) 
{ 
    var executable = FindExecutable(path); 
    return !string.IsNullOrEmpty(executable); 
} 

private static string FindExecutable(string path) 
{ 
    var executable = new StringBuilder(1024); 
    FindExecutable(path, string.Empty, executable); 
    return executable.ToString(); 
} 

[DllImport("shell32.dll", EntryPoint = "FindExecutable")] 
private static extern long FindExecutable(string lpFile, string lpDirectory, StringBuilder lpResult); 
+0

Tại sao bạn sử dụng StringBuilder (1024) thay vì StringBuilder()? – mggSoft

+3

@mggSoft Phương thức gốc FindExecutable yêu cầu một bộ đệm để trả về đường dẫn thực thi. Tài liệu chỉ định tham số _This phải chứa giá trị không null hợp lệ và được giả định là có độ dài MAX_PATH_. Vì vậy, trong khi 1024 là một chút overkill, ghi đè dung lượng StringBuilder mặc định với giá trị của MAX_PATH (260) được khuyến khích. – Yaurthek

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