維尼的蜂巢

RealTime??!! It’s amazing!!!!

函數指標(似乎算是CallBack Function)的一些小問題 八月 28, 2006

Filed under: VC++/C++/C — kevinlin @ 10:57 下午

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

我現在的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 Responses to “函數指標(似乎算是CallBack Function)的一些小問題”

  1. lewis Shih Says:

    不好意思想跟你請教一下!!!
    最近我再寫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已經執行結束….
    不知道你有沒有辦法可以解決呢?? 如果可以的話可以回覆到我的信箱嗎??

  2. kevin Says:

    可以 我先在這邊回一下
    用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;
    }

  3. lewis Shih Says:

    不好意思..先謝謝你的熱心回答!! 可是我會使用那個程式裡內建的參數耶~~~
    像是這樣 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他又沒辦法達到我的需求….
    不好意思阿!!我的問題很多@@

  4. kevin Says:

    其實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);

  5. lewis Shih Says:

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

  6. kevin Says:

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


發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 變更 )

Twitter picture

You are commenting using your Twitter account. Log Out / 變更 )

Facebook照片

You are commenting using your Facebook account. Log Out / 變更 )

Google+ photo

You are commenting using your Google+ account. Log Out / 變更 )

連結到 %s