2013-02-25 45 views
3

我正在創建一個包裝類,它包裝了特定第三方API中列出的一堆功能。當我嘗試包裹非成員函數是這樣的:如何包裝成員函數的DLL函數?

(AVTcamDllWrapper.h)

typedef VmbErrorType (WINAPI * AVTGETCAMERAS) (CameraPtrVector cameras); 

class CAVTcamDllWrapper 
{ 
    HMODULE mAVTCamLibrary; //I later have this point to the DLL 

public: 
    void AVTGetCameras (CameraPtrVector cameras); 
}; 

(AVTcamDllWrapper.cpp)

void CAVTcamDllWrapper::AVTGetCameras(AVTNS CameraPtrVector cameras) 
{ 

    AVTGETCAMERAS pFunc = NULL; 

    pFunc = (AVTGETCAMERAS) GetProcAddress(mAVTCamLibrary, "[email protected]@[email protected]@@[email protected]@[email protected]@[email protected]@@@[email protected]@Z"); 
    DWORD dw = GetLastError(); 
    if(pFunc == NULL) 
    { 
     Exlog(L"CAVTcamDllWrapper::AVTGetCameras: Failed to locate AVTGetCameras method in AVTCamera DLL."); 
     NIERR_SET_AND_THROW_ERROR(NIERR_CAMERA_ERROR, L"Failed to locate AVTGetCameras method in AVTCamera DLL."); 
    } 
    VmbErrorType vErr = pFunc(cameras); 

    if(vErr != VmbErrorSuccess) 
    { 
     wstring exLogMsg = Format(exLogMsg, L"CAVTcamDllWrapper::AVTGetCameras(): Failed to get any cameras. VmbErrorType = %d", vErr); 
     Exlog(exLogMsg.c_str()); 

     NIERR_SET_AND_THROW_ERROR(NIERR_CAMERA_ERROR, L"Failed to get any cameras."); 
    } 
} 

上面的代碼的偉大工程非會員功能。例如,如果我想換一個由簡單地說,所謂的功能:

CallFunction(blah, blaaaaah); 

然後包裝類工作正常,並且pFunc設置正確,並在VmbErrorType vErr = pFunc();線沒有出現錯誤;

然而,我的很多功能是成員函數,並且被稱爲是這樣的:

SomeObject.CallMemberFunction(blah, bleh); 

// or 

SomeObjectPointer->CallMemberFunction(what, ever); 

,這些都是我似乎無法換行功能。上線時出現錯誤:

VmbErrorType vErr = pFunc(); 

因爲功能不能沒有一個特定的對象從調用它來調用。在我的例子中,我正在包裝Camera中存在的函數GetCameras。如果沒有包裝的功能,稱之爲我簡單地創建攝像頭指針的向量,並做到:

cameras[0]->GetCameras(VmbAccessModeFull); 

其中工程。但我不知道如何去包裝這個功能,因爲GetCameras的調用都依賴於cameras[0],並且完全沒有相機來調用它。

那麼如何包裝上面顯示的成員函數呢?


編輯1:

我試圖在參考傳遞給特定對象,做

VmbErrorType vErr = theObject->pFunc(); 

,但顯然這是行不通的,因爲那會請考慮在object中查找名爲pFunc的函數,該函數不存在。


編輯2:

我覺得我幾乎有修改包裝函數傳遞引用對象作爲參數什麼的。所以像,而​​不是常規:

cameras[0]->GetCameras(VmbAccessModeFull); 

我將不得不修改一些東西,使我的包裝功能是這樣的:

mWrapperObject->WrappedGetCameras(VmbAccessModeFull, cameras[0]); 

,使包裝的功能將需要採取行動的情況下作爲成員函數。

+0

成員函數可能需要訪問'this'指針,例如用於訪問成員變量。如果確實如此,您將*需要一些實例來調用該方法。 – 2013-02-25 16:58:35

+0

但是,這不會產生一個錯誤,或者說,一個無法解讀的程序?它會尋找一個名爲pFunc任何對象'this'指的是內部函數,它不會找到一個,例如:如果我在'this'通過爲'theObject',然後我會做'VmbErrorType VERR = theObject - > pFunc();',這不會編譯,因爲有theObject – xcdemon05 2013-02-25 17:10:26

+0

的內部沒有pFunc功能對於WINAPI裝飾功能,相機[0]應該是第一參數。 – 2013-03-02 09:04:24

回答

0

做到這一點下面是它是如何做。假設你有兩層:成員函數層和包裝函數層。您需要做的是創建位於這兩個圖層之間的第三個圖層,並將此圖層導出爲.dll文件。起初,(回來時,我問的問題),我試圖總結,看上去像這樣的功能:

void SomeClass::SomeFunction(CString someParam) 
{ 
    //blah blah 
} 

這並沒有工作,因爲,作爲問題描述,你不能完成的成員函數。我發現我需要在成員函數調用之上的層上執行所有的對象管理,但仍然在包裝函數之下。我最終得到的是一堆「橋」功能(這就是我稱之爲的),它們「彌合了」包裝函數和成員函數之間的差距。所以,現在,我包看起來像這樣的功能:

void BridgedSomeFunction(CString someParam) 
{ 
    classObject.SomeFunction(someParam); 
} 

然後,我只是做了一些__declspec(dllexport)的和__declspec(dllimport)的將這些功能集成到一個.dll文件,這就是它!

0

要調用成員函數,您必須手頭有一個對象。要有一個對象,你必須從某個地方得到它。唯一一個有良好行爲能力的小功能可以從它的參數列表中獲取。

因此,你的每個函數顯然必須有一個接收對象的參數。

如果您希望封裝函數可以從C中調用,則不能將類類型作爲函數參數。所以你要麼聲明它爲void*,並在裏面進行投射,或只是作弊並鍵入它(僅限C!)struct YourClassName*(沒有定義結構)。對於C++,它應該仍然使用class關鍵字。使用預處理器。

簡而言之,

foo->bar(moo, roo) 

是說

FooType_bar(foo, moo, roo) 

看中shmancy C++方式,你應該想想包裝後者,而實際上拼寫前者。

調用者如何獲得對象呢?其中一個函數可以創建對象(使用new)並返回指向它們的指針。另一個可以做刪除。或者你可以返回指向預分配數組元素的指針。管他呢。基本上,你用原來打開的庫的用戶來包裝你用來獲取指向對象的指針的方式。

就是這樣。

0

如果您調用memberfunctions並確保使用正確的調用約定,則只需要將此指針作爲第一個參數傳遞。對於靜態成員函數,你不必傳遞這個指針。

在x64上,您甚至不必擔心調用約定,因爲所有內容都將被編譯爲__fastcall。無論您指定什麼調用約定。

#include <iostream> 
#include <stdint.h> 


class Camera 
{ 
    int i; 
public: 
    Camera() 
    { 
     i = 123; 
    } 


    void __stdcall print_1(int j, int k) 
    { 
     std::cout << i << j << k << std::endl; 
    } 

    void __cdecl print_2(int j, int k) 
    { 
     std::cout << i << j << k << std::endl; 
    } 

    void print_3(int j, int k) 
    { 
     std::cout << i << j << k << std::endl; 
    } 

    static void __cdecl print_s1(int j, int k) 
    { 
     std::cout << j << k << std::endl; 
    } 

    static void __stdcall print_s2(int j, int k) 
    { 
     std::cout << j << k << std::endl; 
    } 
}; 

int main() { 
    Camera cam; 
    Camera* pCam = &cam; 

    // call __stdcall memberfunction 
    typedef void (__stdcall* tprint_1)(Camera*,int,int); 
    tprint_1 print_1 = (tprint_1)&Camera::print_1; 
    print_1(pCam,1,2); 

    // call __cdecl memberfunction 
    typedef void (__cdecl* tprint_2)(Camera*,int,int); 
    tprint_2 print_2 = (tprint_2)&Camera::print_2; 
    print_2(pCam,3,4); 

    // call __thiscall memberfunction 
    typedef void (__thiscall* tprint_3)(Camera*,int,int); 
    tprint_3 print_3 = (tprint_3)&Camera::print_3; 
    print_3(pCam,5,6); 

    // call __thiscall memberfunction different syntax 
    typedef void (Camera::* tprint_4)(int,int); 
    tprint_4 print_4 = (tprint_4)&Camera::print_3; 
    (pCam->*print_4)(7,8); 


    // static member functions don´t take a this pointer 
    typedef void(__cdecl* tprint_s1)(int,int); 
    tprint_s1 print_s1 = (tprint_s1)&Camera::print_s1; 
    print_s1(9,10); 

    // static member functions don´t take a this pointer 
    typedef void(__stdcall* tprint_s2)(int,int); 
    tprint_s2 print_s2 = (tprint_s2)&Camera::print_s2; 
    print_s2(11,12); 


    return 0; 
} 
+0

雖然會傳遞'this'指針工作嗎?如果你看看我的包裝類的實現,我正在創建一個指向我想打包的函數的指針,叫做「pFunc」。如果我傳入一個'this'指針,例如'pThis',那麼我該怎麼處理它呢?如果我試圖調用pThis-> pFunc,那麼會導致我的程序無法編譯,因爲我在這個名爲pFunc中沒有函數。 – xcdemon05 2013-02-28 21:12:57

+0

你可以這樣調用它 – user1283078 2013-02-28 22:43:54

+0

你無法通過包裝類的thispointer。你將不得不將這個指針傳遞給你想要調用的方法。這是我例子中的第一個論點。由於您不能直接調用pThis-> pFunc,因此必須將pThis作爲第一個參數傳遞,如print_1至_3。或者使用print_4示例的語法。 _3和_4與typedef和call的不同語法相同 – user1283078 2013-02-28 22:58:17