全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:4341
推到 Plurk!
推到 Facebook!

在BCB中使用VC的DLL問題

尚未結案
tomas850
一般會員


發表:12
回覆:16
積分:5
註冊:2004-01-05

發送簡訊給我
#1 引用回覆 回覆 發表時間:2004-03-09 19:40:17 IP:61.222.xxx.xxx 未訂閱
第一次用LoadLibrary實作,有點問題想要請教一下。 是不是只要用LoadLibrary()就可以不用管這個DLL是 在VC下或是BCB下實作出來的?? 例如原本在VC下使用的"TESTDLL.DLL" 我在BCB下這樣寫 HINSTANCE dllHandle; typedef void(CALLBACK* TDLLFUNCTION)(void); TDLLFUNCTION TDLLSet; dllHandle = NULL; TDLLSet = NULL; dllHandle = LoadLibrary("testdll.dll"); TDLLSet = (TDLLFUNCTION)GetProcAddress(dllHandle,"SetDut"); 是不是這樣就可以捉出TESTDLL.DLL中的SetDut()來用? 因為翻之前的文章好像說使用loadlibrary()就不用特地去轉換VC 那邊過來的DLL檔,不知是不是這樣。 我用上面的方式組譯起來是沒有語法的問題, 但在最後Link的時候會出現 Unresolved external 'SetDut(int)' reference from E:\......... 第一次用loadlibrary(),說了一堆也不知道有沒有人看的懂。
taishyang
站務副站長


發表:377
回覆:5490
積分:4563
註冊:2002-10-08

發送簡訊給我
#2 引用回覆 回覆 發表時間:2004-03-09 19:47:16 IP:140.135.xxx.xxx 未訂閱
tomas850您好: 請先參考下面連結的文章 http://delphi.ktop.com.tw/topic.php?TOPIC_ID=33420 【發表】如何由 BCB 使用 VC 所產生的 LIB 及 DLL By RaynorPao版主 順心 <>~我也是在學習的階段,回答的不好請您多多見諒與指教~
luckfox
一般會員


發表:34
回覆:40
積分:24
註冊:2002-10-15

發送簡訊給我
#3 引用回覆 回覆 發表時間:2004-03-09 20:50:37 IP:218.32.xxx.xxx 未訂閱
包子大大寫的粉好,沒有啥需要補充的,但是我用的方法可能更簡單 在做好VC的DLL檔後,直接用VC的dumplib觀看他的實際函式名字 D:\BCB_share\Porject\UI_SoftGate2\SoftGate_API>dumpbin /exports softapapi.dll Section contains the following exports for SoftApApi.dll 0 characteristics 404C5B2C time date stamp Mon Mar 08 19:38:20 2004 0.00 version 1 ordinal base 2 number of functions 2 number of names ordinal hint RVA name 1 0 00001210 ?GetFirmwareVersion@@YGFPAD@Z 2 1 00001200 ?TestDll@@YGXXZ typedef int (*GETVER)(char *); void __fastcall TForm1::Button1Click(TObject *Sender) { HINSTANCE dll; GETVER GetVer; int RTV; char VerString[1024]; AnsiString DllPathName; DllPathName=AppPath SoftGate_API_Path "SoftApApi.dll"; dll=LoadLibrary(DllPathName.c_str()); if(dll!=NULL) { GetVer=(GETVER)GetProcAddress(dll, "?GetFirmwareVersion@@YGFPAD@Z");//直接引用 if(GetVer!=NULL) { RTV=GetVer(VerString); Edit29->Text(AnsiString(VerString)); } else { Edit29->Text("GetVer Fail"); } FreeLibrary(dll); } else { Edit29->Text("Load Dll Fail"); } }
tomas850
一般會員


發表:12
回覆:16
積分:5
註冊:2004-01-05

發送簡訊給我
#4 引用回覆 回覆 發表時間:2004-03-09 21:15:51 IP:61.222.xxx.xxx 未訂閱
剛看了RaynoPao發表的那篇文章, 我做的應該就是他所提到的第四大部份吧! 我也有把他的source code下載來看, 感覺我的用法應該沒有錯誤耶~~~~~~ 只是不知為啥在最後的link階段,我從dll中引用的function都會是 [Linker Error] Unresolved external'TForm1::(DLL引用的函數名稱)..... 唯一我覺的有點奇怪的是,在RaynoPro的範例中, 他在從DLL中引用了AddMethodEx(),並不用在.H的檔案中再次定義該函數原型。 而我沒有再次定義的話,會出現 Call to undefined fuction的錯誤。
markov
中階會員


發表:55
回覆:135
積分:53
註冊:2003-12-01

發送簡訊給我
#5 引用回覆 回覆 發表時間:2004-03-09 22:25:26 IP:61.229.xxx.xxx 未訂閱
應該先將visual c 的dll利用implib轉成bcb可以看的懂的形式
tomas850
一般會員


發表:12
回覆:16
積分:5
註冊:2004-01-05

發送簡訊給我
#6 引用回覆 回覆 發表時間:2004-03-10 08:58:47 IP:61.222.xxx.xxx 未訂閱
引言: 應該先將visual c 的dll利用implib轉成bcb可以看的懂的形式
我看書上的寫法是說,要載入DLL的方式有二種。 一種是靜態的連結: 若是Visual C 的DLL,要利用implib和coff2omf來轉換格式。 另一種是動態連結: 這種方式並不須要做轉換的動作。而我用的是動態的連結方式。 不知道這種說法對不對......... 另外我覺得問題可能是出在這種地方吧 > 今天朝這個方面去找找看。
ENIX007
高階會員


發表:28
回覆:274
積分:185
註冊:2003-11-27

發送簡訊給我
#7 引用回覆 回覆 發表時間:2004-03-10 09:29:56 IP:210.243.xxx.xxx 未訂閱
tomas850您好  
引言: HINSTANCE dllHandle; typedef void(CALLBACK* TDLLFUNCTION)(void); TDLLFUNCTION TDLLSet; dllHandle = NULL; TDLLSet = NULL; dllHandle = LoadLibrary("testdll.dll"); TDLLSet = (TDLLFUNCTION)GetProcAddress(dllHandle,"SetDut");
請看紅色部分,typedef定義函式指標型態,為的是讓您的TDLLSet能接收DLL內部 函式的位址,因此DLL內部函式是什麼型態,TDLLSet就必須是什麼型態... 因此除非您6種DLL內函式型態都一樣,否則一定會發生錯誤的... 另外照小弟所學,BCB呼叫VC的DLL應該不需額外步驟,只要DLL內匯出前加上 extern "C"關鍵字,不使用編譯器的name mangling即可 程式迷人之處,在於邏輯思考,然而卻也是惱人之處~~
------
程式迷人之處,在於邏輯思考,然而卻也是惱人之處~~
tomas850
一般會員


發表:12
回覆:16
積分:5
註冊:2004-01-05

發送簡訊給我
#8 引用回覆 回覆 發表時間:2004-03-10 13:29:32 IP:61.222.xxx.xxx 未訂閱
實在找不出問題點,把我的source code放上來給大家看一下有沒有什麼問題。 方法一:使用靜態連結,已將原testdll.dll用implib轉出BCB使用的testdll.lib並add到project裡面。    #include  #pragma hdrstop #include "Unit1.h" //-------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" extern "C" __declspec(dllimport) int SetThisCardAsDut(int nCardIndex); extern "C" __declspec(dllimport) int EnableDutCard(int nCardIndex); extern "C" __declspec(dllimport) int SetDriverTestMode(int nCardIndex); extern "C" __declspec(dllimport) int SetDriverTestMode(int nCardIndex); extern "C" __declspec(dllimport) int ReadEEPRom16(int nCardIndex, int offset, int* vlaue); TForm1 *Form1; //-------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //-------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { m_nCardIndex = 1; SetThisCardAsDut(m_nCardIndex); EnableDutCard(m_nCardIndex); SetDriverTestMode(m_nCardIndex); GetMACAddress(); // GetCountryCode(); } //-------------------------------------------------------------------- void TForm1::GetMACAddress() { int tempInt[6]={0},i; int shortArray[3]={0}; int *temp; AnsiString MacString; int iAdapter = 1; int status; ReadEEPRom16(iAdapter, 0x10, temp); shortArray[0]=*temp; ReadEEPRom16(iAdapter, 0x11, temp); shortArray[1]=*temp; ReadEEPRom16(iAdapter, 0x12, temp); shortArray[2]=*temp; MAC1->Text=shortArray[0]; MAC2->Text=shortArray[1]; MAC3->Text=shortArray[2]; } //-------------------------------------------------------------------- 廠商提供的.h file /* ** $Id: testDll.h 1.12 2003/06/10 02:15:38Z juji Exp $ */ /********************************************************************* * Copyright (c) 2002 Integrated Programmable Communications, Inc. * * All rights reserved. Copying, compilation, modification, distribution * or any other use whatsoever of this material is strictly prohibited * except in accordance with a Software License Agreement with * Integrated Programmable Communications, Inc. *********************************************************************/ /********************************************************************* GENERAL DESCRIPTION ******************** 1. RF test main procedure implementation. 2. The export dll function should be in 'C' language (not C ), for the ease of use in other language (VB, Pascal...) 3. In this version, .def is not used but "__declspec(dllexport)" instead 4. This version of DLL functions can be called either by InProComm RF Test Utility or 3rd party's application, which wraps with a language-independant, upgradable intermediate layer */ /********************************************************************* * F U N C T I O N D E C L A R A T I O N S ********************************************************************** */ /// BB registers int ReadBBReg8(int nCardIndex, int offset, int* ucValue); int WriteBBReg8(int nCardIndex, int offset, int ucValue); /// EEPRom int BurnEEPRomFromFile(int nCardIndex, char* fileName); int ReadEEPRom16(int nCardIndex, int offset, int* value); int WriteEEPRom16(int nCardIndex, int offset, int usValue); int GetEEPRomSize(int nCardIndex, int* value); ///// Testing functions of RFTest //extern "C" __declspec(dllexport) int DisableWlanDll(); int StandBy(int nCardIndex); int ContinuousPktTx(int nCardIndex, char* szBuf, int bufSize, int txRate, int pktCount, int pktInterval, int txPwr); int qryTxStatus(int nCardIndex, long *sentCount); int qryRxStatus(int nCardIndex, int *rxOk_p, int *rxCrcErr_p, int *rxPauReceive_p, int *rxPauFcsErr_p, int *rxCcaCount_p); int setChannel(int nCardIndex, int channelConfig); int SetDriverTestMode(int nCardIndex); int SetDriverNormalMode(int nCardIndex); int qryChannel(int nCardIndex, int *channelConfig_p); int setRxDMA(int nCardIndex, int condition, int nAntenna); int qryCR62MeanVar(int nCardIndex, int *cr62Mean_p, int *cr62Var_p); int OutputPower(int nCardIndex, int nTxRate); int LocalFrequecyMeasure(int nCardIndex); int CarrierSuppressionMeasure(int nCardIndex, int nModulationType, int nTxRate); int SetTxFilter(int nCardIndex, int iFilterType, int iChannel); int SetRxAntenna(int nCardIndex, int iAntennaType); int PowerSave(int nCardIndex, int iEnable); int SetDrvDescName(char* pchDrvDesc); int GetDriverUsedIndex(); //// functions to manipulate Agilent DUT shielding box interface int DisableDutCard(int nCardIndex); int EnableDutCard(int nCardIndex); int DeActiveDut(int nCardIndex); int ActiveDut(int nCardIndex); int SetThisCardAsDut(int nCardIndex); int SetThisCardAsDutWithTi(int nCardIndex); int InitTxCalibration(int nCardIndex, int nGain); double TXIQCalibration(int Step, char *w0s, char* wnks, char *wpks, int nCardIndex); int InitRxCalibration(int nCardIndex); double SetRxCalibrationParam(int Step, int Gain, int nCardIndex); double RFRxCalibration(int Step, int LoopCount, int nCardIndex); int StopRFCalibration(int nCardIndex); int SaveTxPowerToEeprom(int nCardIndex, int nChannel, int bCck, int nTxPwr); int ReadTxPowerFromEeprom(int nCardIndex, int nChannel, int bCck, char* nTxPwr); int SaveRFCalTabToEEPROM(int nCardIndex, int nChannel); 方法二:動態連結 //-------------------------------------------------------------------- #include #pragma hdrstop #include "Unit1.h" //-------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //-------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //-------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { m_nCardIndex = 1; SetThisCardAsDut(m_nCardIndex); EnableDutCard(m_nCardIndex); SetDriverTestMode(m_nCardIndex); GetMACAddress(); } //-------------------------------------------------------------------- void TForm1::DllLoad() { dllHandle = NULL; typedef int(*TDLLFUNCTION1)(int); typedef int(*TDLLFUNCTION3)(int,int,int*); typedef int(*TDLLFUNCTION4)(int,int,int); TDLLFUNCTION1 TDLLSetDut,TDLLEnabledDut,TDLLDisabledDut,TDLLSetTestMode,TDLLSetNormalMode; TDLLFUNCTION3 TDLLReadEPPE16; TDLLFUNCTION4 TDLLWriteEPPE16; TDLLSetDut = NULL, TDLLEnabledDut = NULL, TDLLDisabledDut = NULL, TDLLSetTestMode = NULL, TDLLSetNormalMode = NULL, TDLLReadEPPE16 = NULL, TDLLWriteEPPE16 = NULL; dllHandle = LoadLibrary("testdll.dll"); if( dllHandle != NULL ) { TDLLSetDut = (TDLLFUNCTION1)GetProcAddress(dllHandle,"SetThisCardAsDut"); TDLLEnabledDut = (TDLLFUNCTION1)GetProcAddress(dllHandle,"EnableDutCard"); TDLLDisabledDut = (TDLLFUNCTION1)GetProcAddress(dllHandle,"DisableDutCard"); TDLLSetTestMode = (TDLLFUNCTION1)GetProcAddress(dllHandle,"setDriverTestMode"); TDLLSetNormalMode = (TDLLFUNCTION1)GetProcAddress(dllHandle,"setDriveNormalMode"); TDLLReadEPPE16 = (TDLLFUNCTION3)GetProcAddress(dllHandle,"ReadEEPRom16"); TDLLWriteEPPE16 = (TDLLFUNCTION4)GetProcAddress(dllHandle,"WriteEEPRom16"); if(TDLLSetDut == NULL) ShowMessage(" .dll loading failure please check .dll file is exist"); if(TDLLEnabledDut == NULL) ShowMessage(" .dll loading failure please check .dll file is exist"); if(TDLLDisabledDut == NULL) ShowMessage(" .dll loading failure please check .dll file is exist"); if(TDLLSetTestMode == NULL) ShowMessage(" .dll loading failure please check .dll file is exist"); if(TDLLSetNormalMode == NULL) ShowMessage(" .dll loading failure please check .dll file is exist"); if(TDLLReadEPPE16 == NULL) ShowMessage(" .dll loading failure please check .dll file is exist"); if(TDLLWriteEPPE16 == NULL) ShowMessage(" .dll loading failure please check .dll file is exist"); } } //-------------------------------------------------------------------- void TForm1::GetMACAddress() { int tempInt[6]={0},i; int shortArray[3]={0}; int *temp; AnsiString MacString; int iAdapter = 1; int status; ReadEEPRom16(iAdapter, 0x10, temp); shortArray[0]=*temp; ReadEEPRom16(iAdapter, 0x11, temp); shortArray[1]=*temp; ReadEEPRom16(iAdapter, 0x12, temp); shortArray[2]=*temp; MAC1->Text=shortArray[0]; MAC2->Text=shortArray[1]; MAC3->Text=shortArray[2]; } //-------------------------------------------------------------------- void __fastcall TForm1::FormActivate(TObject *Sender) { DllLoad(); } //-------------------------------------------------------------------- 二種方法試的結果都是一樣的。 [Linker Error] Unresolved external 'TForm1::SetThisCardAsDut(int)' referenced from E:\WIRELESS\WA4270\MAC&COUNTRY_CODE_BCB\UNIT1.OBJ [Linker Error] Unresolved external 'TForm1::EnableDutCard(int)' referenced from E:\WIRELESS\WA4270\MAC&COUNTRY_CODE_BCB\UNIT1.OBJ [Linker Error] Unresolved external 'TForm1::SetDriverTestMode(int)' referenced from E:\WIRELESS\WA4270\MAC&COUNTRY_CODE_BCB\UNIT1.OBJ [Linker Error] Unresolved external 'TForm1::ReadEEPRom16(int, int, int *)' referenced from E:\WIRELESS\WA4270\MAC&COUNTRY_CODE_BCB\UNIT1.OBJ
ENIX007
高階會員


發表:28
回覆:274
積分:185
註冊:2003-11-27

發送簡訊給我
#9 引用回覆 回覆 發表時間:2004-03-10 14:22:22 IP:210.243.xxx.xxx 未訂閱
tomas850您好 請試試看改成這樣,不過不確定是不是問題所在 <>< face="Verdana, Arial, Helvetica">引言: typedef int(__stdcall *TDLLFUNCTION1)(int); typedef int(__stdcall *TDLLFUNCTION3)(int,int,int*); typedef int(__stdcall *TDLLFUNCTION4)(int,int,int); 再參考這2篇連結 http://delphi.ktop.com.tw/topic.php?TOPIC_ID=42637 http://delphi.ktop.com.tw/topic.php?TOPIC_ID=42769 程式迷人之處,在於邏輯思考,然而卻也是惱人之處~~
------
程式迷人之處,在於邏輯思考,然而卻也是惱人之處~~
tomas850
一般會員


發表:12
回覆:16
積分:5
註冊:2004-01-05

發送簡訊給我
#10 引用回覆 回覆 發表時間:2004-03-10 16:05:41 IP:61.222.xxx.xxx 未訂閱
引言: typedef int(__stdcall *TDLLFUNCTION1)(int); typedef int(__stdcall *TDLLFUNCTION3)(int,int,int*); typedef int(__stdcall *TDLLFUNCTION4)(int,int,int);
我試著改成上述的方式也是不能用,(__cdcel我也順便試了一下,也是不行) 後來我去翻廠商提供的範例程式(Visual C )。廠商是這樣寫的 #define DECLARE_FUNCTION0(retVal, FuncName) typedef retVal (*TYPE_##FuncName)(); TYPE_##FuncName m_##FuncName; short m_is##FuncName; retVal FuncName() { if (m_dllHandle) { if (FUNC_LOADED != m_is##FuncName) { m_##FuncName = NULL; m_##FuncName = (TYPE_##FuncName)GetProcAddress(m_dllHandle, #FuncName); m_is##FuncName = FUNC_LOADED; } if (NULL != m_##FuncName) return m_##FuncName(); else return (retVal)NULL; } else return (retVal)NULL; } #define DECLARE_FUNCTION1(retVal, FuncName, Param1) typedef retVal (*TYPE_##FuncName)(Param1); TYPE_##FuncName m_##FuncName; short m_is##FuncName; retVal FuncName(Param1 p1) { if (m_dllHandle) { if (FUNC_LOADED != m_is##FuncName) { m_##FuncName = NULL; m_##FuncName = (TYPE_##FuncName)GetProcAddress(m_dllHandle, #FuncName); m_is##FuncName = FUNC_LOADED; } if (NULL != m_##FuncName) return m_##FuncName(p1); else return (retVal)NULL; } else return (retVal)NULL; } #define DECLARE_FUNCTION2(retVal, FuncName, Param1, Param2) typedef retVal (*TYPE_##FuncName)(Param1, Param2); TYPE_##FuncName m_##FuncName; short m_is##FuncName; retVal FuncName (Param1 p1, Param2 p2) { if (m_dllHandle) { if (FUNC_LOADED != m_is##FuncName) { m_##FuncName = NULL; m_##FuncName = (TYPE_##FuncName)GetProcAddress(m_dllHandle, #FuncName); m_is##FuncName = FUNC_LOADED; } if (NULL != m_##FuncName) return m_##FuncName(p1, p2); else return (retVal)NULL; } else return (retVal)NULL; } 他們只區分所以函數參數的個數來套用到所有的函數中。 但說真的我看不懂他到底是寫些什麼。 發表人 - tomas850 於 2004/03/10 16:13:55
ENIX007
高階會員


發表:28
回覆:274
積分:185
註冊:2003-11-27

發送簡訊給我
#11 引用回覆 回覆 發表時間:2004-03-10 16:54:01 IP:210.243.xxx.xxx 未訂閱
tomas850您好 突然發現,您Post的source code基本上是沒問題的,但若真的要使用這些函式的話, 就會產生問題了,因為所有的宣告(包括typedef)都寫在TForm1::DllLoad函式內, 只要離開這個函式,那些宣告的函式已經脫離它們的scope了,因此別的地方是無法 使用的... 不過您的問題好像不在這裡... 程式迷人之處,在於邏輯思考,然而卻也是惱人之處~~
------
程式迷人之處,在於邏輯思考,然而卻也是惱人之處~~
tomas850
一般會員


發表:12
回覆:16
積分:5
註冊:2004-01-05

發送簡訊給我
#12 引用回覆 回覆 發表時間:2004-03-10 17:40:50 IP:61.222.xxx.xxx 未訂閱
引言: tomas850您好 突然發現,您Post的source code基本上是沒問題的,但若真的要使用這些函式的話, 就會產生問題了,因為所有的宣告(包括typedef)都寫在TForm1::DllLoad函式內, 只要離開這個函式,那些宣告的函式已經脫離它們的scope了,因此別的地方是無法 使用的... 不過您的問題好像不在這裡... 程式迷人之處,在於邏輯思考,然而卻也是惱人之處~~ < face="Verdana, Arial, Helvetica"> 真的非常的感謝ENIX007的幫忙, 我陸續的有在試各種方法來解決這個問題, 剛也有把所有的typedef和宣告都移到.h的檔案去。 現在我是可以執行出執行檔出來了。 但一但呼叫到DLL的函數時,就會出現下面的問題。 Error Project BurnMac.exe raised exception class EAcccess Violation with message 'Access violation at address 1000666A in module 'testdll.dll' Read of address 00000008'.Process stopped.Use Step or Run to continue. 其實上面那個error應該是要post圖片上來,但我不知道怎上傳......
ENIX007
高階會員


發表:28
回覆:274
積分:185
註冊:2003-11-27

發送簡訊給我
#13 引用回覆 回覆 發表時間:2004-03-10 17:56:34 IP:210.243.xxx.xxx 未訂閱
tomas850您好 記憶體存取錯誤...這個就麻煩了... 這個時候只能單步trace囉...只要確定LoadLibrary()出來所接收到的函式 不是NULL,就表示讀取DLL流程OK! 看來您也無法trace到DLL內部吧,我的方法是,找出當在哪個函式,檢查進入 函式前所有引數是否正確,如果都沒問題,再來只能詢問廠商了吧... 程式迷人之處,在於邏輯思考,然而卻也是惱人之處~~
------
程式迷人之處,在於邏輯思考,然而卻也是惱人之處~~
tomas850
一般會員


發表:12
回覆:16
積分:5
註冊:2004-01-05

發送簡訊給我
#14 引用回覆 回覆 發表時間:2004-03-10 19:57:39 IP:61.222.xxx.xxx 未訂閱
引言: tomas850您好 記憶體存取錯誤...這個就麻煩了... 這個時候只能單步trace囉...只要確定LoadLibrary()出來所接收到的函式 不是NULL,就表示讀取DLL流程OK! 看來您也無法trace到DLL內部吧,我的方法是,找出當在哪個函式,檢查進入 函式前所有引數是否正確,如果都沒問題,再來只能詢問廠商了吧... 程式迷人之處,在於邏輯思考,然而卻也是惱人之處~~ < face="Verdana, Arial, Helvetica"> 嗯~~真的是DLL的內容有問題,有某些函式是無法使用的, 亦或是應該說某些函式是在特定環境下才能使用...... 現在已經確定在
系統時間:2024-07-01 20:05:42
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!