維尼的蜂巢

函數指標(似乎算是CallBack Function)的一些小問題

Posted by: kevinlin on: 八月 28, 2006

遇到一個小問題,要紀錄一下以免以後忘記

我現在的Button有弄一個ButtonDown跟ButtonUp的事件
可以設定該button的CallBackFunction
ex.
使用的時候只要照下面這樣設定,前端就不用在去理會鍵盤有沒有按了

Button->pfnOnButtonDown = OpenMenu; //傳給他函式
Button->pClientArg = anythig //用來擴充用的,傳任何型態都可以(這時候就知道void的好用)

所以如果我們在類別裡面做的時候 OpenMenu() 必須要弄成static
假設有一個Test的類,裡面有一個按鈕 跟一個CallBackFunction(OpenMenu)跟一個簡單的Function

Class Test
{
public:
static void OpenMenu( Button*pBtn, void*pClientArg );
void fuctionA();
Button *m_button;
int m_x;
}//為了方便 都假設是public

如果我建立m_button時候
給他一個CallBackFunction
m_Button->pfnOnButtonDown = OpenMenu;
這樣基本上簡單的操作都沒有問題了,不過下面的情況下就有問題了

這時候我發現問題就是如果我OpenMenu是這樣實做的

void OpenMenu( Button*pBtn, void*pClientArg )
{
functionA();
m_x=1;
}

就是說使用到那個Test類別的成員,會有錯誤產生,因為static基本上算是另類的全域,不允許我這樣呼叫
這時候叫要那個擴充用的參數就有用了

只要
m_Button->pfnOnButtonDown = OpenMenu;
m_Button->pClientArg = this;
然後把OpenMenu改成

void OpenMenu( Button*pBtn, void*pClientArg )
{
Test*pTestInstance = (Test*)pClientArg;
pTestInstance->functionA();
pTestInstance->m_x=1;
}//這樣就解決了問題了

6 回應 至 "函數指標(似乎算是CallBack Function)的一些小問題"

不好意思想跟你請教一下!!!
最近我再寫BCB的自動化流程時遇到了一個問題!!我想應該就是callback function~~~
我的想法是執行A->A CALL PROCEDURE執行B->B執行完回到A->A才能繼續做它的事
p.s. A是BCB
B是windows裡面的一個程式例如:modelsim
目前我是只有做到 “執行A->A CALL PROCEDURE執行B->B執行完” 這樣而已
我用的方法是ShellExecute(
HWND hwnd, // 父視窗 Handle
LPCTSTR lpOperation, // 開啟或操作方式
LPCTSTR lpFile, // 檔案名稱
LPCTSTR lpParameters, // 參數內容
LPCTSTR lpDirectory, // 命令所在目錄
int nShowCmd // 執行時視窗型態
);

現在是卡在有沒有辦法在B執行完後讓A得知B已經執行結束….
不知道你有沒有辦法可以解決呢?? 如果可以的話可以回覆到我的信箱嗎??

可以 我先在這邊回一下
用GetExitCodeProcess Createprocess
如果程序A要等程序B 就用個While 然後裡面GetExitCodeProcess 去等B的process結束
下面這段code就是建立一個Process然後等待他結束
我貼一段sample code (google到的:P)你就瞭解了
http://goff.nu/techarticles/development/cpp/createprocess.html

int ExecuteProcess(std::string &FullPathToExe, std::string &Parameters,
int SecondsToWait)
{
int iMyCounter = 0, iReturnVal = 0;
DWORD dwExitCode;
/* - NOTE - You could check here to see if the exe even exists */
/* Add a space to the beginning of the Parameters */
if (Parameters.size() != 0 )
{
Parameters.insert(0," ");
}
/*
When using CreateProcess the first parameter needs to be
the exe itself
*/
Parameters = getExeName(FullPathToExe).append(Parameters);
/*
The second parameter to CreateProcess can not be anything
but a char!! Since we are wrapping this C function with
strings, we will create the needed memory to hold the parameters
*/
/* Dynamic Char */
char * pszParam = new char[Parameters.size() + 1];
/* Verify memory availability */
if (pszParam == 0)
{
/* Unable to obtain (allocate) memory */
return 1;
}
const char* pchrTemp = Parameters.c_str();
strcpy(pszParam, pchrTemp);
/* CreateProcess API initialization */
STARTUPINFO siStartupInfo;
PROCESS_INFORMATION piProcessInfo;
memset(&siStartupInfo, 0, sizeof(siStartupInfo));
memset(&piProcessInfo, 0, sizeof(piProcessInfo));
siStartupInfo.cb = sizeof(siStartupInfo);
/* Execute */
if (CreateProcess(FullPathToExe.c_str(), pszParam, 0, 0, false,
CREATE_DEFAULT_ERROR_MODE, 0, 0, &siStartupInfo,
&piProcessInfo) != false)
{
/*
A loop to watch the process. Dismissed with SecondsToWait
set to 0
*/
GetExitCodeProcess(piProcessInfo.hProcess, &dwExitCode);
while (dwExitCode == STILL_ACTIVE && SecondsToWait != 0)
{
GetExitCodeProcess(piProcessInfo.hProcess, &dwExitCode);
Sleep(500);
iMyCounter += 500;
if (iMyCounter > (SecondsToWait * 1000))
{
dwExitCode = 0;
}
}
}
else
{
/*
CreateProcess failed. You could also set the
return to GetLastError()
*/
iReturnVal = 2;
}
/* Release handles */
CloseHandle(piProcessInfo.hProcess);
CloseHandle(piProcessInfo.hThread);
/* Free memory */
delete[]pszParam;
pszParam = 0;
return iReturnVal;
}
/*------------------| getExeName |--------------------------------*
| Description:
| ~~~~~~~~~
| Returns the string after the last "\"
\*--------------------------------------------------------------------*/
std::string getExeName(std::string strFullPathToExe)
{
int Position = strFullPathToExe.find_last_of("\\");
strFullPathToExe = strFullPathToExe.erase(0, Position +1);
return strFullPathToExe;
}

不好意思..先謝謝你的熱心回答!! 可是我會使用那個程式裡內建的參數耶~~~
像是這樣 ShellExecute(NULL,”open”,”C:\\Modeltech_6.1b\\win32\\modelsim.exe”, “-do resimscript0.do” ,”C:\\Modeltech_6.1b\\examples\\wb_synthesis_2″, SW_SHOWNA);

其中第四個參數是我下給modelsim的指令,問題是你給我的程式碼裡是用creat process他不能下參數@@ 然後我用shellexecute他又沒辦法達到我的需求….
不好意思阿!!我的問題很多@@

其實CreateProcess的STARTUPINFO可以設定那些參數不過好像還蠻複雜的
那可以用ShellExecuteEx + WaitForSingleObject
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/functions/shellexecuteex.asp
你只要取得 process的handle就能給GetExitCodeProcess去檢查是不是結束了
BOOL ShellExecuteEx(
LPSHELLEXECUTEINFO lpExecInfo);
只有一個參數
typedef struct _SHELLEXECUTEINFO {
DWORD cbSize;
ULONG fMask;
HWND hwnd;
LPCTSTR lpVerb;
LPCTSTR lpFile;
LPCTSTR lpParameters;
LPCTSTR lpDirectory;
int nShow;
HINSTANCE hInstApp;
LPVOID lpIDList;
LPCTSTR lpClass;
HKEY hkeyClass;
DWORD dwHotKey;
union {
HANDLE hIcon;
HANDLE hMonitor;
} DUMMYUNIONNAME;
HANDLE hProcess;
} SHELLEXECUTEINFO, *LPSHELLEXECUTEINFO;
類似這樣來實做
SHELLEXECUTEINFO sfi;
TCHAR szFileName[128];
wcscpy(szFileName, TEXT(“\\xxx.exe”));
memset(&sfi, 0, sizeof(sfi));
sfi.cbSize = sizeof(sfi);
sfi.fMask = SEE_MASK_NOCLOSEPROCESS;
sfi.hwnd = hDlg;
sfi.lpVerb = L”open”;
sfi.lpFile = szFileName;
sfi.lpParameters = NULL;
sfi.lpDirectory = NULL;
sfi.nShow = SW_SHOWNA;
ShellExecuteEx(&sfi);
WaitForSingleObject(sfi.hProcess, INFINITE);

非常謝謝你詳細的指教!!!
我試過了…還是不行QQ 我覺得是bcb抓不到我外部程式的handle吧@@
所以最後還是用了最爛的方法…..
用sleep….. 雖然很爛… 但是有達到我的需求@@
總而言之~~~還是謝謝你提供的方法啦!!!

是喔!!
我也沒用過BCB,我還以為BCB只是披著郎皮的羊,多一層VCL包裝而已,跟VC在寫應該沒什麼差,想不到還是不行。

留言