Delphi:TComPort封裝在DLL中,通訊時無法接收串口資料的解決辦法
來源:互聯網
上載者:User
現象:將Tcomport(版本:ComPort Library ver. 3.0 )封裝在DLL中,進行串口通訊時,無法接收資料! 解決辦法:在建立組件時,只需要更改一個屬性的設定就可以了。如下所示: //DLL入口 talencaport:=ttalencaport.Create(nil); talencaport.port:='COM1';
talencaport.SyncMethod:=smWindowSync; talencaport.OnRxChar:=talencaport.readbuf;紅色加粗的代碼就是關鍵的一句代碼!加入此句代碼後,在DLL中發送與接收資料就與在表單上使用一樣。 分析:由於工作需要,一直使用DELPHI5,DELPHI7兩個版本進行開發。在DELPHI5中,將TCOMPORT封裝在DLL中使用,沒有任何的異常。後來抱成DELPHI7後,當時以為,同樣的代碼,應當沒有什麼問題。於是,編譯。成功!哈!原來版本升級這麼容易!也沒有多想,沒有測試,就把這事情放在了腦後。-_-!! 時間過了一個月,公司有裝置要進行測試,因此,自己很高興地把新的東西用來測試,結果,所有的通訊指令均是失敗(無資料)!頭頓時就要炸了。。。。。。 還好,是自己測試,有問題還算是可以補救的。仔細看源碼,與DELPHI5下的源碼是一樣的,為什麼在DELPHI7下就接收不到資料呢?看來問題還是在TCOMPORT本身上。(:),偶還是粉相信DELPHI實力的!:))一看DLL入口代碼:talencaport:=ttalencaport.Create(nil); talencaport.port:='COM1'; talencaport.OnRxChar:=talencaport.readbuf;似乎也看不出什麼問題來。 心想,是不是在發送完資料後,要延時一點時間呢,於是在發送完資料後,加入一個延時100ms和小過程(這個延時時間跟我們的裝置相關),結果發現還是收不到資料。看來不是這個延時的問題。延時過程代碼: var Com_waittime:cardinal; Com_waittime:=gettickcount; While gettickcount- Com_waittime<100 do application.processmessages; 沒有辦法,只能看TCOMPORT源碼了。一看源碼,TCOMPORT的收資料是由線程完成的。相應線程類是:TcomThread;因此,決定看看線程優先順序。哦,是tpNormal.那調高這個優先順序會不會有所改善?改成tohigher,tphighest…問題依然!看來與線程優先順序無關。再仔細研究這個線程的代碼, TComThread = class(TThread) private FComPort: TCustomComPort; FStopEvent: THandle; FEvents: TComEvents; protected procedure DispatchComMsg; procedure DoEvents; procedure Execute; override; procedure SendEvents; procedure Stop; public constructor Create(AComPort: TCustomComPort); destructor Destroy; override; end; 從Execute入口,得知:線程內部是利用了系統事件對象完成對串口資料接收的觸發。當收到事件後,把系統對應的事件儲存在組合的屬性中。 TComEvent = (evRxChar, evTxEmpty, evRxFlag, evRing, evBreak, evCTS, evDSR, evError, evRLSD, evRx80Full); TComEvents = set of TComEvent; // if event occurs, dispatch it if (Signaled = WAIT_OBJECT_0 + 1) and GetOverlappedResult(FComPort.Handle, Overlapped, BytesTrans, False) then begin// FEvents := IntToEvents(Mask); DispatchComMsg; end; 從藍色的代碼可知:當發生串口事件時,儲存事件類型,然後就分發事件,找對應的事件來執行這個接收過程了。於是再看DispatchComMsg方法:// dispatch eventsprocedure TComThread.DispatchComMsg;begin case FComPort.SyncMethod of smThreadSync: Synchronize(DoEvents); // call events in main thread smWindowSync: SendEvents; // call events in thread that opened the port smNone: DoEvents; // call events inside monitoring thread end;end; 在doEvents這個同步方法中,無法執行相應的事件。從注釋來看,是指在主線程中執行這個操作,由於此時是封裝在DLL中,沒有主線程存在,因此,這個方法的執行也就是石沉大海了。這就是無法接收資料的原因了。 而第二個項就是:調用開啟串口的線程對應事件。看來這個有戲。因此,將組件線程的同步方法類型改成
smWindowSync
。
果然,接收資料正常。 對於第三個選項:在監視線程中執行事件,本人沒有測試,因為時間關係。。。。。哎,有興趣的DELPHIER可以試試。。。。。。。