Delphi之東進模擬語音卡(D160A)可複用源碼

Delphi之東進模擬語音卡(D160A)可複用源碼

網友急需,先開源吧,文檔過幾天慢慢補。

作者:成曉旭

設計簡介:

1、 將卡、通道分別單獨進行設計與封裝。

2、 所有的外部操作接口都封裝在卡類這一類。

3、 在我的項目中,在卡類這一級還增加了適配器或者代理,分別實現了Adapter或Proxy模式;以盡可能地解耦卡設備的實現細節與具體應用業務之間的關系。因爲,我們的系統中使用了幾家不同的卡設備,另一方面,這些卡設備,在不同的軟件系統中,又有不同的業務應用需求。

4、 當然,卡這一級,也可以實現一個統一的接口,這樣對外部可以表現出相對統一的行爲,以方便業務層代碼的調用,比如說:在數據采集的應用中,統一的接口可以讓采集控制層不必依賴于具體的采集設備和通信方式,可以一致地實現數據收發,不管通信方式是RS232、RS485、TCP/IP、PSTN,還是別的方式或者通信設備。

5、 在通道設計中,核心的就是一個“狀態機模式”,通過輪巡通道狀態來管理硬件卡設備,並且,還自己設計了一個業務級的“業務狀態機”,來抽象業務方面需要關心的“業務狀態”,通過增加“業務狀態機”這樣一個中間層,以解耦業務狀態與設備狀態之間的依賴。(這一點,在我看到的所有卡廠商提供的各類Demo程序裏面都沒有這樣做,這也無形中誤導了很多的開發人員,我看到的所有應用軟件開發的源碼都是:設備細節、尤其是通道狀態,與業務邏輯代碼緊緊地耦合在一起,難解難分)。

6、 此設計的另一個亮點是:IoC模式的應用(2004年自己在設計此類時還不知道這個概念,全憑自己的經驗總結出這樣的設計)。對通道進入“呼入成功”、“呼出成功”等業務狀態的調用代碼從通道類是解耦出來:設計一個接口,在各個業務狀態的處理方法中,再調用接口方法,將具體的業務處理邏輯委托給實現此接口的對象。並且這個接口的實現是通過“依賴注入”實現IoC的。這樣設計,就達到了很好的可複用性和靈活性。

7、 當然,更好的實現可以采用AOP(面向方法編程)的思想或者實現技術,這樣可複用性更好,如此設計,在業務與卡方法的調用之間,耦合度將是最低的。

8、 目前的版本,沒有在代碼中體現接口的實現……

9、 類圖(以後補上):

10、卡類源碼:

王朝网络
//------------------------------------------------------------------------------

王朝网络
//

王朝网络
// 産品名稱: 成曉旭的個人軟件Delphi源碼庫

王朝网络
// 産品版本: CXXSoft delphi code source lib 2.0

王朝网络
// 模塊名稱: Delphi之東進模擬語音卡類

王朝网络
// 模塊描述:

王朝网络
// 單元文件: unDJCard160A.pas

王朝网络
// 開發作者: 成曉旭

王朝网络
// 備注: 任何人使用此文件時,請保留此段自述文件,謝謝!

王朝网络
// 開發時間: 2004-08-03

王朝网络
// 修改曆史:

王朝网络
// 修改描述:

王朝网络
//------------------------------------------------------------------------------

王朝网络
unit unDJCard160A;

王朝网络

王朝网络
interface

王朝网络
uses

王朝网络
Windows,

王朝网络
unDJTC08a32,unDJNewSig,

王朝网络
unBaseDefine,unDJ160ADefine,

王朝网络
unDJChanne160A;

王朝网络
type

王朝网络
TCXXCommCard160A = class(TObject)

王朝网络
private

王朝网络

王朝网络
ChannelNumber:Word;

王朝网络
channelObject:array of TCXXDJChannel160A;

王朝网络
OnCardChannelState:TTrunkStatusEvent;

王朝网络

王朝网络
procedure Stop();

王朝网络
procedure ReleaseCommDevice();

王朝网络
function GetChannelObjectOrder(const aChannelID:Word):Word;

王朝网络

王朝网络
public

王朝网络

王朝网络
constructor Create(const trunkEvent:TTrunkStatusEvent);

王朝网络
destructor Destroy(); override;

王朝网络

王朝网络
function LoadCommDevice(const loadAll:boolean=false):boolean;

王朝网络
function Startup():boolean;

王朝网络
function GetAFreeChannel():Word;

王朝网络
function GetChannelNumber():Word;

王朝网络
function DialPhone(const aChannelID:Word;const DialPhoneNumber:PChar):boolean;

王朝网络
function HangUp(const aChannelID:Word):boolean;

王朝网络

王朝网络
end;

王朝网络

王朝网络

王朝网络
implementation

王朝网络

王朝网络
王朝网络
...{ TCXXCommCard160A }

王朝网络
constructor TCXXCommCard160A.Create(const trunkEvent:TTrunkStatusEvent);

王朝网络
begin

王朝网络
ChannelNumber := 0;

王朝网络
Self.OnCardChannelState := trunkEvent;

王朝网络
end;

王朝网络

王朝网络
destructor TCXXCommCard160A.Destroy;

王朝网络
var

王朝网络
Loop:Word;

王朝网络
begin

王朝网络
Stop();

王朝网络
if (Length(channelObject) > 0) and (channelNumber > 0) then

王朝网络
begin

王朝网络
for Loop := 0 to ChannelNumber - 1 do

王朝网络
begin

王朝网络
if Assigned(channelObject[Loop]) then

王朝网络
begin

王朝网络
channelObject[Loop].Free();

王朝网络
channelObject[Loop] := nil;

王朝网络
end;

王朝网络
end;

王朝网络
end;

王朝网络
ReleaseCommDevice();

王朝网络
end;

王朝网络

王朝网络
function TCXXCommCard160A.DialPhone(const aChannelID: Word;

王朝网络
const DialPhoneNumber: PChar): boolean;

王朝网络
var

王朝网络
K:Word;

王朝网络
begin

王朝网络
Result := false;

王朝网络
K := GetChannelObjectOrder(aChannelID);

王朝网络
if (K <> ErrorTrunkNumber) and (Assigned(channelObject[K])) then

王朝网络
begin

王朝网络
Result := channelObject[K].DialPhone(DialPhoneNumber);

王朝网络
end;

王朝网络
end;

王朝网络

王朝网络
procedure TCXXCommCard160A.ReleaseCommDevice();

王朝网络
begin

王朝网络
DisableCard();

王朝网络
FreeDrv();

王朝网络
end;

王朝网络

王朝网络
function TCXXCommCard160A.GetAFreeChannel(): Word;

王朝网络
var

王朝网络
Loop:Word;

王朝网络
begin

王朝网络
Result := ErrorTrunkNumber;

王朝网络
for Loop := Low(channelObject) to High(channelObject) do

王朝网络
begin

王朝网络
if (channelObject[Loop].GetChannelType() = ctEmpty) then continue;

王朝网络
if (channelObject[Loop].GetChannelStatus() = atsFree) then

王朝网络
begin

王朝网络
Result := channelObject[Loop].GetChannelID();

王朝网络

break;

王朝网络
end;

王朝网络
end;

王朝网络
end;

王朝网络

王朝网络
function TCXXCommCard160A.GetChannelNumber(): Word;

王朝网络
begin

王朝网络
Result := channelNumber;

王朝网络
end;

王朝网络

王朝网络
function TCXXCommCard160A.GetChannelObjectOrder(

王朝网络
const aChannelID: Word): Word;

王朝网络
var

王朝网络
Loop:Word;

王朝网络
begin

王朝网络
Result := ErrorTrunkNumber;

王朝网络
for Loop := Low(channelObject) to High(channelObject) do

王朝网络
begin

王朝网络
if (channelObject[Loop].GetChannelID = aChannelID) then

王朝网络
begin

王朝网络
Result := Loop;

王朝网络

break;

王朝网络
end;

王朝网络
end;

王朝网络
end;

王朝网络

王朝网络
function TCXXCommCard160A.HangUp(const aChannelID: Word): boolean;

王朝网络
var

王朝网络
K:Word;

王朝网络
begin

王朝网络
Result := false;

王朝网络
K := GetChannelObjectOrder(aChannelID);

王朝网络
if (K <> ErrorTrunkNumber) and (Assigned(channelObject[K])) then

王朝网络
begin

王朝网络
channelObject[K].ChannelHangUp();

王朝网络
Result := true;

王朝网络
end;

王朝网络
end;

王朝网络

王朝网络
function TCXXCommCard160A.LoadCommDevice(const loadAll:boolean): boolean;

王朝网络
const

王朝网络
loadEmpty = true;

王朝网络
var

王朝网络
Loop,tempNumber:Word;

王朝网络
isFlag:LongInt;

王朝网络
function CheckLoadTrunk():boolean;

王朝网络
begin

王朝网络
Result := loadAll or ((NOT loadAll) and(TChannelType(CheckChType(Loop)) <> ctEmpty));

王朝网络
end;

王朝网络
begin

王朝网络
isFlag := LoadDRV();

王朝网络
Result := (isFlag=0);

王朝网络
if NOT Result then Exit;

王朝网络
tempNumber := CheckValidCh();

王朝网络
Result := EnableCard(tempNumber,1024*8)=0;

王朝网络
if NOT Result then

王朝网络
begin

王朝网络
FreeDrv();

王朝网络
Exit;

王朝网络
end;

王朝网络
Result := Sig_Init()=1;

王朝网络
if NOT Result then Exit;

王朝网络
SetBusyPara(700);

王朝网络
SetPackRate(PACK_64KBPS );

王朝网络
channelNumber := tempNumber;

王朝网络
SetLength(channelObject,channelNumber);

王朝网络
for Loop := 0 to channelNumber - 1 do

王朝网络
begin

王朝网络
if CheckLoadTrunk() then

王朝网络
begin

王朝网络
channelObject[Loop] := TCXXDJChannel160A.Create(OnCardChannelState);

王朝网络
channelObject[Loop].CreateCommChannel(Loop);

王朝网络
end;

王朝网络
end;

王朝网络
end;

王朝网络

王朝网络
function TCXXCommCard160A.Startup(): boolean;

王朝网络
var

王朝网络
Loop:integer;

王朝网络
begin

王朝网络
for Loop := 0 to channelNumber - 1 do

王朝网络
begin

王朝网络
channelObject[Loop].Resume();

王朝网络
end;

王朝网络
Result := true;

王朝网络
end;

王朝网络

王朝网络
procedure TCXXCommCard160A.Stop();

王朝网络
var

王朝网络
Loop:integer;

王朝网络
begin

王朝网络
for Loop := 0 to channelNumber - 1 do

王朝网络
begin

王朝网络
channelObject[Loop].Suspend();

王朝网络
channelObject[Loop].Terminate();

王朝网络
channelObject[Loop] := nil;

王朝网络
end;

王朝网络
end;

王朝网络

王朝网络
end.

王朝网络

11、 通道類源碼:

王朝网络
//------------------------------------------------------------------------------

王朝网络
//

王朝网络
// 産品名稱: 成曉旭的個人軟件Delphi源碼庫

王朝网络
// 産品版本: CXXSoft delphi code source lib 2.0

王朝网络
// 模塊名稱: Delphi之東進模擬語音卡通道類

王朝网络
// 模塊描述:

王朝网络
// 單元文件: unDJChanne160A.pas

王朝网络
// 開發作者: 成曉旭

王朝网络
// 備注: 任何人使用此文件時,請保留此段自述文件,謝謝!

王朝网络
// 開發時間: 2004-08-03

王朝网络
// 修改曆史:

王朝网络
// 修改描述:

王朝网络
//------------------------------------------------------------------------------

王朝网络
unit unDJChanne160A;

王朝网络

王朝网络
interface

王朝网络

王朝网络
uses

王朝网络
Windows,Classes,SysUtils,

王朝网络
unBaseDefine,unDJ160ADefine,

王朝网络
unDJTC08a32,unDJNewSig;

王朝网络
Type

王朝网络
TCXXDJChannel160A = class(TThread)

王朝网络
//TCXXDJChannel160A = class(TObject)

王朝网络
private

王朝网络
channelType:TChannelType;

王朝网络
oldChannelState,channelState:TTrunkState;

王朝网络
channelID:Word;

王朝网络
phoneNumber:string;

王朝网络
dtmfString:string;

王朝网络

王朝网络
isConntectd:boolean;

王朝网络

王朝网络
isDialOut:boolean;

王朝网络
aTrunkState:TTrunkStatus;

王朝网络

王朝网络
procedure InformTrunkStatus(const aMsgFlag: TLVOperateFlag);

王朝网络

王朝网络
procedure ClearTrunkStatus();

王朝网络
function CheckSigHangup():boolean;

王朝网络
function CheckCallIn():boolean;

王朝网络
function SwitchOnCallIn():boolean;

王朝网络

王朝网络
procedure ProcessCallInSuccess();

王朝网络
procedure ProcessDialSuccess();

王朝网络

王朝网络
procedure ProcessCheckDialSend();

王朝网络
protected

王朝网络
procedure Execute(); override;

王朝网络
public

王朝网络
strMessage:string;

王朝网络
OnChannelState:TTrunkStatusEvent;

王朝网络

王朝网络
constructor Create(const trunkEvent:TTrunkStatusEvent);

王朝网络
destructor Destroy();override;

王朝网络

王朝网络
procedure CreateCommChannel(const aChennelID: Word);

王朝网络
procedure ChannelProcessor();

王朝网络

王朝网络
function GetChannelID():Word;

王朝网络
function GetChannelStatus():TTrunkState;

王朝网络
function GetChannelType():TChannelType;

王朝网络
function DialPhone(const DialPhoneNumber:PChar):boolean;overload;

王朝网络
function DialPhone(const DialPhoneNumber:PChar;const PreDialNumber:PChar):boolean;overload;

王朝网络
procedure ChannelHangUp();

王朝网络

王朝网络
function GetDialOut():boolean;

王朝网络
end;

王朝网络
implementation

王朝网络

王朝网络
王朝网络
...{ TCXXDJChannel160A }

王朝网络

王朝网络
procedure TCXXDJChannel160A.ChannelHangUp();

王朝网络
begin

王朝网络
isDialOut := false;

王朝网络
StopSigCheck(channelID);

王朝网络
HangUp(channelID);

王朝网络
Sig_ResetCheck(channelID);

王朝网络
StartSigCheck(channelID);

王朝网络
InitDTMFBuf(channelID);

王朝网络
ClearTrunkStatus();

王朝网络
InformTrunkStatus(lvofUpdate);

王朝网络
end;

王朝网络

王朝网络
procedure TCXXDJChannel160A.ChannelProcessor();

王朝网络
var

王朝网络
dState:Word;

王朝网络
begin

王朝网络
PUSH_PLAY();

王朝网络
FeedSigFunc();

王朝网络
CheckCallIn();

王朝网络
case channelState of

王朝网络
atsFree:

王朝网络
begin

王朝网络
//

王朝网络
end;

王朝网络
atsCallIning:

王朝网络
begin

王朝网络
SwitchOnCallIn();

王朝网络
end;

王朝网络
atsCallInSuccess:

王朝网络
begin

王朝网络
if CheckSigHangup() then Exit;

王朝网络
ProcessCallInSuccess();

王朝网络
end;

王朝网络
atsCheckSendDial:

王朝网络
begin

王朝网络
ProcessCheckDialSend();

王朝网络
end;

王朝网络
atsDialing:

王朝网络
begin

王朝网络
dState := Sig_CheckDial(channelID);

王朝网络
case dState of

王朝网络
// S_NORESULT:

王朝网络
S_CONNECT:

王朝网络
begin

王朝网络
channelState := atsDialSuccess;

王朝网络
isConntectd := true;

王朝网络
end;

王朝网络
S_BUSY,

王朝网络
S_NOBODY,

王朝网络
S_NODIALSIG,

王朝网络
S_NOSIGNAL:

王朝网络
begin

王朝网络
channelState := atsHangOff;

王朝网络
end;

王朝网络
end;

王朝网络
strMessage := '撥號中...';

王朝网络
end;

王朝网络
atsDialSuccess:

王朝网络
begin

王朝网络
if CheckSigHangup() then Exit;

王朝网络
ProcessDialSuccess();

王朝网络
strMessage := '撥號成功';

王朝网络
end;

王朝网络
atsHangOff:

王朝网络
begin

王朝网络
ChannelHangUp();

王朝网络
end;

王朝网络
end;

王朝网络
if (oldChannelState <> channelState) then

王朝网络
begin

王朝网络
oldChannelState := channelState;

王朝网络
InformTrunkStatus(lvofUpdate);

王朝网络
end;

王朝网络
end;

王朝网络

王朝网络
function TCXXDJChannel160A.CheckCallIn(): boolean;

王朝网络
begin

王朝网络
Result := RingDetect(channelID);

王朝网络
if Result then

王朝网络
begin

王朝网络
OffHook(channelID);

王朝网络
if isDialOut then

王朝网络
channelState := atsDialSuccess

王朝网络
else

王朝网络
channelState := atsCallIning;

王朝网络
end;

王朝网络
end;

王朝网络

王朝网络
function TCXXDJChannel160A.CheckSigHangup(): boolean;

王朝网络
begin

王朝网络
Result := false;

王朝网络
if (Sig_CheckBusy(channelID)=1) then

王朝网络
begin

王朝网络
strMessage := '對方已挂機';

王朝网络
InformTrunkStatus(lvofUpdate);

王朝网络
StopPlayFile(channelID);

王朝网络
channelState := atsHangOff;

王朝网络
Result := true;

王朝网络
end;

王朝网络
end;

王朝网络

王朝网络
procedure TCXXDJChannel160A.ClearTrunkStatus();

王朝网络
begin

王朝网络
channelState := atsFree;

王朝网络
oldChannelState := channelState;

王朝网络
phoneNumber := '';

王朝网络
dtmfString := '';

王朝网络
strMessage := '';

王朝网络
isConntectd := false;

王朝网络
end;

王朝网络

王朝网络
constructor TCXXDJChannel160A.Create(const trunkEvent:TTrunkStatusEvent);

王朝网络
begin

王朝网络
Self.OnChannelState := trunkEvent;

王朝网络
Self.FreeOnTerminate := true;

王朝网络
inherited Create(true);

王朝网络
end;

王朝网络

王朝网络

王朝网络
destructor TCXXDJChannel160A.Destroy;

王朝网络
begin

王朝网络
Suspend();

王朝网络
ChannelHangUp();

王朝网络
//inherited Destroy();

王朝网络
end;

王朝网络

王朝网络
function TCXXDJChannel160A.DialPhone(const DialPhoneNumber:PChar;

王朝网络
const PreDialNumber:PChar): boolean;

王朝网络
begin

王朝网络
isDialOut := true;

王朝网络
phoneNumber := DialPhoneNumber;

王朝网络
OffHook(channelID);

王朝网络
InitDTMFBuf(channelID);

王朝网络
Result := Sig_StartDial(channelID,DialPhoneNumber,PreDialNumber,0)=1;

王朝网络
channelState := atsCheckSendDial;

王朝网络
end;

王朝网络

王朝网络
function TCXXDJChannel160A.DialPhone(

王朝网络
const DialPhoneNumber: PChar): boolean;

王朝网络
begin

王朝网络
Result := DialPhone(DialPhoneNumber,'');

王朝网络
end;

王朝网络

王朝网络
procedure TCXXDJChannel160A.Execute;

王朝网络
begin

王朝网络
while NOT Terminated do

王朝网络
begin

王朝网络
Synchronize(ChannelProcessor);

王朝网络
Sleep(10);

王朝网络
end;

王朝网络
end;

王朝网络

王朝网络
function TCXXDJChannel160A.GetChannelID(): Word;

王朝网络
begin

王朝网络
Result := channelID;

王朝网络
end;

王朝网络

王朝网络
function TCXXDJChannel160A.GetChannelStatus(): TTrunkState;

王朝网络
begin

王朝网络
Result := channelState;

王朝网络
end;

王朝网络

王朝网络
procedure TCXXDJChannel160A.InformTrunkStatus(const aMsgFlag: TLVOperateFlag);

王朝网络
begin

王朝网络
aTrunkState.lvFlag := aMsgFlag;

王朝网络
aTrunkState.TrunkID := IntToStr(channelID);

王朝网络
aTrunkState.TrunkType := channelType;

王朝网络
aTrunkState.TrunkTypeStr := ChannelTypeString[channelType];

王朝网络
aTrunkState.TrunkStep := channelState;

王朝网络
aTrunkState.TrunkStepStr := TrunkStateString[channelState];

王朝网络
aTrunkState.TrunkPhone := phoneNumber;

王朝网络
aTrunkState.TrunkData := dtmfString;

王朝网络
OnChannelState(aTrunkState);

王朝网络
end;

王朝网络

王朝网络
procedure TCXXDJChannel160A.ProcessCallInSuccess();

王朝网络
begin

王朝网络

王朝网络
end;

王朝网络

王朝网络
function TCXXDJChannel160A.SwitchOnCallIn(): boolean;

王朝网络
begin

王朝网络
OffHook(channelID);

王朝网络
InitDTMFBuf(channelID);

王朝网络
StartSigCheck(channelID);

王朝网络
channelState := atsCallInSuccess;

王朝网络
Result := true;

王朝网络
end;

王朝网络

王朝网络
procedure TCXXDJChannel160A.ProcessDialSuccess();

王朝网络
begin

王朝网络

王朝网络
end;

王朝网络

王朝网络
procedure TCXXDJChannel160A.CreateCommChannel(const aChennelID: Word);

王朝网络
begin

王朝网络
channelID := aChennelID;

王朝网络
channelType := TChannelType(CheckChType(channelID));

王朝网络
ClearTrunkStatus();

王朝网络
InformTrunkStatus(lvofAdd);

王朝网络
end;

王朝网络

王朝网络
function TCXXDJChannel160A.GetChannelType(): TChannelType;

王朝网络
begin

王朝网络
Result := channelType;

王朝网络
end;

王朝网络

王朝网络
function TCXXDJChannel160A.GetDialOut(): boolean;

王朝网络
begin

王朝网络
Result := isDialOut;

王朝网络
end;

王朝网络

王朝网络
procedure TCXXDJChannel160A.ProcessCheckDialSend();

王朝网络
begin

王朝网络
if(CheckSendEnd(channelID) = 1) then

王朝网络
begin

王朝网络
StartSigCheck(channelID);

王朝网络
channelState := atsDialing;

王朝网络
end;

王朝网络
end;

王朝网络

王朝网络
end.

王朝网络

 
Delphi之三彙模擬語音卡(SHT-8B/PCI/FAX)可複用源碼
Delphi之三彙模擬語音卡(SHT-8B/PCI/FAX)可複用源碼作者:成曉旭設計簡介:1、 設計思路請參考本站Blog的另一篇文章:“Delphi之東進模擬語音卡(D160A)可複用源碼”;鏈接。2、 其實,仔細對比,你會發...查看完整版>>Delphi之三彙模擬語音卡(SHT-8B/PCI/FAX)可複用源碼
 
Delphi 6 SOAP 源碼中的BUG修正
Delphi 6 SOAP 源碼中的BUG修正最近我正在用delphi 6 做一個關于SOAP的項目,調試程序的時候跟蹤源碼發現了delphi 6的源碼中的一些bug :( 在 delphi/source/soap 目錄下面的XSBuiltIns.pas 文件中,第438行如下:pro...查看完整版>>Delphi 6 SOAP 源碼中的BUG修正
 
模擬delphi編輯窗體操作控件。。。
unit Unit1;interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, jpeg;const LMouseDown=False;type TForm1 = class(TForm) Edit1: TEd...查看完整版>>模擬delphi編輯窗體操作控件。。。
 
WIN32下DELPHI中的多線程【深入VCL源碼】(一)
線程的基礎知識 線程的組成。線程有兩部分組成。 1、一個是線程的內核對象,操作系統用它來對線程實施管理。內核對象也是系統用來存放線程統計信息的地方。 2、另一個是線程堆棧,它用于維護線程在執行...查看完整版>>WIN32下DELPHI中的多線程【深入VCL源碼】(一)
 
最近剛爲公司完成的一款監視的小工具軟件!用DELPHI 7 寫的,可以從後台監控系統﹑鍵盤﹑鼠標﹑屏幕以及文件與目錄!有源碼!
最近剛爲公司完成的一款監視的小工具軟件!用DELPHI 7 寫的,可以從後台監控系統﹑鍵盤﹑鼠標﹑屏幕以及文件與目錄!有源碼!要源碼可以發郵件給我! 大小:45.4K大小:24.1K下載地址:...查看完整版>>最近剛爲公司完成的一款監視的小工具軟件!用DELPHI 7 寫的,可以從後台監控系統﹑鍵盤﹑鼠標﹑屏幕以及文件與目錄!有源碼!