混淆在使用BSTR在com dll在c++构建器
Confused in used BSTR in com dll in c++ builder
我在c++ Builder Borland中制作了一个OCX。我的OCX有如下功能:
- 登录
- 读
- DebugOutput
- GetVal
我在我的c#应用程序中使用这个OCX。在c#方面,我有一个按钮和列表框。按钮从OCX调用login
方法,列表框显示该方法的输出。
在OCX端,login
方法为服务器(使用套接字编程)创建一个命令来获得身份验证。然后调用Write
函数写入套接字。然后从套接字获取响应,调用Read
函数读取套接字响应。
Read
方法读取结果并将其发送给DebugOutput
以调试输出流并调用GetVal
以查找最后的主服务器响应。然后它们相互传递参数。最后c#端显示登录方法的结果(SUCCESS | FAIL)。
我使用BSTR。(我在stackoverflow和MSDN上阅读了关于BSTR的主题,但我认为我在解决方案中没有得到很好的解决方案)。这些是我在OCX方面的代码:
BSTR STDMETHODCALLTYPE TVImpl::Login(BSTR PassWord)
{
wchar_t wcs1[500];
Var *var=new Var();
//here make the command
...................
//get the server response to show to user
BSTR read=::SysAllocString(Write(wcs1));
if(read!=NULL) ::SysFreeString(read);
return read;
}
BSTR STDMETHODCALLTYPE TVImpl::Read()
{
BSTR str ;
try
{
IdTCPClient1->ReadTimeout=100;
str =::SysAllocString( IdTCPClient1->IOHandler->ReadLn().c_str());
}
catch(Exception &e)
{
str= e.Message.c_str();
}
str=(DebugOutput(str));
return str;
}
BSTR STDMETHODCALLTYPE TVImpl::Write(BSTR str)
{
IdTCPClient1->IOHandler->WriteLn(str) ;
BSTR str2=::SysAllocString(L"TST");
str2=Read();
return str2;
}
BSTR STDMETHODCALLTYPE TVImpl::GetVal(BSTR st,BSTR ValTyp)
{
BSTR res;
AnsiString stAnsi;
//Do some thing with st and save it to stAnsi
.................
res=(BSTR)WideString(stAnsi);
return ::SysAllocString(res);
}
BSTR STDMETHODCALLTYPE TVImpl::DebugOutput(BSTR st)
{
Var *val=new Var();
BSTR res;
res=GetVal(st,val->CMD_CMD);
if(res==val->CMD_AUTHENTICATE)
res=GetVal(st,val->XPassword);
return res;
}
在C3代码中它是挂起的。我知道我的问题是使用sysAllocString。但是当我在每个方法中使用::sysFreestring时,我的c#代码又挂起了。
这是我的c#代码:
private void button4_Click(object sender, EventArgs e)
{
VinSockCmplt.Vin vin = new Vin();
listBox1.Items.Add(vin.Login("1234"));
}
您不应该返回BSTR(或任何各种编译器以各种方式编译的"复杂"类型)。COM方法的推荐返回类型为HRESULT(32位整数)。此外,您不能释放刚刚分配的BSTR并将其返回给调用者。
你可以这样布局你的方法:
HRESULT STDMETHODCALLTYPE TVImpl::Login(BSTR PassWord, /*out*/ BSTR *pRead)
{
...
*pRead = ::SysAllocString(L"blabla"); // allocate a BSTR
...
// don't SysFreeString here, the caller should do it
...
return S_OK;
}
如果你在一个。idl文件中定义你的接口,它应该是这样的:
interface IMyInterface : IUnknown
{
...
HRESULT Login([in] BSTR PassWord, [out, retval] BSTR *pRead);
...
}
retval
用于表示对于支持它的语言来说,赋值语义是可能的,就像你最初试图实现的那样,var read = obj.Login("mypass")
你的代码中有很多错误:
-
if(read!=NULL) ::SysFreeString(read); return read;
释放一个字符串,然后返回它 -
str= e.Message.c_str();
…return str;
返回一个指向甚至不是BSTR 的东西的指针 -
BSTR str2=::SysAllocString(L"TST"); str2=Read();
分配一个字符串,然后立即泄漏该字符串 -
res=(BSTR)WideString(stAnsi);
创建悬浮指针
所有这些都是未定义的行为(除了泄漏),并可能导致崩溃。
另外,我不确定是否有你的函数返回BSTR
是有效的;COM编程中的常规约定是函数返回HRESULT
,任何"返回值"都通过[out]
参数返回。这与所有具有COM绑定的语言兼容;而实际上返回BSTR
限制了代码兼容性。(我可能是错的——欢迎指正)。你可以在你链接的另一个问题中看到这种技巧。
要获得关于"为什么我的代码崩溃了?"这样的问题的帮助,请参见如何询问和如何创建一个最小的,完整的和可验证的示例。
- 挂起和取消挂起一个文件DLL
- std::threads可以从Windows DLL中的全局变量创建/销毁吗?
- 导入库可以跨dll版本工作吗
- 从C++dll访问C#中的一行主要参数
- 链接到自行创建的dll失败
- 为什么使用 P/Invoke 调用 dll 时,某些计算机中的 LoadLibrary 失败?
- 在调用FreeLibrary后,释放动态链接到具有相同版本的CRT堆的DLL的内存
- 如何指定我希望我的LIB链接到的DLL文件?-Visual Studio 2019
- 如何将图像传输到c++(dll)中的缓冲区,然后在c#的缓冲区中读/写
- C++:将外部库链接到dll库
- 在 Windows 上,是否可以让 dll 在不使用 PATH 环境变量的情况下在另一个文件夹中查找依赖项?
- 不同的Visual Studio版本中缺少.dll
- 从DLL中删除类的实例
- 如何包装第三方DLL在R中使用
- 使用c#访问c++dll中带有char*参数的函数时发生AccessViolationException
- 系统.将数组移交给c#中动态加载的c++DLL时发生AccessViolationException
- 为什么导入Mixed native/CLR lib.dll的本机C++应用程序没有在Mixed lib.dll中的外部变
- 当我使用 C++ 中的 C# dll 来使用 Selenium 时,存在异常处理问题
- Python ctypes:不会按预期加载 dll
- 在 C++/CLI 中将 .NET 事件从一个 DLL 引发到另一个 DLL