2011-11-29 83 views
2

單獨的線程無法查詢TMediaPlayer對象的Position屬性的原因是什麼?從單獨的線程訪問TMediaPlayer.Position

我已經寫了一個Delphi DLL,它是一個帶有TMediaPlayer組件的窗體。該應用程序調用定期的DLL,這些DLL調用可以查詢該DLL的形式在TMediaPlayer對象的位置和長度值:

procedure TDLLForm.SongPosUpdate(); 
var 
    new_pos: integer; 
    new_len: integer; 
begin 
    new_pos := AudioPlayer.Position; 
    new_len := AudioPlayer.Length; 
end; 

在應用的上下文中調用時,以上功能工作正常加載該DLL。但是,如果該DLL創建一個單獨的線程(子類的TThread)和新的線程調用相同的功能,它變得無效值對象的位置和長度屬性:

// TTimerThread: Constructor 
constructor TTimerThread.Create(F: TDLLForm); 
begin 
    DllForm := F; 
    inherited Create(True); 
    inherited priority := tpHighest; 
end; 


// TTimerThread: Execute 
procedure TTimerThread.Execute; 
begin 
    while not Terminated do 
    begin 
    DLLForm.SongPosUpdate(); 
    Sleep (1000); 
    end; 
end; 

的TMediaPlayer對象的其他屬性(例如AudioPlayer.FileName)可以從線程成功查詢,但不能定位/長度。 TMediaPlayer在開始播放的原始線程的上下文中未被調用時會拒絕透露正確的位置/長度是否有原因?

回答

4

UI控件不直接從主VCL線程之外訪問。沒有任何保證,如果從工作線程查詢,ANY屬性將正常工作。在這種情況下,FileName屬性只讀取作爲TMediaPlayer類成員的String變量,因此通常足夠安全,但屬性必須將MCI命令發送到媒體設備,這就是線程問題可能會出現。

+0

謝謝,你知道一個正確的方法來做到這一點嗎?有一個單獨的線程的原因是保持DLL的活動,即使DLL的調用應用程序線程暫時阻止某些操作。我以前使用一個TTimer來完成這個活動,但我知道這是一個低優先級的事件,它通過正常的VCL線程,因此可以在應用程序忙時進行備份。 – ukembedded

+0

不是讓線程直接查詢'TMediaPlayer'屬性,我可能會讓'TMediaPlayer'的父'TForm'運行一個'TTimer'來查詢'TMediaPlayer'屬性並將值存儲在線程安全變量中該線程可以從中讀取。另一種方法是使用'TThread.Synchronize()',但在DLL內部存在問題。如果主線程得到備份(這意味着您在主線程中做了太多的工作以開始),則無論如何媒體播放可能會得到備份(除非MCI使用自己的後臺線程進行播放)。 –

+0

謝謝。你知道是否有任何規則可以用來確定哪些控件可以安全地從工作線程訪問?例如,我似乎可以從工作線程更新TPaintBox中的位圖。如何確定哪些控件是線程安全的,哪些不是? - ukembedded 14分鐘前 – ukembedded