我有一个COM函数应该通过LPSAFEARRAY*
out参数返回一个SafeArray .该函数使用ATL的CComSafeArray
模板类创建SafeArray .我的天真实现用于CComSafeArray<T>::Detach()
将所有权从局部变量移动到输出参数:
void foo(LPSAFEARRAY* psa)
{
CComSafeArray<VARIANT> ret;
ret.Add(CComVariant(42));
*psa = ret.Detach();
}
int main()
{
CComSafeArray<VARIANT> sa;
foo(sa.GetSafeArrayPtr());
std::cout << sa[0].lVal << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
问题是CComSafeArray::Detach()
执行一个Unlock
操作,以便当SafeArray的新所有者(sa
在这种情况下为main )被销毁时,锁定不为零并且Destroy
无法解锁SafeArray E_UNEXPECTED
(这导致内存泄漏,因为SafeArray不是解除分配).
通过COM方法边界将所有权转移到CComSafeArrays的正确方法是什么?
编辑:从单个答案到目前为止似乎错误是在客户端(main
)而不是从服务器端(foo
),但我发现很难相信这CComSafeArray
不是为这个琐碎的用例设计的,必须是一种优雅的方法,可以将COMA方法中的SafeArray转换为CComSafeArray
.
我需要从C++调用我的C#方法
最初我的C#方法接受double []类型的参数,但是当从C++调用时它变成了SAFEARRAY
在C++中,我需要从双精度数组中获取数据,并填充SAFEARRAY.我没有找到任何示例代码来执行此操作.
任何帮助表示赞赏
如何迭代C++ safearray指针指向并访问其元素.
我试图复制发表林生物LIONG解决 http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/022dba14-9abf-4872-9f43-f4fc05bd2602 但奇怪的是,该IDL方法签名出来了
HRESULT __stdcall GetTestStructArray([out] SAFEARRAY ** test_struct_array);
Run Code Online (Sandbox Code Playgroud)
代替
HRESULT __stdcall GetTestStructArray([out] SAFEARRAY(TestStruct)* test_struct_array);
Run Code Online (Sandbox Code Playgroud)
有任何想法吗?
提前致谢
我有一个c ++函数来获取数据,我从c#调用它.该函数获取一个指向SAFEARRAY的指针并用字符串弹出它(使用SysAllocString)
一切都很好,但程序泄漏了内存.
我做了一点搜索,发现如果我将此属性添加到方法签名:
[MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)]
out string[] strServerList
Run Code Online (Sandbox Code Playgroud)
我需要在c ++代码中释放它(它被分配),所以我创建了这个函数
[DllImport("Native.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "DeallocateExternal")]
internal static extern void DeallocateExternal(
[MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)]
out string[] strServerList);
Run Code Online (Sandbox Code Playgroud)
在我的DLL中我写了这段代码
void DeallocateExternal(SAFEARRAY** psa)
{
LONG cDims = SafeArrayGetDim(*psa);
BSTR* pvData = (BSTR*)((*psa)->pvData);
for (LONG x = 0; x < cDims; x++)
{
SysFreeString(pvData[x]);
}
SafeArrayDestroy(*psa);
}
Run Code Online (Sandbox Code Playgroud)
但我有一个例外:
Tester.exe中发生了未处理的"System.AccessViolationException"类型异常
附加信息:尝试读取或写入受保护的内存.这通常表明其他内存已损坏.
怎么了?
这是我的C#服务器方法:
public void Exec(out int status, string output)
{
status = 3;
Console.WriteLine("Exec({0}, ...)", status);
output = string.Format("Hello from .NET {0}", DateTime.Now);
Console.WriteLine("Exec(..., {0})", output);
}
Run Code Online (Sandbox Code Playgroud)
我的C++客户端正在设置并调用此方法.这工作正常,但状态和输出变量似乎不是链接.就好像它们是通过价值而不是通过引用传递的.
这是我的客户端代码:
InitCLR();
LONG index = 0;
LONG i1 = 12; // just some number for testing
BSTR s1 = SysAllocString(L"Hello world");
SAFEARRAY* args = NULL;
CHECK_HRESULT( SafeArrayAllocDescriptor(1, &args) );
args->cbElements = sizeof(VARIANT);
args->rgsabound[0].lLbound = 0;
args->rgsabound[0].cElements = 2;
CHECK_HRESULT( SafeArrayAllocData(args) );
// byref not working for in/out param
VARIANT arg1;
VariantInit(&arg1);
V_I4REF(&arg1) = …
Run Code Online (Sandbox Code Playgroud) 我的工作与功能的COM对象库,它返回一个VARIANT
带有SAFEARRAY
的BSTR
秒.如何显示此VARIANT
实例的值并将其保存在TStringList
?我试着在网上搜索没有明确的答案.
我尝试了以下但没有成功:
Variant V;
String mystr;
VarClear(V);
TVarData(V).VType = varOleStr;
V = ComFunction->GetValues(); //<<<<----- V is empty
mystr = (wchar_t *)(TVarData(V).VString);
Memo1->Lines->Add(mystr);
VarClear(V);
Run Code Online (Sandbox Code Playgroud) 如何使用a Safearray
将一组自定义类型(一个只包含属性的类)从C++传递给C#?使用该VT_RECORD
类型的方法是正确的吗?
我正在尝试以下方式,但对类SafeArrayPutElement
在尝试填充safearray时返回错误,数组的引用以NULL形式获取托管代码.
我在托管世界中有以下内容:
[ComVisible(true)]
public interface IStatistics
{
double Mean { get; set; }
double StdDev { get; set; }
}
[Serializable]
[ComVisible(true)]
public class Statistics : IStatistics
{
public Mean { get; set; }
public double StdDev { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
未管理的世界:
HRESULT hr = CoInitialize(NULL);
...
SAFEARRAY *pEquationsStatistics;
// common dimensions for all arrays
SAFEARRAYBOUND dimensions[1];
dimensions[0].cElements = 2;
dimensions[0].lLbound = 0;
pEquationsStatistics = SafeArrayCreate(VT_RECORD, 1, dimensions);
... …
Run Code Online (Sandbox Code Playgroud) 我正在尝试使用以下方法的COM组件:
HRESULT _stdcall Run(
[in] SAFEARRAY(BSTR) paramNames,
[in] SAFEARRAY(VARIANT *) paramValues
);
Run Code Online (Sandbox Code Playgroud)
如何在C/C++中创建paramValues数组?
我目前遇到一个问题,需要将SAFEARRAY(GUID)作为返回值从C++传递给C#.
目前,C#端正在使用从Tlbimp.exe(类型库导入程序)生成的Interop dll.
IDL是:
HRESULT GetGuids(
[out]SAFEARRAY(GUID)* guids);
Run Code Online (Sandbox Code Playgroud)
我也试过[out,retval]
功能签名是:
HRESULT
WINAPI
MyClass::GetGuids(SAFEARRAY** guids)
Run Code Online (Sandbox Code Playgroud)
如果我使用SafeArrayCreate()
或SafeArrayCreateVector()
:
SAFEARRAY* psa
psa = SafeArrayCreate(VT_CLSID, 1, rgsabound);
Run Code Online (Sandbox Code Playgroud)
我得到一个NULL SAFEARRAY
指针,它应该指示E_OUTOFMEMORY
哪个是不正确的.
我发现的VT_CLSID
只是Ole属性集而不是SAFEARRAY:http:
//poi.apache.org/apidocs/org/apache/poi/hpsf/Variant.html它表明CLSID是
我还尝试了使用以下方法构建安全数组的替代方法:
SafeArrayAllocDescriptor()
和SafeArrayAllocData()
.
hResult = SafeArrayAllocDescriptor(1, guids)
hResult = SafeArrayAllocData(*guids);
Run Code Online (Sandbox Code Playgroud)
这让我创建了数组,但是当SafeArrayPutElement()
我用它填充它时,我得到一个0x80070057的HRESULT(参数不正确).这可能是因为它也需要VT_CLSID
参数
我可以手动填充它 SafeArrayAccessData()
GUID* pData = NULL;
hResult = SafeArrayAccessData(*guids, (void**)&pData);
Run Code Online (Sandbox Code Playgroud)
但我从C#端得到一个错误:"该值不在预期的范围内"
我不确定如何通过retval或out参数完成将SAFEARRAY(GUID)返回到C#的所需功能.
它似乎应该很简单 - IDL中有很多区域我已经在没有任何UDT或编组的情况下传递GUID.一切正常,直到我需要在SAFEARRAY传递它们.
任何帮助表示赞赏,在此先感谢
我试图调用COM对象的方法,其中一个记录的参数是"字节数组 ".实际声明取决于您正在查看的每种语言文档:
在C#语言中:
byte[] TransformFinalBlock(
byte[] inputBuffer,
int inputOffset,
int inputCount
)
Run Code Online (Sandbox Code Playgroud)用C++语言;
array<unsigned char>^ TransformFinalBlock(
array<unsigned char>^ inputBuffer,
int inputOffset,
int inputCount
)
Run Code Online (Sandbox Code Playgroud)用VB语言:
Function TransformFinalBlock ( _
inputBuffer As Byte(), _
inputOffset As Integer, _
inputCount As Integer _
) As Byte()
Run Code Online (Sandbox Code Playgroud)在F#语言中:
abstract TransformFinalBlock :
inputBuffer:byte[] *
inputOffset:int *
inputCount:int -> byte[]
Run Code Online (Sandbox Code Playgroud)我正在使用的对象也可以使用COM访问.该对象提供了一个早期绑定接口ICryptoTransform
,它将该方法声明为using SAFEARRAY
.
从类型库:
使用IDL语法
[ …
Run Code Online (Sandbox Code Playgroud)safearray ×10
c++ ×7
com ×6
c# ×4
variant ×2
.net ×1
atl ×1
bstr ×1
c++builder ×1
delphi ×1
guid ×1
interop ×1
marshalling ×1
memory ×1
parameters ×1
visual-c++ ×1
winapi ×1