2012-01-19 46 views
5

Tôi có tiêu đề chức năng sau đây trong một DLL bản địa:soái một unsigned char * chức năng trở về từ một dll, trong C#

unsigned char* Version_String() 

Tôi đang cố gắng gọi nó từ một dự án C#, tôi đã cố gắng cuộc gọi sau (như được tìm thấy trên những câu hỏi tương tự khác ở đây):

[DllImport("BSL430.dll", CharSet=CharSet.Ansi)] 
public extern static UIntPtr Version_String(); 

Và tôi tiếp tục nhận được ngoại lệ sau đây:

cố gắng để đọc hoặc viết Prot bộ nhớ ected. Đây thường là dấu hiệu cho thấy rằng bộ nhớ khác bị hỏng.

Các thử tiếp theo là sau đây và tôi nhận được cùng một ngoại lệ:

[DllImport("BSL430.dll", CharSet=CharSet.Ansi)] 
[return : MarshalAs(UnmanagedType.LPStr)] 
public extern static string Version_String(); 

tôi dường như không thể để có được xung quanh vấn đề này. Mọi sự trợ giúp sẽ rất được trân trọng!

Edit: vẻ

tôi không thể cung cấp cho mã DLL đây, do được xếp vào một NDA, nhưng chức năng tôi gọi như thế này:

unsigned char versionString[50]; 

__declspec(dllexport) unsigned char* Version_String() 
{ 
    if(check_hardware_stuff()) 
    { 
     strcpy((char *) versionString, "version_string_bla_bla"); 
     versionString[5] = stuff; 
    } 
    else if (other_check()) 
    { 
     //will return empty string, that should be filled with '\0' 
    } 
    else 
    { 
     strcpy((char *) versionString, "ERROR"); 
    } 
    return versionString; 
} 

Tôi không đặc biệt thích việc thực hiện DLL, nhưng tôi cần phải sử dụng nó "vì nó là". Tôi bị loại trừ bất cứ khi nào tôi cố gắng gọi VersionString(), bất kể tôi làm gì với giá trị trả lại.

+0

Có thể bạn đang sử dụng sai [quy ước gọi điện] (http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.callingconvention.aspx)? – svick

+0

Dll của bạn có được biên dịch với tùy chọn bộ ký tự MultiByte không? –

+1

Sử dụng trình gỡ rối để tìm ra nơi mã gốc bị treo. Project + Properties, Debug, đánh dấu chọn "Enable unmanaged code debugging". Đặt điểm ngắt trên hàm trong tệp mã nguồn C. –

Trả lời

8

Cập nhật

Sau khi nhìn thấy các câu hỏi được cập nhật, các ý kiến ​​khác nhau, và mã chức năng mẹ đẻ của mình, có vẻ như khả năng là ngoại lệ xảy ra khi bạn gọi check_hardware_stuff(). Nó đủ đơn giản để gỡ lỗi. Tôi sẽ thay thế chức năng của bạn bằng một cái như sau:

phiên bản char chưa kýString [50];

__declspec(dllexport) unsigned char* Version_String() 
{ 
    strcpy(versionString, "testing"); 
    return versionString; 
} 

Nếu vẫn không thành công thì phỏng đoán của tôi là lỗi được nêu trong số DllMain của tệp DLL của bạn. Debug rằng bằng cách đặt các chức năng trên vào một vani vanilla đơn giản mà không có gì khác.

Original câu trả lời

ước gọi là vấn đề rõ ràng nhất. Mã gốc của bạn rất có thể sử dụng cdecl nhưng mặc định p/invoke là stdcall. Thay đổi p của bạn/gọi chữ ký để được như thế này:

[DllImport("BSL430.dll", CallingConvention=CallingConvention.Cdecl)] 
public extern static IntPtr Version_String(); 

Bạn có thể bỏ qua một cách an toàn các thông số CharSet kể từ khi không ai trong số các thông số có văn bản bởi vì bạn đang điều trị các giá trị trả về là một con trỏ.

Chỉnh sửa: Hans chỉ ra một cách chính xác trong các nhận xét rằng vì không có tham số, kết quả trùng khớp quy ước cuộc gọi không quan trọng. Vì vậy, đây không phải là vấn đề.

Gọi Marshal.PtrToStringAnsi để chuyển đổi thành chuỗi .net.

string version = Marshal.PtrToStringAnsi(Version_String()); 

Kể từ PtrToStringAnsi được mong đợi một IntPtr thông số tôi sẽ khuyên bạn nên sử dụng IntPtr như kiểu trả về của bạn p/gọi chữ ký.

Tất cả điều này giả định rằng bộ nhớ được trả về từ hàm gốc của bạn được cấp phát và được giải phóng trong DLL gốc. Nếu đó là đống phân bổ và bạn mong đợi người gọi để deallocate nó sau đó bạn có một vấn đề nhỏ. Làm thế nào để bạn deallocate bộ nhớ từ C# kể từ khi bạn không có quyền truy cập vào heap DLL gốc?

Giải pháp đơn giản là sử dụng chia sẻ COM heap để cấp phát bộ nhớ. Gọi CoTaskMemAlloc để cấp phát bộ đệm cho chuỗi. Sau đó khai báo giá trị trả về là loại string và p/gọi marshaller sẽ deallocate với bộ cấp phát COM.

[DllImport("BSL430.dll", CallingConvention=CallingConvention.Cdecl)] 
public extern static string Version_String(); 
... 
string version = Version_String(); 

Tất nhiên, điều này chỉ áp dụng nếu bạn đang trả lại bộ nhớ phân bổ heap mà bạn mong đợi người gọi phải deallocate.

+0

Cảm ơn bạn đã trả lời nhanh chóng. Tôi đã thử mã, nhưng tôi vẫn nhận được cùng một ngoại lệ. Tôi đã nhìn vào mã DLL, và từ những gì tôi có thể cho biết chuỗi là toàn cầu khai báo như là một mảng kích thước cố định: 'unsigned char versionString [50];'. Từ những gì tôi biết, không cần phân bổ thêm trong trường hợp này, phải không? – andreiscurei

+1

Nó không thể là CallingConvention, chức năng này không nhận bất kỳ đối số nào. –

+0

Tại thời điểm nào bạn nhận được ngoại lệ? Khi gọi DLL, hoặc khi làm một cái gì đó với giá trị được trả về? –

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