如果將一個資料檔案與一個可執行檔關聯,那麼就可以通過雙擊資料檔案來直接執行可執行檔,比如雙擊以txt為副檔名的文字檔,系統就會自動執行Notepad.exe檔案來編輯它,這就是因為txt檔案是與Notepad.exe檔案關聯的。
檔案關聯是在註冊表的HKEY_CLASSES_ROOT根鍵中設定的。要為某種副檔名設定關聯,需要在HKEY_CLASSES_ROOT根鍵下設定兩個子鍵,第一個子鍵的名稱是“.副檔名”(和資料檔案的副檔名相對應),這個子鍵需要設定預設值,預設值的資料為HKEY_CLASSES_ROOT根鍵下另一個子鍵的名稱,在這個子鍵下可以繼續設定與這種資料檔案關聯的可執行檔名。
如果關聯的操作方式是“開啟”,那麼在第二個子鍵中,可以繼續建立“shell/open/command”子鍵,並把command子鍵的預設值設為可執行檔名,這樣雙擊資料檔案,就會執行這個可執行檔;如果關聯的操作方式是“列印”,那麼可以在第二個子鍵中繼續建立“shell/print/command”子鍵,同樣將command子鍵的預設值設為執行列印操作的可執行檔名。當然,也可以只設定“open”操作的關聯。經過這兩個步驟,檔案關聯就設定好了。
以“*.test”資料檔案為例,要在HKEY_CLASSES_ROOT根鍵下建立一個“.test”子鍵,把它的預設值設定為“testfile”,然後再建立一個“testfile/shell/open/command”子鍵,並把command鍵的預設值設定為指定的可執行檔名。
下面這段代碼就是將“*.test”資料檔案與當前可執行檔進行關聯:
// associate.c
// 本程式將設定註冊表,把.test檔案和本程式關聯起來,關聯成功後,雙擊.test檔案
// windows 將自動開啟本檔案
// 要設定一個程式和特定副檔名的檔案關聯,需要做以下2步
// 1. 在 HKEY_CLASSES_ROOT 下面建立一個以副檔名為鍵名的子鍵,比如,你要關聯.test檔案
// 則需要在它下面建立一個.test的子鍵,然後建立一個預設的索引值,即只有索引值沒有鍵名的鍵
// 這個索引值是建立第2個鍵的鍵名,比如我們取鍵名為testfile
// 2. 在 HKEY_CLASSES_ROOT 下面再建立一個子鍵,這個子鍵是第1步建立的鍵名,如testfile
// 如果你要開啟一個檔案,則在這子鍵下建立shell/open/command子鍵,索引值為:
// 可執行檔名稱 %1
//
// 建立成功後的結構可能如下:
// HKEY_CLASSES_ROOT
// |
// |---.test (有一個預設的索引值 testfile)[預設 = testfile]
// |
// |--- testfile
// |
// |--shell
// |
// |--open
// |
// |--command (有一個預設的索引值: 如 c:/associate.exe %1)
// [預設 = c:/associate.exe %1]
#include <Windows.h>
#include "resource.h"
HWND hWinMain = NULL;
char szKeyEnter[] = TEXT("testfile");
char szKeyExt1[] = TEXT(".test");
char szKeyExt2[] = TEXT("testfile//shell//open//command");
char szParam[] = TEXT(" /"%1/"");
char szDelSub1[] = TEXT("testfile//shell//open");
char szDelSub2[] = TEXT("testfile//shell");
void SetAssociate();
void DelAssociate();
BOOL IsAssociate();
LRESULT CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance, IN LPSTR lpCmdLine, IN int nShowCmd )
{
DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, DialogProc, 0);
return 0;
}
void SetAssociate()
{
HKEY hKey;
char szFileName[MAX_PATH];
if ( ERROR_SUCCESS == RegCreateKey(HKEY_CLASSES_ROOT, szKeyExt1, &hKey))
{
RegSetValueEx(hKey, NULL, 0, REG_SZ, szKeyEnter, sizeof(szKeyEnter));
RegCloseKey(hKey);
}
if ( ERROR_SUCCESS == RegCreateKey(HKEY_CLASSES_ROOT, szKeyExt2, &hKey) )
{
GetModuleFileName(NULL, szFileName, sizeof(szFileName));
lstrcat(szFileName, szParam);
RegSetValueEx(hKey, NULL, 0, REG_EXPAND_SZ, szFileName, strlen(szFileName) + 1);
RegCloseKey(hKey);
}
}
void DelAssociate()
{
HKEY hKey;
RegDeleteKey(HKEY_CLASSES_ROOT, szKeyExt1);
// NT下只能一層一層的刪除
// testfile//shell//open//command
if ( ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, szDelSub1, 0, KEY_WRITE, &hKey) )
{
RegDeleteKey(hKey, "command"); // 刪除command這一層
RegCloseKey(hKey);
}
if ( ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, szDelSub2, 0, KEY_WRITE, &hKey))
{
RegDeleteKey(hKey, "open"); // 刪除open這一層
RegCloseKey(hKey);
}
if ( ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, szKeyEnter, 0, KEY_WRITE, &hKey))
{
RegDeleteKey(hKey, "shell"); // 刪除shell這一層
RegCloseKey(hKey);
}
RegDeleteKey(HKEY_CLASSES_ROOT, szKeyEnter); // 刪除testfile這一層
}
BOOL IsAssociate()
{
HKEY hKey;
if ( ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, szKeyExt1, 0, KEY_WRITE, &hKey) )
{
RegCloseKey(hKey);
return TRUE;
}
return FALSE;
}
LRESULT CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch ( uMsg )
{
case WM_CLOSE:
EndDialog(hWnd, 0);
break;
case WM_INITDIALOG:
hWinMain = hWnd;
if ( IsAssociate() )
{
CheckDlgButton(hWnd, IDC_ASSOCIATE, BST_CHECKED);
}
break;
case WM_COMMAND:
if ( LOWORD(wParam) == IDC_ASSOCIATE &&
HIWORD(wParam) == BN_CLICKED )
{
if ( IsDlgButtonChecked(hWinMain, IDC_ASSOCIATE) )
SetAssociate();
else
DelAssociate();
}
break;
default:
return FALSE;
}
return TRUE;
}
// resource.h
#define IDD_MAIN 101
#define IDC_ASSOCIATE 1000
#define IDC_STATIC -1
// associate.rc
#include "resource.h"
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_MAIN DIALOG DISCARDABLE 0, 0, 143, 73
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "檔案關聯樣本"
FONT 10, "宋體"
BEGIN
CONTROL "將本程式關聯到 .test 檔案",IDC_ASSOCIATE,"Button",
BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,7,7,129,18
LTEXT "說明:關聯之後,當你雙擊 .test檔案的時候,windows會自動開啟本程式,取消關聯,把前面的勾去掉即可",
IDC_STATIC,7,31,129,35
END
當程式運行起來之後,你選中複選框之後,就將本程式和.test檔案關聯起來了。這時候你可以關閉程式,然後隨便建立一個空的.test檔案,比如a.test,你雙擊一下這個a.test檔案,你發現本程式被啟動起來了,然後你取消複選框關閉程式,再雙擊a.test你發現程式就不會再啟動。這是一個簡單的關聯實現。你可以參照本程式,設計出更複雜的關聯,甚至可以將關聯的檔案表徵圖也改掉。
本程式理論部分來源於羅雲彬32位組合語言一書,原始碼也是由組合語言改寫而來。查看該程式的彙編版本,可以參看此書。