我有 VB6 代码,无法更改,从外部 dll 调用函数。我正在用我正在编写的 C++ dll 替换外部 dll,它将通过 COM 调用我正在编写的 .NET dll。我可以控制 C++ 和 C#。
VB6 调用 dll 函数如下:
Declare Sub IEsend _
Lib "IEEE_32M1.DLL" _
Alias "_ieee_send@16" (ByVal addr As Long, _
ByVal s As String, _
ByVal l As Long, _
status As Long)
C# 通过 COM 公开函数以供 C++ 调用
namespace IEEE_32MCOM
{
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("41C9877D-C110-4CBC-9E1B-4507D220DBCD")]
public interface IIEEE_32MCOM
{
void _ieee_sendCOM(int addr, string s, int l, ref int status);
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
[Guid("FE506B77-AD6B-4C37-97E2-A7A5DDE0CA52")]
public class IEEE_32MCOMClass : IIEEE_32MCOM
{
public void _ieee_sendCOM(int addr, string s, int l, ref int status)
{
// .NET stuff here
}
}
}
C++ 标头
#pragma once
#include <string>
#import "IEEE_32MCOM.tlb" raw_interfaces_only, named_guids
extern "C"
{
#pragma comment(linker, "/EXPORT:ieee_send=_ieee_send@16")
__declspec(dllexport) void __stdcall ieee_send(long addr, BSTR cmd, long l, long* status);
}
IEEE_32MCOM::IIEEE_32MCOM* myInterface;
void init();
C++ 代码文件
#pragma comment(lib, "IEEE_32MCOM.tlb")
#include "pch.h"
#include "IEEE_32M1.h"
extern "C" __declspec(dllimport) void _ieee_sendCOM(long addr, BSTR cmd, long l, long* status);
void __stdcall ieee_send(long addr, BSTR cmd, long l, long* status)
{
init();
myInterface->_ieee_sendCOM(addr, cmd, l, status);
}
void init()
{
HRESULT hr = CoCreateInstance(
__uuidof(IEEE_32MCOM::IEEE_32MCOMClass),
NULL,
CLSCTX_ALL,
IEEE_32MCOM::IID_IIEEE_32MCOM,
(void**)&myInterface);
if (FAILED(hr))
{
_com_error e(hr);
}
}
经过大量研究后,调用链已经可以正常工作 - 我不精通 C++。
但问题是从 VB6 传递的字符串似乎是 8 位字符,而 C++ 中的 BSTR 呈现为 16 位字符。
传递 9 个字符串“ABCDEFGHI”,
C++ 看到䉁䑃䙅䡇I
C# 看到䉁䑃䙅䡇
我不介意在 C# 中将其转换为人类可读的字符串,实际上我更喜欢它。但可以看出,C# 中的字符串缺少最后一个字符
检查字节,var bytes = Encoding.Unicode.GetBytes(s);
得到 8 个字节,其中包括前 8 个字符,65, 66, ..., 72
但缺少最后一个字符73
,即“I”。
我相信我被限制使用 BSTR 来进行 COM,但当字符数为奇数时,它会截断一个字符。如何将整个字符串传递给 .NET?我首先希望将整个人类可读的字符串从 C++ 传递到 C#,但无论如何我都可以让它工作。