C++Builder 程序员博客
9 Nov
有这样一个函数原型: tagVARIANTIDocument::GetItemValue(wchar_t* text);
在它的返回结果中是一个字符串数组,如何取第一个字符串?
我这样做得到乱码:
IDocument d;
tagVARIANTa=d.GetItemValue((WideString)"Subject");
ShowMessage(ShowMessage(a.bstrVal));
请教各位高手,如何正确取字符串?
有这样一个函数原型: tagVARIANTIDocument::GetItemValue(wchar_t* text);
在它的返回结果中是一个字符串数组,如何取第一个字符串?
我这样做得到乱码:
IDocument d;
tagVARIANTa=d.GetItemValue((WideString)"Subject");
ShowMessage(a.bstrVal);
请教各位高手,如何正确取字符串?
这样试了一下,出现非法访问错误: ShowMessage( s.pbstrVal[0]);
哪位知道请指点一下,谢谢!
做了这样一个试验也不行,报内存错误,知道的朋友请说一下,谢谢,其实,我就是想从Variant 中取出字符串数组中的一个字符串。
String a[2]={"aaa","bbb"};
Variant s(a);
String ss=s.GetElement(0) ;
ShowMessage(ss );
哪位高手能给我答案?
不知妖兄(ccrun)来过没有,希望能给点意见。。。
Variant[i] 这样取值试下。
关键是:tagVARIANTa 不是指针,另外tagVARIANT可能也不支持这样的操作
tagVARIANT g; g.vt = VT_BSTR; g.bstrVal =L"hello"; ShowMessage(g.bstrVal);
不知道能不能帮到你!
你这个你面放的是N个字符串?
pbstrVal这个成员应该可以返回字符串数组的指针,但不知如何取值,我用 pbstrVal[0]操作出现内存操作错误
g.vt = VT_LPSTR ; wchar_t *p[2]={ L"hello",L"world"}; g.pbstrVal = p; ShowMessage(g.pbstrVal[1]);
我测试也通过的啊。能正确显示"world"字符串
1,你确保你在取值前,设定了vt没有
2,你确保你的COM接口返回的是字符串数组,而且你应该知道字符串数组的大小!
可以试试SafeArrayGetElement
作了如下测试,仍没有所需要的结果,大家帮帮忙
HRESULT hr; long lLower, lUpper; tagVARIANT s; s=d->GetItemValue((WideString)"$FILE"); ShowMessage(s.vt); //显示类型为8204,即8204是VT_VARIANT|VT_ARRAY unsigned int dim=SafeArrayGetDim(s.parray);//取得数组维数 ShowMessage(dim); //这里显示为1,即为一维数组 if ( ( hr = SafeArrayGetLBound(s.parray, dim, &lLower ) ) == S_OK )//数组元素上界 hr = SafeArrayGetUBound( s.parray, dim , &lUpper );//数组元素下界 else ShowMessage("error"); ShowMessage(lUpper); //这里显示为0,难道没有数组元素个数为0? WideString ss; for(long k=lLower;k<50;k++) { long y=k; SafeArrayGetElement(s.parray,&y,ss); String sss=ss; if(sss!="") ShowMessage(sss); }
HRESULT hr;
long lLower, lUpper;
tagVARIANT s;
s=d->GetItemValue((WideString)"$FILE");
ShowMessage(s.vt); //显示类型为8204,即8204是VT_VARIANT|VT_ARRAY
unsigned int dim=SafeArrayGetDim(s.parray);//取得数组维数
ShowMessage(dim); //这里显示为1,即为一维数组
if ( ( hr = SafeArrayGetLBound(s.parray, dim, &lLower ) ) == S_OK )//数组元素上界
hr = SafeArrayGetUBound( s.parray, dim , &lUpper );//数组元素下界
else
ShowMessage("error");
ShowMessage(lUpper); //这里显示为0,难道没有数组元素个数为0?/*起始下标为0*/
WideString ss;
for(long k=lLower;k/* <50*/ <=lUpper ;k++)
{
long y=k;
SafeArrayGetElement(s.parray,&y,ss);
String sss=ss;
if(sss!="")
ShowMessage(sss);
}
很难知道原始数据得到的具体是什么内容,除非楼主说明具体的应用环境
我这里用于取NOTES邮件的附件信息,返回值中有附件文件名,文件大小,创建日期等信息,根据HELP返回值应该是一字符串数组,存于一个tagVARIANT类型变量中。现在的问题是如何从这个tagVARIANT类型变量中得到这些信息?
没有环境,无法帮你测试.不过可以把Variant存为文件,然后帮你分析.告诉我你的邮箱吧.
unit VBVariants; interface uses Variants,Classes,ActiveX,ComObj; const EasyArrayTypes = [varSmallInt, varInteger, varSingle, varDouble, varCurrency, varDate, varBoolean, varByte]; VariantSize: array[0..varByte] of Word = (0, 0, SizeOf(SmallInt), SizeOf(Integer), SizeOf(Single), SizeOf(Double), SizeOf(Currency), SizeOf(TDateTime), 0, 0, SizeOf(Integer), SizeOf(WordBool), 0, 0, 0, 0, 0, SizeOf(Byte)); type PIntArray = ^TIntArray; TIntArray = array[0..0] of Integer; PVariantArray = ^TVariantArray; TVariantArray = array[0..0] of OleVariant; TVarFlag = (vfByRef, vfVariant); TVarFlags = set of TVarFlag; function GetVariantPointer(const Value: OleVariant): Pointer; function ReadArray(VType: Integer;const Data: TStream): OleVariant; procedure WriteArray(const Value: OleVariant; const Data: TStream); function ReadVariant(out Flags: TVarFlags;const Data: TStream): OleVariant; procedure WriteVariant(const Value: OleVariant;const Data: TStream); implementation function GetVariantPointer(const Value: OleVariant): Pointer; begin case VarType(Value) of varEmpty, varNull: Result := nil; varDispatch: Result := TVarData(Value).VDispatch; varVariant: Result := @Value; varUnknown: Result := TVarData(Value).VUnknown; else Result := @TVarData(Value).VPointer; end; end; function ReadArray(VType: Integer; const Data: TStream): OleVariant; var Flags: TVarFlags; LoDim, HiDim, Indices, Bounds: PIntArray; DimCount, VSize, i: Integer; {P: Pointer;} V: OleVariant; LSafeArray: PSafeArray; P: Pointer; begin VarClear(Result); Data.Read(DimCount, SizeOf(DimCount)); VSize := DimCount * SizeOf(Integer); GetMem(LoDim, VSize); try GetMem(HiDim, VSize); try Data.Read(LoDim^, VSize); Data.Read(HiDim^, VSize); GetMem(Bounds, VSize * 2); try for i := 0 to DimCount - 1 do begin Bounds[i * 2] := LoDim[i]; Bounds[i * 2 + 1] := HiDim[i]; end; Result := VarArrayCreate(Slice(Bounds^,DimCount * 2), VType and varTypeMask); finally FreeMem(Bounds); end; if VType and varTypeMask in EasyArrayTypes then begin Data.Read(VSize, SizeOf(VSize)); P := VarArrayLock(Result); try Data.Read(P^, VSize); finally VarArrayUnlock(Result); end; end else begin LSafeArray := PSafeArray(TVarData(Result).VArray); GetMem(Indices, VSize); try FillChar(Indices^, VSize, 0); for I := 0 to DimCount - 1 do Indices[I] := LoDim[I]; while True do begin V := ReadVariant(Flags, Data); if VType and varTypeMask = varVariant then OleCheck(SafeArrayPutElement(LSafeArray, Indices^, V)) else OleCheck(SafeArrayPutElement(LSafeArray, Indices^, TVarData(V).VPointer^)); Inc(Indices[DimCount - 1]); if Indices[DimCount - 1] > HiDim[DimCount - 1] then for i := DimCount - 1 downto 0 do if Indices[i] > HiDim[i] then begin if i = 0 then Exit; Inc(Indices[i - 1]); Indices[i] := LoDim[i]; end; end; finally FreeMem(Indices); end; end; finally FreeMem(HiDim); end; finally FreeMem(LoDim); end; end;
//续上
procedure WriteArray(const Value: OleVariant; const Data: TStream); var VType, VSize, i, DimCount, ElemSize: Integer; LSafeArray: PSafeArray; LoDim, HiDim, Indices: PIntArray; V: OleVariant; P: Pointer; begin VType := VarType(Value); LSafeArray := PSafeArray(TVarData(Value).VPointer); Data.Write(VType, SizeOf(Integer)); DimCount := VarArrayDimCount(Value); Data.Write(DimCount, SizeOf(DimCount)); VSize := SizeOf(Integer) * DimCount; GetMem(LoDim, VSize); try GetMem(HiDim, VSize); try for i := 1 to DimCount do begin LoDim[i - 1] := VarArrayLowBound(Value, i); HiDim[i - 1] := VarArrayHighBound(Value, i); end; Data.Write(LoDim^,VSize); Data.Write(HiDim^,VSize); if VType and varTypeMask in EasyArrayTypes then begin ElemSize := SafeArrayGetElemSize(LSafeArray); VSize := 1; for i := 0 to DimCount - 1 do VSize := (HiDim[i] - LoDim[i] + 1) * VSize; VSize := VSize * ElemSize; P := VarArrayLock(Value); try Data.Write(VSize, SizeOf(VSize)); Data.Write(P^,VSize); finally VarArrayUnlock(Value); end; end else begin GetMem(Indices, VSize); try for I := 0 to DimCount - 1 do Indices[I] := LoDim[I]; while True do begin if VType and varTypeMask <> varVariant then begin OleCheck(SafeArrayGetElement(LSafeArray, Indices^, TVarData(V).VPointer)); TVarData(V).VType := VType and varTypeMask; end else OleCheck(SafeArrayGetElement(LSafeArray, Indices^, V)); WriteVariant(V, Data); Inc(Indices[DimCount - 1]); if Indices[DimCount - 1] > HiDim[DimCount - 1] then for i := DimCount - 1 downto 0 do if Indices[i] > HiDim[i] then begin if i = 0 then Exit; Inc(Indices[i - 1]); Indices[i] := LoDim[i]; end; end; finally FreeMem(Indices); end; end; finally FreeMem(HiDim); end; finally FreeMem(LoDim); end; end; function ReadVariant(out Flags: TVarFlags; const Data: TStream): OleVariant; var I, VType: Integer; W: WideString; TmpFlags: TVarFlags; begin VarClear(Result); Flags := []; Data.Read(VType, SizeOf(VType)); if VType and varByRef = varByRef then Include(Flags, vfByRef); if VType = varByRef then begin Include(Flags, vfVariant); Result := ReadVariant(TmpFlags, Data); Exit; end; if vfByRef in Flags then VType := VType xor varByRef; if (VType and varArray) = varArray then Result := ReadArray(VType, Data) else case VType and varTypeMask of varEmpty: VarClear(Result); varNull: Result := NULL; varOleStr: begin Data.Read(I, SizeOf(Integer)); SetLength(W, I); Data.Read(W[1], I * 2); Result := W; end; {varDispatch: begin Data.Read(I, SizeOf(Integer)); Result := TDataDispatch.Create(Self, I) as IDispatch; end;} //varUnknown: // raise EInterpreterError.CreateResFmt(@SBadVariantType,[IntToHex(VType,4)]); else TVarData(Result).VType := VType; Data.Read(TVarData(Result).VPointer, VariantSize[VType and varTypeMask]); end; end; procedure WriteVariant(const Value: OleVariant; const Data: TStream); var I, VType: Integer; W: WideString; begin VType := VarType(Value); if VarIsArray(Value) then WriteArray(Value, Data) else case (VType and varTypeMask) of varEmpty, varNull: Data.Write(VType, SizeOf(Integer)); varOleStr: begin W := WideString(Value); I := Length(W); Data.Write(VType, SizeOf(Integer)); Data.Write(I,SizeOf(Integer)); Data.Write(W[1], I * 2); end; {varDispatch: begin //if VType and varByRef = varByRef then // raise EInterpreterError.CreateResFmt(@SBadVariantType,[IntToHex(VType,4)]); I := StoreObject(Value); Data.Write(VType, SizeOf(Integer)); Data.Write(I, SizeOf(Integer)); end;} varVariant: begin //if VType and varByRef <> varByRef then // raise EInterpreterError.CreateResFmt(@SBadVariantType,[IntToHex(VType,4)]); I := varByRef; Data.Write(I, SizeOf(Integer)); WriteVariant(Variant(TVarData(Value).VPointer^), Data); end; //varUnknown: // raise EInterpreterError.CreateResFmt(@SBadVariantType,[IntToHex(VType,4)]); else Data.Write(VType, SizeOf(Integer)); if VType and varByRef = varByRef then Data.Write(TVarData(Value).VPointer^, VariantSize[VType and varTypeMask]) else Data.Write(TVarData(Value).VPointer, VariantSize[VType and varTypeMask]); end; end; end.
使用readVariant和writeVariant将tagVariant与TStream(可以是TFileStream或TMemoryStream),然后再存为文件即可.发到我的邮箱:unsigned@126.com
如果确定返回的是一个字符串,那么VT_VARIANT|VT_ARRAY类型说明它是为了和脚本兼容,应该可以这样做:
Variant varR = d->GetItemValue(WideString("$FILE"));
Variant varEle1 = varR.GetElement(1); // 可以通过ArrayDimCount/ArrayHighBound/ArrayLowBound得到维数/上限/下限(不一定是0)
楼主先看看varR的ArrayDimCount/ArrayHighBound/ArrayLowBound各是多少再用GetElement得到其中一个数据varEle1,再看看它的vt是什么类型,很可能就是你要的第一个字符了。
你可以看一下我回的这个帖子:http://topic.csdn.net/u/20080909/12/d08db442-ef7e-4ab0-aafa-151e67b2f6f2.html那个代码片是用于和脚本数组通信的。
tagVARIANT a;
WideString s="aaa";
a=Variant(s);
ShowMessage(a.bstrVal); //这里能正常显示 aaa
换成如下,用数组初始化却不行
tagVARIANT a;
WideString s[2]={"aaa","bbb"};
a=Variant(s);
ShowMessage(a.pbstrVal[0]); //非法访问地址,内存出错
Variant varData[2]={"aaa","bbb"}; Variant varA(varData,1); // 产生一个包含"aaa","bbb"的Variant tagVARIANT a={0,0}; ::VariantCopy(&a, (tagVARIANT*)&varA ); // 现在a.vt=8204(VT_VARIANT|VT_ARRAY) unsigned int nDim = ::SafeArrayGetDim(a.parray); long lLB,lUB; ::SafeArrayGetLBound(a.parray,1,&lLB); ::SafeArrayGetUBound(a.parray,1,&lUB); // 结果:nDim=1, lLB=0, lUB=1; tagVARIANT ele={0,0}; long lidx[]={0}; ::SafeArrayGetElement(a.parray, lidx, &ele); ShowMessage(ele.bstrVal); // 显示aaa
因为涉及到COM接口,所以还是建议对接口传过来的内容做分析.
看一下这个,tagVARIANT可以使用Variant(tagVARIANT_Value)转换
http://topic.csdn.net/u/20080617/12/8756bef8-c049-48a6-b585-adb49e52dc9c.html?1364875940