Tenho código VB6, que não pode ser alterado, chamando funções de uma dll externa. Estou substituindo a dll externa por uma dll C++ que estou escrevendo, que chamará uma dll .NET que estou escrevendo, via COM. Tenho controle sobre o C++ e o C#.
O VB6 chama as funções dll assim:
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# expondo funções via COM para C++ chamar
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
}
}
}
Cabeçalho 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();
Arquivo de código 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);
}
}
A cadeia de chamadas está funcionando depois de muita pesquisa - não sou fluente em C++.
Exceto que o problema é que as strings passadas do VB6 parecem ter caracteres de 8 bits, e o BSTR em C++ está sendo renderizado como caracteres de 16 bits.
Passando a string de 9 caracteres "ABCDEFGHI",
C++ vê䉁䑃䙅䡇I
C# vê䉁䑃䙅䡇
Não me importo em converter para uma string legível por humanos em C#, na verdade, prefiro. Mas como pode ser visto, o último caractere está faltando na string em C#
A inspeção dos bytes var bytes = Encoding.Unicode.GetBytes(s);
produz 8 bytes que incluem os primeiros 8 caracteres, 65, 66, ..., 72
, faltando o caractere final 73
, ou "I".
Acredito que estou restrito ao BSTR para COM, mas ele está cortando um caractere quando o número de caracteres é ímpar. Como passo a string inteira para o .NET? Eu preferiria que a string inteira legível por humanos fosse passada de C++ para C# em primeiro lugar, mas qualquer maneira que eu possa fazer isso funcionar está boa.