Tôi có mã VB6 (cũ) mà tôi muốn sử dụng từ mã C#.Tiêu thụ mảng chuỗi VB6 trong C#
Điều này hơi giống với this question, nhưng nó đề cập đến việc truyền một mảng từ VB6 tiêu thụ một đĩa C#. Vấn đề của tôi là ngược lại.
Trong VB, có một giao diện trong một dll và triển khai trong một dll khác.
Interface:
[
odl,
uuid(339D3BCB-A11F-4fba-B492-FEBDBC540D6F),
version(1.0),
dual,
nonextensible,
oleautomation,
helpstring("Extended Post Interface.")
]
interface IMyInterface : IDispatch {
[id(...),helpstring("String array of errors.")]
HRESULT GetErrors([out, retval] SAFEARRAY(BSTR)*);
};
thực hiện (fragment) trong cMyImplementationClass:
Private Function IMyInterface_GetErrors() As String()
If mbCacheErrors Then
IMyInterface_GetErrors = msErrors
End If
End Function
Tôi bọc những 2 dlls với Tlbimp.exe và cố gắng để gọi hàm từ C#.
public void UseFoo()
{
cMyImplementationClass foo;
...
var result = foo.GetErrors();
...
}
Gọi foo.GetErrors() gây ra SafeArrayRankMismatchException. Tôi nghĩ rằng điều này cho thấy vấn đề marshaling như được mô tả trong phần Mảng an toàn here.
Đề xuất có vẻ là sử dụng tham số/sysarray của tlbimp.exe hoặc để chỉnh sửa thủ công IL được tạo, mà tôi đã thử.
Các IL gốc trông như thế này:
.method public hidebysig newslot virtual
instance string[]
marshal(safearray bstr)
GetErrors() runtime managed internalcall
{
.override [My.Interfaces]My.Interface.IMyInterface::GetErrors
} // end of method cImplementationClass::GetErrors
Trong khi phiên bản cập nhật là:
.method public hidebysig newslot virtual
instance class [mscorlib]System.Array
marshal(safearray)
GetErrors() runtime managed internalcall
{
.override [My.Interfaces]My.Interface.IMyInterface::GetErrors
} // end of method cImplementationClass::GetErrors
tôi thực hiện thay đổi chức năng chữ ký giống hệt nhau trong cả giao diện và thực hiện. Quá trình này được mô tả here. Tuy nhiên, nó không chỉ định giá trị trả về trong hàm (nó sử dụng tham chiếu "trong") và cũng không sử dụng giao diện. Khi tôi chạy mã và gọi từ C#, tôi gặp lỗi
Không tìm thấy phương thức: 'System.Array MyDll.cImplementationClass.GetErrors()'.
Dường như có sự cố trong IL mà tôi đã chỉnh sửa, mặc dù tôi không biết phải đi đâu từ đây.
Làm cách nào để có thể sử dụng hàm này từ C# mà không thay đổi mã VB6?
--Chỉnh sửa-- Định nghĩa lại "msErrors", khởi tạo mảng riêng được trả về.
ReDim Preserve msErrors(1 To mlErrorCount)
Nếu tôi hiểu chính xác, "1" trong đó có nghĩa là mảng được lập chỉ mục từ 1 thay vì 0, là nguyên nhân của ngoại lệ tôi thấy bị ném.
Tôi hiểu rằng bạn muốn nhận nó làm việc đầu tiên, nhưng việc chỉnh sửa các IL không có vẻ như một giải pháp lâu dài. –
Có lẽ như vậy, nhưng đó là thực hành được khuyến nghị cho các thay đổi marshaling được đề cập [ở đây] (https://msdn.microsoft.com/en-us/library/ek1fb3c6 (v = vs.100) .aspx # cpconeditingmicrosoftintermediatelanguagemsilanchor4). FWIW, cờ/sysarray dường như có cùng hiệu ứng ròng, bao gồm cả lỗi kết quả. – ayers
Bạn chưa chỉ ra cách bạn khai báo mảng mà bạn trả lại từ mã VB6. Liệu nó có xếp hạng 1 và thấp hơn bị ràng buộc 0, tức là tuyên bố là một cái gì đó giống như 'Dim msErrors (0 To N) là String'? Ngoài ra, nếu mbCacheErrors là sai, thực hiện hiện tại của bạn dường như đang trả về một mảng chưa được khởi tạo. – Joe