本文為系列第二篇,詳細說明 MCI (Media Control Interface) 開啟/關閉光碟機托盤 的核心函數實作,以及開機自動執行的登錄表讀寫操作。
使用 mciSendCommand 控制 CDAudio 裝置,流程:
開啟裝置 → 發送開門/關門命令 → 關閉裝置
function OpenCDROM(Drive: PChar): Boolean;
var
Res: MCIERROR;
OpenParm: TMCI_OPEN_PARMS;
Flags: DWORD;
s: string;
DeviceID: Word;
begin
Result := False;
s := Drive + ':';
Flags := MCI_OPEN_TYPE or MCI_OPEN_ELEMENT;
with OpenParm do begin
dwCallback := 0;
lpstrDeviceType := 'CDAudio'; // 裝置類型:CD 音訊
lpstrElementName := PChar(s); // 元素名稱:磁碟機代號 (如 "D:")
end;
// 1. 開啟裝置
Res := mciSendCommand(0, MCI_OPEN, Flags, Longint(@OpenParm));
if Res <> 0 then Exit;
DeviceID := OpenParm.wDeviceID;
try
// 2. 發送開門命令
Res := mciSendCommand(DeviceID, MCI_SET, MCI_SET_DOOR_OPEN, 0);
if Res = 0 then Exit; // 失敗則跳出
Result := True;
finally
// 3. 關閉裝置釋放資源
mciSendCommand(DeviceID, MCI_CLOSE, Flags, Longint(@OpenParm));
end;
end;
function CloseCDROM(Drive: PChar): Boolean;
var
Res: MCIERROR;
OpenParm: TMCI_OPEN_PARMS;
Flags: DWORD;
s: string;
DeviceID: Word;
begin
Result := False;
s := Drive + ':';
Flags := MCI_OPEN_TYPE or MCI_OPEN_ELEMENT;
with OpenParm do begin
dwCallback := 0;
lpstrDeviceType := 'CDAudio';
lpstrElementName := PChar(s);
end;
Res := mciSendCommand(0, MCI_OPEN, Flags, Longint(@OpenParm));
if Res <> 0 then Exit;
DeviceID := OpenParm.wDeviceID;
try
// 發送關門命令
Res := mciSendCommand(DeviceID, MCI_SET, MCI_SET_DOOR_CLOSED, 0);
if Res = 0 then Exit;
Result := True;
finally
mciSendCommand(DeviceID, MCI_CLOSE, Flags, Longint(@OpenParm));
end;
end;
| 常數 | 數值/用途 |
|---|---|
| MCI_OPEN | 打開裝置命令 |
| MCI_CLOSE | 關閉裝置命令 |
| MCI_SET | 設定裝置狀態命令 |
| MCI_OPEN_TYPE | 指定 lpstrDeviceType |
| MCI_OPEN_ELEMENT | 指定 lpstrElementName |
| MCI_SET_DOOR_OPEN | 彈出托盤 |
| MCI_SET_DOOR_CLOSED | 收回托盤 |
| lpstrDeviceType = 'CDAudio' | 標準 CD 音訊裝置類型 |
procedure TForm1.mAutoRunClick(Sender: TObject);
var Reg: TRegistry;
begin
if Application.ExeName = '' then begin
MessageBox(Handle, '應用程式檔名不可為空。', '錯誤', MB_OK + MB_ICONERROR);
Exit;
end;
Reg := TRegistry.Create;
try
Reg.RootKey := HKEY_LOCAL_MACHINE;
if Reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\Run', False) then begin
Reg.WriteString('MyStartup', Application.ExeName); // 寫入啟動項
end else
MessageBox(Handle, '開啟登錄表失敗。', '錯誤', MB_OK + MB_ICONERROR);
finally
Reg.CloseKey;
Reg.Free;
end;
end;
procedure TForm1.mNotAutoRunClick(Sender: TObject);
var Reg: TRegistry;
begin
Reg := TRegistry.Create;
try
Reg.RootKey := HKEY_LOCAL_MACHINE;
if Reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\Run', False) then begin
Reg.DeleteValue('MyStartup'); // 刪除啟動項
end else
MessageBox(Handle, '開啟登錄表失敗。', '錯誤', MB_OK + MB_ICONERROR);
finally
Reg.CloseKey;
Reg.Free;
end;
end;
| 項目 | 舊版 (Win9x/2000/XP) | 現代 (Vista/7/10/11) |
|---|---|---|
| 寫入 HKLM\Run | 直接成功 | 需管理員權限 (UAC 提升) |
| MCI CDAudio | 廣泛支援 | 部分筆電/超薄光碟機無實體馬達,命令無效 |
| 替代方案 | 無 | DeviceIoControl(hDevice, IOCTL_STORAGE_EJECT_MEDIA, ...) |
| 取得裝置代碼 | 磁碟機代號 | CreateFile('\\.\D:', ...) 取得裝置代碼 |
原始碼中 if Res = 0 then Exit 邏輯有誤:mciSendCommand 成功時回傳 0 (MMSYSERR_NOERROR),失敗時回傳非零錯誤碼。正確判斷應為:
// 正確邏輯
Res := mciSendCommand(DeviceID, MCI_SET, MCI_SET_DOOR_OPEN, 0);
if Res <> 0 then begin // 失敗
// 可選:mciGetErrorString(Res, buf, len) 取得錯誤訊息
Exit;
end;
Result := True; // 成功
掌握 MCI 多媒體控制介面,不僅能操作光碟機,同樣適用於音訊播放、視訊控制、波形音訊錄製等多媒體應用開發。