研究這的目的,是要在Visual C++視窗模式下呼叫gnuplot
也順便解決了呼叫新版gnuplot會出現的問題:
Timeout: gnuplot is not ready
原本只會用C的popen()來呼叫gnuplot,或用Visual C++的_popen()。
這種方法在console(控制台,黑黑的視窗)模式下是可行的。
但在VC++的視窗模式下,是無法使用_popen()的。
因為popen()是Unix系統的pipe function,Windows系統雖有模擬,但使用上有些限制( ex. 視窗程式不能用 )
因為在視窗程式不能用_popen(),只好用在console模式下寫另一只程式Callgnuplot
然後再用視窗程式呼叫Callgnuplot讀檔畫圖
system( "Callgnuplot.exe" )
但這種方式會出現黑色console視窗,有礙觀瞻
就算Callgnuplot裡加上隱藏視窗,還是會閃一下黑色視窗
Using popen():
    →指令傳遞方向
    My Program ( console )
       ↓
       ↓ popen() function
       ↓
    pgnuplot.exe
       ↓
       ↓ pipe function of Windows
       ↓
    wgnuplot.exe ( GUI )
此方法適用於:
舊版gnuplot
compiler: mingw32-gcc
compiler: VC++ console 模式 (popen要改成_popen)
無法用於 VC++ 視窗模式
系統: Windows XP           gnuplot版本: Version 4.4 patchlevel 0-rc1 (gp44rc1win32)
/*******************************************************************/
#include <stdio.h>
int main( void )
{
    FILE *command;
    //command = popen( "gnuplot", "w" ); // XP可用,Vista不行
    command = popen( "pgnuplot", "w" ); // XP Vista 皆可
    fprintf( command, "plot x**2\n" );
    fflush( command ); // 清空pipe緩衝區裡的指令,把指令傳到 pgnuplot,此時圖才會畫出來
    //為了慢慢欣賞畫出的圖,這裡要放暫停的指令
    pclose( command ); // 清除pipe緩衝區裡的指令,此時gnuplot就被關掉了
    return 0;
}
/*******************************************************************/
以上程式修改自:
Appendix B. Call gnuplot from C program
用popen呼叫新版gnuplot( Version 4.4 patchlevel 3 )( gp443win32 )
每次都會出現Timeout: gnuplot is not ready,且畫不出圖
我曾試著在popen之後加上Sleep,還是失敗
後來找到pgnuplot的原始碼,從中找到用Windows的pipe function呼叫gnuplot的方式
於是視窗程式也可以直接呼叫gnuplot!!!
順便也解決了呼叫新版gnuplot會出現的問題:
Timeout: gnuplot is not ready
Timeout: gnuplot is not ready
Using pipe function of Windows:
    →指令傳遞方向
    My Program ( console or 視窗 )
       ↓
       ↓ pipe function of Windows
       ↓
    wgnuplot.exe ( GUI )
/*******************************************************************/
#include <stdio.h>
#include <windows.h>
#define PROGNAME "wgnuplot.exe"
#define TEXTCLASS "wgnuplot_text"
/* GLOBAL Variables */
HWND hwndParent = NULL;
HWND hwndText = NULL;
PROCESS_INFORMATION piProcInfo;
STARTUPINFO         siStartInfo;
/* CRS: Callback for the EnumThreadWindows function */
BOOL CALLBACK
cbGetTextWindow(HWND  hwnd, LPARAM  lParam)
{
    /* save the value of the parent window */
    hwndParent = hwnd;
    /* check to see if it has a child text window */
    hwndText = FindWindowEx(hwnd, NULL, TEXTCLASS, NULL);
    /* if the text window was found, stop looking */
    return (hwndText == NULL);
}
/* sends a string to the specified window */
/* CRS: made this into a function call */
void
PostString(HWND hwnd, char *pc)
{
    while(*pc) {
    PostMessage(hwnd, WM_CHAR, (unsigned char) *pc, 1L);
    /* CRS: should add a check of return code on PostMessage. If 0, the
      message que was full and the message wasn't posted. */
    pc++;
    }
}
int
main ()
{
    char    psGnuplotCommandLine[MAX_PATH] = PROGNAME;
    BOOL    bSuccess;
    /* CRS: initialize the STARTUPINFO and call CreateProcess(). */
    siStartInfo.cb = sizeof(STARTUPINFO);
    siStartInfo.lpReserved = NULL;
    siStartInfo.lpReserved2 = NULL;
    siStartInfo.cbReserved2 = 0;
    siStartInfo.lpDesktop = NULL;
    siStartInfo.dwFlags = STARTF_USESHOWWINDOW;
    siStartInfo.wShowWindow = SW_SHOWMINIMIZED;
    //如果不加下面這兩行, 會Error:998
    ZeroMemory(&piProcInfo,   sizeof(piProcInfo) ); 
    ZeroMemory(&siStartInfo,   sizeof(siStartInfo) );
    bSuccess = CreateProcess(
                NULL,                   /* pointer to name of executable module   */
                psGnuplotCommandLine,   /* pointer to command line string         */
                NULL,                   /* pointer to process security attributes */
                NULL,                   /* pointer to thread security attributes  */
                FALSE,                  /* handle inheritance flag                */
                0,                      /* creation flags                         */
                NULL,                   /* pointer to new environment block       */
                NULL,                   /* pointer to current directory name      */
                &siStartInfo,           /* pointer to STARTUPINFO                 */
                &piProcInfo             /* pointer to PROCESS_INFORMATION         */
                );
    /* if CreateProcess() failed, print a warning and exit. */
    if (! bSuccess) {
        fprintf(stderr,"ERROR %u: Couldn't execute: \"%s\"\n",
        GetLastError(), psGnuplotCommandLine);
        exit(EXIT_FAILURE);
    }
    Sleep(1000); // 這行是我加的,不加的話,新版的gnuplot會失敗
    if (WaitForInputIdle(piProcInfo.hProcess, 1000)) {
    fprintf(stderr, "Timeout: gnuplot is not ready\n");
    exit(EXIT_FAILURE);
    }
    /* CRS: get the HWND of the parent window and text windows */
    EnumThreadWindows(piProcInfo.dwThreadId, cbGetTextWindow, 0);
    /* CRS: free the process and thread handles */
    CloseHandle(piProcInfo.hProcess);
    CloseHandle(piProcInfo.hThread);
    //下面3行是我隨意寫的,你可以改成你想要的指令傳給gnuplot
    PostString(hwndText, "plot x**2\n");
    Sleep(10000);
    PostString(hwndText, "\nexit\n");
    return EXIT_SUCCESS;
}
/*******************************************************************/
以上程式修改自:
 
沒有留言:
張貼留言