由於不熟悉動態連結庫的運作方式,先練習C語言呼叫動態連結庫,之後再研究python的方式。

編譯出C的動態連結庫 :

找到了一個別人學校的DLL簡單範例。

http://pws.niu.edu.tw/~ttlee/sp.100.2/dll/

雖然NetBeans在截圖時很容易閃退,但是Visual Studio的專案又會把檔案搞得太複雜,所以就將就點使用NetBeans了。

使用NetBeans建立了一個C/C++ Dynamic Library。

若沒有預設Make file,也不是二進位資料,又需要動態連結庫的話,這個類別的專案是項很好的選擇。

新建完成後,Projects的欄位就會幫使用者分類:

Header Files, Resource Files, Source Files, Test Files.

這些分類預設是空的,而在NetBeans中沒有分類的檔案是不能編譯的。

如果要讓既有的檔案歸類,在想添加的目錄上按下右鍵,選擇"Add Existing Item...",再選擇想加入的檔案就行了。

按照範例先在SciTE中寫好了三個檔案。

編譯成DLL文件的是dllmain.c和dll.h,編譯成執行檔的是call DLL.c,在標頭檔dll.h中有相關紀錄。

DLL中的Add函式中輸入三個類型分別是char、int、int的值,會回傳一串文字,類型是char。

DLLIMPORT char* Add(char*str, int a, int b)
{
    printf("This is your ID(8):\n");
    printf("Your ID: %s\n", str);
    printf("%d+%d=%d:\n", a, b, a+b);
    return "OK";
}

標頭檔中也有這一段匯入,供可執行檔呼叫。

DLLIMPORT char* Add(char*, int, int);

這時候先編譯動態連結庫,在專案上按右鍵,選擇Properties。

在Build的設定中,Configuration Type的選項選擇Dynamic Library,設定好後按下Build鈕。

這時候會顯示成功,並在\dist\Debug\MinGW的資料中編譯出dll檔,動態連結庫就算是成功了。


編譯出C的可執行檔 :

這時再把call DLL.c加入Source File中。

call DLL.exe主要就是接受使用者輸入的三個值,並讓動態連結庫處理完顯示值後,再把顯示值回傳,顯示給使用者看。

call DLL.c的主程式如下:

int main(void)
{
    int i1, i2;
    char str1[9];
    printf("Key in:\n");
    scanf("%s,%d,%d", &str1, i1, i2);
    printf("\n");

    HMODULE hInst=LoadLibrary("DLLtest.dll");
    if(hInst==NULL){
        printf("Can't load library.\n");
        system("PAUSE");
        return 1;
    }
    char* (*CallDll)(char*, int, int);
    (FARPROC*)(CallDll)=GetProcAddress(hInst, "Add");
    if(CallDll==NULL){
        printf("NO Value.\n");
        system("PAUSE");
        return 2;
    }
    printf("Result: %s\n", CallDll(str1, i1,i2));
    FreeLibrary(hInst);
    system("PAUSE");
    return 0;
}

然而在編譯時,NetBeans卻顯示了下列訊息:

顯示是在這段出了問題:

(FARPROC*)(CallDll)=GetProcAddress(hInst, "Add");

這裡的問題是定義項和被定義項的關係錯誤。

上網查了一些資料,使用的語法都試過了,但是問題仍然無法解決。

由於是內建函式,所以不太了解其格式甚麼的。

於是回去觀察Solvespace的標頭檔,發現CDemo是直接使用這段:

DLL void Slvs_Solve(Slvs_System *sys, Slvs_hGroup hg);

完全不用呼叫dll名稱什麼的。

因為在slvs.h中,所有的格式在開始就寫得清清楚楚,所以若要使用,必須將需要的數值按照規定的格式填入,然後由最高層的"Slvs_"指派計算。

編譯後,動態連結庫取代了標頭檔的功能,包裝各項副程式後,在同個目錄下,可以供其他想使用函式的可執行檔使用。

至於工程師規定的格式在slvs.h的註解中有所說明。


雖然這次編譯基礎程式時失敗了,但是瞭解這些引用功能的方式,仍然是有所收穫。

下次應該是模仿CDemo寫題目給libslvs.dll求解,不過若之後是要使用python的話還需要再研究一下SWIG的功能。


Comments

comments powered by Disqus