2009-02-20 34 views
5

Tôi đang tạo một trình bao bọc C++/CLI DLL phụ thuộc vào nhiều thư viện tĩnh C++. Một số hàm gọi các con trỏ không được quản lý sẽ được truyền vào. Làm cách nào để truyền chúng đúng cách?Truyền con trỏ không được quản lý trong C++/CLI

Ngoài ra, các chức năng khác mong đợi "con trỏ này" được chuyển vào dưới dạng khoảng trống *. Cách đúng để vượt qua "điều này" là gì?

Dưới đây là định nghĩa lớp học của tôi ...

public ref class RTPClient 
{ 
    public: 
     RTPClient(); 
     ~RTPClient(); 

     bool Connect(); 
     void Disconnect(); 

    private: 
     CIsmaClient* mClient; 
}; 

Dưới đây là cách sử dụng của tôi, nơi các con trỏ trong câu hỏi được sử dụng ...

RTPClient::RTPClient(): 
    mClient(NULL) 
{ 
    CIsmaClient::Create(&mClient, NULL, &AllocBuffer, &GetDataPointer, this); 
} 

Việc sử dụng & mClient và " điều này "gây ra các lỗi trình biên dịch sau đây ... 1>. \ VBLoadSimulatorDll.cpp (40): lỗi C2664: 'CIs maClient :: Tạo': không thể chuyển đổi thông số 1 từ 'cli :: interior_ptr' thành 'CIsmaClient **' 1> với 1> [ 1> Loại = CIsmaClient * 1>]

1> \. VBLoadSimulatorDll.cpp (40): lỗi C2664: 'CIsmaClient :: Tạo': không thể chuyển đổi tham số 5 từ 'VBLoadSimulator :: RTPClient^const' sang 'VOID *'

Trả lời

9

Nếu bạn đang chuyển một con trỏ tới một lớp được quản lý dễ chuyển đổi tham chiếu^thành con trỏ nhưng bạn phải ghim đối tượng được quản lý để GC không di chuyển nó vào bộ nhớ (do đó làm mất hiệu lực con trỏ)

Đây là đơn giản với pin_ptr

Tuy nhiên mã của bạn đang làm hai điều đó sẽ không làm việc

RTPClient::RTPClient(): 
     mClient(NULL) 
{ 
    CIsmaClient::Create(
     &mClient,   // 1 
     NULL, 
     &AllocBuffer, 
     &GetDataPointer, 
     this);   //2 
} 

1) Bạn đang cố gắng để lấy địa chỉ của một cái gì đó trên heap quản lý (vị trí của con trỏ đến con trỏ mClient nằm trên vùng quản lý.

Vì vậy, nó có thể di chuyển trong bộ nhớ, do đó con trỏ bên trong của nhà cung cấp trình biên dịch (có giá trị được duy trì trên các phép toán GC). Điều này cần phải là pinned và điều này sẽ chỉ hoạt động nếu chức năng Tạo không mong đợi sử dụng con trỏ sau khi phạm vi của nó đã kết thúc (nếu nó vượt qua bất cứ nơi nào khác để lưu trữ nó, điều này sẽ dẫn đến lỗi).

2) Bạn đang chuyển một số handle (biểu tượng chiếc mũ vui) thay vì một con trỏ. (Đọc phần wikipedia trên đây là một tổng quan tốt) Đây không phải là (và không thể) được hiểu bởi mã không được quản lý.

Lý do duy nhất tôi có thể nghĩ đến cho tham số này trong ngữ cảnh này là một biến trạng thái rõ ràng được chuyển đến hàm callback tiếp theo (sửa tôi nếu tôi sai). 'Điều này' trong bối cảnh này là KHÔNG BAO GIỜ sẽ hoạt động bình thường vì điều này có thể di chuyển trong bộ nhớ khi pin_ptr nằm ngoài phạm vi.

Với ý nghĩ đó, đây là một phần (thực hiện) đã được sửa chữa để làm rõ những gì có thể và không thể sửa được.

RTPClient::RTPClient(): 
     mClient(NULL) 
{ 
    // make it clear you want the address of the instance variable 
    pin_ptr<CIsmaClient*> pinnedClient = &this->mClient; 
    CIsmaClient::Create(
     pinnedClient,   // fixed 
     NULL, 
     &AllocBuffer, 
     &GetDataPointer, 
     x /* pass something else in */);   //2 
} 

Nếu bạn cung cấp thêm thông tin về những gì các tham số cuối cùng được sử dụng để tôi có thể đề nghị giải pháp khả thi

+0

Dưới đây là liên kết chính xác: http://msdn.microsoft.com/en-us/library/1dz8byfh.aspx –

+0

Con trỏ là một lớp không được quản lý mặc dù ... – cjserio

+0

nếu nó không được quản lý sau đó chỉ cần chỉ chuyển một đồng bằng C + + con trỏ chỉ là tốt. Tôi không thấy vấn đề là gì ... – ShuggyCoUk

2

Tôi nghĩ rằng bạn sẽ thấy đây là cách đơn giản nhất của đi qua một tài liệu tham khảo quản lý thông qua một con trỏ void:

void SomeFunction(void* input) 
{ 
    gcroot<ManagedClass^>* pointer = (gcroot<ManagedClass^>*)(input); 
    (*pointer)->ManagedFunction(); 
} 

void Example() 
{ 
    ManagedClass^ handle = gcnew ManagedClass(); 
    gcroot<ManagedClass^>* pointer = new gcroot<ManagedClass^>(handle); 
    SomeFunction((void*)pointer); 
    delete pointer; 
} 
+0

Tại sao bạn sử dụng 'mới' và' xóa'? –

+0

vì bạn không thể lấy địa chỉ của gcroot. bạn nên sử dụng GCHandle trực tiếp Ngoài ra, trong nhiều trường hợp, đừng ngại sử dụng Obect^* nếu bên dưới Object^nằm trên stack. ở đây: SomeFunction (& handle); và đầu vào phải được truyền tới ManagedClass^* – reuns

Các vấn đề liên quan