ATL-COM-server and VBScript 
Author Message
 ATL-COM-server and VBScript

A com-server (ATL with MFC) called from ASP works fine, called from C++ I
have a problem with the parameters, but can't find it.

IDL:

[id(13), helpstring("method convert")] HRESULT convert([in] VARIANT in1,
[out,retval] VARIANT* out1);

The Server

 STDMETHODIMP CCalcServ::convert(VARIANT in1, VARIANT* out1)

{

    HRESULT hr;
    SAFEARRAY* InputArray;

    VARIANT* InputVariant;

      if ((in1.vt & VT_VARIANT) && (in1.vt & VT_BYREF))

            InputVariant = in1.pvarVal;

      else

            InputVariant = & in1;

      if ((! ( InputVariant->vt & VT_ARRAY)) || (! ( InputVariant->vt
&VT_VARIANT)))

            return Error("Expecting an array of variants");

      if (InputVariant->vt & VT_BYREF)

            hr = SafeArrayCopy(*(InputVariant->pparray), &InputArray);

      else

            hr = SafeArrayCopy(InputVariant->parray, &InputArray);

      long lbound, ubound;

      SafeArrayGetLBound(InputArray, 1, &lbound);

      SafeArrayGetUBound(InputArray, 1, &ubound);

      VariantInit(out1);

      out1->vt = VT_ARRAY | VT_VARIANT;

      out1->parray = SafeArrayCreate(VT_VARIANT, 1, InputArray->rgsabound);

      VARIANT * InputElements, * OutputElements;

      SafeArrayAccessData(InputArray, (LPVOID*)&InputElements);

      SafeArrayAccessData(out1->parray, (LPVOID*)&OutputElements);

      for(long i=lbound; i <= ubound; i++)

      {

            VARIANT Hold;

            VariantInit(& Hold);

            VariantChangeType(& Hold, & InputElements[i], 0, VT_BSTR);

            //Convert the InputElement[I] in this

            VariantInit(& OutputElements[i]);

            OutputElements[i].vt = VT_BSTR;

            OutputElements[i].bstrVal = SysAllocString(Hold.bstrVal);

            VariantClear(& Hold);

      }

      SafeArrayUnaccessData(out1->parray);

      return S_OK;

Quote:
}

// and when called from ASP with e.g  test1 =
obj.convert(Array("ABC","DEF",FGI"))  it worked.

Client:

SAFEARRAYBOUND safebound;

safebound.cElements = 2;

safebound.lLbound   = 0;

SAFEARRAY *psaLongs = SafeArrayCreate(VT_I4, 1, &safebound);

elem[0] = elem[1] = 27;    // just for test

for (i = 0; i < 2; i++)

      SafeArrayPutElement(psaLongs, &i, &elem[i]);

VARIANT* varLong=NULL;

varLong  = new VARIANT[1];

VariantInit(varLong);

varLong->vt       = VT_ARRAY| VT_VARIANT;

varLong->parray = psaLongs;

_variant_t varTbRes;

varTbRes = m_ICServ->convert(varLong);

When I enter the Server with convert, are the parameters in the ".vt"
instead of parray.

(I know I handle BSTR in the server, and feed with LONG, but this was the
latest version)

How should I set up the the client call correct?

(have also tried the CComSafeArray<ULONG> (wrapper-class)in the server, but
then I get problems with passsing parameters from VBScript.)

Where is my bug(s)?

Best Regards,

flemming



Fri, 29 Apr 2005 16:59:39 GMT  
 ATL-COM-server and VBScript


Quote:

> [id(13), helpstring("method convert")] HRESULT convert([in] VARIANT in1,
> [out,retval] VARIANT* out1);

In VBScript or VB the [out,retval] attributes translate the second parameter
to a return values. In C++ you have to past the out1 as the second
parameter. The return value will be an HRESULT for which you can check
errors.


Fri, 29 Apr 2005 19:22:46 GMT  
 ATL-COM-server and VBScript
And where exactly is my bug after your opinion?


Quote:



> > [id(13), helpstring("method convert")] HRESULT convert([in] VARIANT in1,
> > [out,retval] VARIANT* out1);

> In VBScript or VB the [out,retval] attributes translate the second
parameter
> to a return values. In C++ you have to past the out1 as the second
> parameter. The return value will be an HRESULT for which you can check
> errors.



Fri, 29 Apr 2005 20:24:40 GMT  
 ATL-COM-server and VBScript
The last line of your code has this

varTbRes = m_ICServ->convert(varLong);

I said that [out,retval] translates to a return value for scripting client
and an out parameter for a C++ client so that the above line should be
something like

VARIANT varTbRes
::VariantInit(&varTbRes);
m_ICServ->convert(varLong,&varTbRes);

the return value will now be an HRESULT. you will find this out by looking
at definition

#define STDMETHODIMP HRESULT __stdcall

Now you can check for error like this

if(FAILED(m_ICServ->convert(varLong,&varTbRes)))
{
    //handle error

Quote:
}

else
{
    do something with varTbRes

Quote:
}



Quote:
> And where exactly is my bug after your opinion?





> > > [id(13), helpstring("method convert")] HRESULT convert([in] VARIANT
in1,
> > > [out,retval] VARIANT* out1);

> > In VBScript or VB the [out,retval] attributes translate the second
> parameter
> > to a return values. In C++ you have to past the out1 as the second
> > parameter. The return value will be an HRESULT for which you can check
> > errors.



Fri, 29 Apr 2005 21:34:27 GMT  
 ATL-COM-server and VBScript
I found out, in the C++ client
1) if I use #import ...  <server>.tlb, then it must looks like:  outpar =
m_ICServ.convert(in_par)
2) don't use #import: then it must look like hr = m_ICServ.convert(in_par,
&outpar)

But to return to my main problem, which is: the server code gets the correct
values from the input variant, if called from VBScript(ASP), but NOT if
called from C++.
For me the server-code looks correct, but there must be a bug in there.

Regards,
flemming

Quote:
> The last line of your code has this

> varTbRes = m_ICServ->convert(varLong);

> I said that [out,retval] translates to a return value for scripting client
> and an out parameter for a C++ client so that the above line should be
> something like

> VARIANT varTbRes
> ::VariantInit(&varTbRes);
> m_ICServ->convert(varLong,&varTbRes);

> the return value will now be an HRESULT. you will find this out by looking
> at definition

> #define STDMETHODIMP HRESULT __stdcall

> Now you can check for error like this

> if(FAILED(m_ICServ->convert(varLong,&varTbRes)))
> {
>     //handle error
> }
> else
> {
>     do something with varTbRes
> }



> > And where exactly is my bug after your opinion?





> > > > [id(13), helpstring("method convert")] HRESULT convert([in] VARIANT
> in1,
> > > > [out,retval] VARIANT* out1);

> > > In VBScript or VB the [out,retval] attributes translate the second
> > parameter
> > > to a return values. In C++ you have to past the out1 as the second
> > > parameter. The return value will be an HRESULT for which you can check
> > > errors.



Sat, 30 Apr 2005 14:16:27 GMT  
 ATL-COM-server and VBScript

Sorry I missed your point. From what you said it sounds
like the error is with the C++ client and not with the
server. I looked at your code for packing the variant
safearray and I think I found a problem. Here is a snippet
of my own code that is in production now. I can't remember
why I use an array of 1 for the safearray bounds. But
notice that when I assign the type I bitwise-OR VT_ARRAY
with the same type specifed in the SafeArrayCreate
function. I believe this is the problem. You are really
creating a variant that is a safearray of integer types.
If you wanted to create a variant safearray of variants
you would have to go through the whole variant init
process for each element of the array. Check my code,
since I'm at work I didn't look at the server code to
closely. The formatting will be off.

        //create safearray bounds
        SAFEARRAYBOUND saBounds[1];
        saBounds[0].lLbound = 0;
        saBounds[0].cElements = m_pbaData->GetSize();

        //initialize variant
        VARIANT vtData;
        ::VariantInit(&vtData);
        vtData.vt = VT_ARRAY | VT_UI1;
        vtData.parray = ::SafeArrayCreate(VT_UI1,
1,saBounds);

        //initialize safearray with m_pbaData
        BYTE *pData;
        ::SafeArrayAccessData(vtData.parray, (void **)
&pData);
        ::memcpy(pData,m_pbaData->GetData(),m_pbaData-

Quote:
>GetSize());

        ::SafeArrayUnaccessData(vtData.parray);


Sat, 30 Apr 2005 20:15:44 GMT  
 ATL-COM-server and VBScript

Quote:
> SAFEARRAY *psaLongs = SafeArrayCreate(VT_I4, 1, &safebound);
> VariantInit(varLong);
> varLong->vt       = VT_ARRAY| VT_VARIANT;
> varLong->parray = psaLongs;

You have created an array of integers, but you lie to your server by
specifying in the VARIANT that it is an array of variants. Should be

varLong->vt       = VT_ARRAY| VT_I4;

--
With best wishes,
    Igor Tandetnik

"For every complex problem, there is a solution that is simple, neat,
and wrong." H.L. Mencken



Sat, 30 Apr 2005 22:31:40 GMT  
 ATL-COM-server and VBScript

Quote:

> I found out, in the C++ client
> 1) if I use #import ...  <server>.tlb, then it must looks like:  outpar =
> m_ICServ.convert(in_par)
> 2) don't use #import: then it must look like hr = m_ICServ.convert(in_par,
> &outpar)

> But to return to my main problem, which is: the server code gets the correct
> values from the input variant, if called from VBScript(ASP), but NOT if
> called from C++.
> For me the server-code looks correct, but there must be a bug in there.

> Regards,
> flemming

You should create array of VARIANT.
//Vi2 -- SAFEARRAY *psaLongs = SafeArrayCreate(VT_I4, 1, &safebound);
SAFEARRAY *psaLongs = SafeArrayCreate(VT_VARIANT, 1, &safebound);

PS
Also this is invalid comparison with VT_VARIANT. VT_VARIANT is not
binary value unlike VT_BYREF or VT_ARRAY.
        if ((in1.vt & VT_VARIANT) && (in1.vt & VT_BYREF))
                ...

        if ((in1.vt & VT_VARIANT) == VT_VARIANT && (in1.vt & VT_BYREF))

or

        if ((in1.vt & VT_TYPEMASK) == VT_VARIANT && (in1.vt & VT_BYREF))



Sat, 30 Apr 2005 22:55:51 GMT  
 ATL-COM-server and VBScript
I have worked with your answers - thanks - , and Igor ,you are right  (have
corrected it) and Vi2 and Ayoub don't agree about the first parameter to
SafeArrayCreate, so I changed the client to (

      VARIANT* parrPar        = NULL;

      parrPar                 = new VARIANT[1];

      VariantInit(parrPar);

      parrPar->vt             = VT_ARRAY|VT_VARIANT;

      SAFEARRAY* psa_Par;

      SAFEARRAYBOUND tagBound[1];

      tagBound[0].lLbound     = 0;

      tagBound[0].cElements   = 1;

      psa_Par = SafeArrayCreate(VT_VARIANT,1,tagBound);

      long lngIndices[1];

      VARIANT varInput;

      VariantInit(&varInput);

      varInput.vt             =  VT_I4;

      lngIndices[0]           = 0;

      SafeArrayPutElement(psa_Par, lngIndices, &varInput);

      parrPar->parray         = psa_Par;

      VARIANT varRes;

      varRes = m_ICServ->resval(parrPar);    // IDL: [in] VARIANT,
[out,retval] VARIANT*

and when I see it in the server, the upperbound is 0, but should be 1, which
means, I don't get the data correct to the server. The received ".vt" is
8204, which I also receive, when called from a client written in ASP.

(using IDL with [in] LONG, [out,retval] LONG* I get corret running, but is
not all what I need)

???

flemming


Quote:


> > SAFEARRAY *psaLongs = SafeArrayCreate(VT_I4, 1, &safebound);
> > VariantInit(varLong);
> > varLong->vt       = VT_ARRAY| VT_VARIANT;
> > varLong->parray = psaLongs;

> You have created an array of integers, but you lie to your server by
> specifying in the VARIANT that it is an array of variants. Should be

> varLong->vt       = VT_ARRAY| VT_I4;

> --
> With best wishes,
>     Igor Tandetnik

> "For every complex problem, there is a solution that is simple, neat,
> and wrong." H.L. Mencken



Sun, 01 May 2005 20:25:51 GMT  
 ATL-COM-server and VBScript

Quote:
>       SAFEARRAYBOUND tagBound[1];
>       tagBound[0].lLbound     = 0;
>       tagBound[0].cElements   = 1;

> and when I see it in the server, the upperbound is 0, but should be 1

No it shouldn't. You are confusing the upper bound with the number of
elements. A safearray with lower bound L and upper bound U has (U-L+1)
elements numbered L, L+1, ..., U-1, U. If L==U, an array has one
element.
--
With best wishes,
    Igor Tandetnik

"For every complex problem, there is a solution that is simple, neat,
and wrong." H.L. Mencken



Sun, 01 May 2005 23:17:25 GMT  
 ATL-COM-server and VBScript
Igor,

Sure you are right (sorry for the blunder), and the elements cross correct
to the server now.
So how acces the output in the client:

VARIANT varRes;
varRes = m_ICServ->resval(parrPar); // in the Server is the SAFEARRAY
created as seen in prev.mail
VARIANT *vv;
vv = new VARIANT[1];
VariantInit(vv);
SafeArrayAccessData(varRes.parray, (LPVOID*)&vv);

and here I would expect the resultvalues i vv[i].LVal (for longs). - but
it's not the case.

AFTER the servercall is the the pointer varRes.parray set to a value, which
gives me the impresseion that the SAFEARRAY is created, but cDim etc. looks
uninitialised. (but varRes.vt is correct set from server). By debugging the
server the safearray and variants seems correct, so I assume the call of the
method is somehow wrong.

Any ideas?

flemming


Quote:


> >       SAFEARRAYBOUND tagBound[1];
> >       tagBound[0].lLbound     = 0;
> >       tagBound[0].cElements   = 1;

> > and when I see it in the server, the upperbound is 0, but should be 1

> No it shouldn't. You are confusing the upper bound with the number of
> elements. A safearray with lower bound L and upper bound U has (U-L+1)
> elements numbered L, L+1, ..., U-1, U. If L==U, an array has one
> element.
> --
> With best wishes,
>     Igor Tandetnik

> "For every complex problem, there is a solution that is simple, neat,
> and wrong." H.L. Mencken



Mon, 02 May 2005 17:28:24 GMT  
 ATL-COM-server and VBScript
I have checked your previous posts, and it appears you have never shown
the code in resval(). I have seen your implementation of convert() which
seems to create an array of strings.

In any case, this produces a memory leak:

Quote:
> VARIANT *vv;
> vv = new VARIANT[1];
> VariantInit(vv);
> SafeArrayAccessData(varRes.parray, (LPVOID*)&vv);

SafeArrayAccessData takes a pointer to a pointer, and makes vv point to
its internal data buffer. Any previous value of vv is lost. Make it

VARIANT *vv;
SafeArrayAccessData(varRes.parray, (LPVOID*)&vv);

--
With best wishes,
    Igor Tandetnik

"For every complex problem, there is a solution that is simple, neat,
and wrong." H.L. Mencken


Quote:
> Igor,

> Sure you are right (sorry for the blunder), and the elements cross
correct
> to the server now.
> So how acces the output in the client:

> VARIANT varRes;
> varRes = m_ICServ->resval(parrPar); // in the Server is the SAFEARRAY
> created as seen in prev.mail
> VARIANT *vv;
> vv = new VARIANT[1];
> VariantInit(vv);
> SafeArrayAccessData(varRes.parray, (LPVOID*)&vv);

> and here I would expect the resultvalues i vv[i].LVal (for longs). -
but
> it's not the case.

> AFTER the servercall is the the pointer varRes.parray set to a value,
which
> gives me the impresseion that the SAFEARRAY is created, but cDim etc.
looks
> uninitialised. (but varRes.vt is correct set from server). By
debugging the
> server the safearray and variants seems correct, so I assume the call
of the
> method is somehow wrong.



Mon, 02 May 2005 23:06:03 GMT  
 ATL-COM-server and VBScript
The server routinesI have are basically the same, dependent on the datatypes
as input (long-arrays,BSTR-arrays) I create a new server-name, and it looks:

STDMETHODIMP CCServ::resval(VARIANT in1, VARIANT* out1)
{
 HRESULT hr;
 SAFEARRAY* InputArray;
 VARIANT* InputVariant;
 if ((in1.vt & VT_VARIANT) && (in1.vt & VT_BYREF))
  InputVariant = in1.pvarVal;
 else
  InputVariant = & in1;

 if ((! ( InputVariant->vt & VT_ARRAY)) || (! ( InputVariant->vt
&VT_VARIANT)))
  return Error("Expecting an array of variants");

 if (InputVariant->vt & VT_BYREF)
  hr = SafeArrayCopy(*(InputVariant->pparray), &InputArray);
 else
  hr = SafeArrayCopy(InputVariant->parray, &InputArray);

 long lbound, ubound;
 SafeArrayGetLBound(InputArray, 1, &lbound);
 SafeArrayGetUBound(InputArray, 1, &ubound);

 VariantInit(out1);
 out1->vt = VT_ARRAY | VT_VARIANT;
 out1->parray = SafeArrayCreate(VT_VARIANT, 1, InputArray->rgsabound);

 VARIANT * InputElements, * OutputElements;
 SafeArrayAccessData(InputArray, (LPVOID*)&InputElements);
 SafeArrayAccessData(out1->parray, (LPVOID*)&OutputElements);

 for(long i=lbound; i <= ubound; i++)
 {
  VARIANT Hold; // unused
  VariantInit(& Hold); // have kept it from the BSTR-case,where I do
VaraiantChangeType to process further
  long b = InputElements[i].lVal;
  b++;
  VariantInit(& OutputElements[i]);
  OutputElements[i].vt = VT_I4;
  OutputElements[i].lVal = b;
  VariantClear(& Hold);
 }
 SafeArrayUnaccessData(out1->parray);
 return S_OK;

Quote:
}

By debugging I see the for-loop is processed, and out1 structure has correct
safearray data (cElements, rgsbound etc).

Flemming


Quote:
> I have checked your previous posts, and it appears you have never shown
> the code in resval(). I have seen your implementation of convert() which
> seems to create an array of strings.

> In any case, this produces a memory leak:

> > VARIANT *vv;
> > vv = new VARIANT[1];
> > VariantInit(vv);
> > SafeArrayAccessData(varRes.parray, (LPVOID*)&vv);

> SafeArrayAccessData takes a pointer to a pointer, and makes vv point to
> its internal data buffer. Any previous value of vv is lost. Make it

> VARIANT *vv;
> SafeArrayAccessData(varRes.parray, (LPVOID*)&vv);

> --
> With best wishes,
>     Igor Tandetnik

> "For every complex problem, there is a solution that is simple, neat,
> and wrong." H.L. Mencken



> > Igor,

> > Sure you are right (sorry for the blunder), and the elements cross
> correct
> > to the server now.
> > So how acces the output in the client:

> > VARIANT varRes;
> > varRes = m_ICServ->resval(parrPar); // in the Server is the SAFEARRAY
> > created as seen in prev.mail
> > VARIANT *vv;
> > vv = new VARIANT[1];
> > VariantInit(vv);
> > SafeArrayAccessData(varRes.parray, (LPVOID*)&vv);

> > and here I would expect the resultvalues i vv[i].LVal (for longs). -
> but
> > it's not the case.

> > AFTER the servercall is the the pointer varRes.parray set to a value,
> which
> > gives me the impresseion that the SAFEARRAY is created, but cDim etc.
> looks
> > uninitialised. (but varRes.vt is correct set from server). By
> debugging the
> > server the safearray and variants seems correct, so I assume the call
> of the
> > method is somehow wrong.



Tue, 03 May 2005 14:59:13 GMT  
 ATL-COM-server and VBScript

Quote:
> The server routinesI have are basically the same, dependent on the
datatypes
> as input (long-arrays,BSTR-arrays) I create a new server-name, and it
looks:

> STDMETHODIMP CCServ::resval(VARIANT in1, VARIANT* out1)
> {
>  HRESULT hr;
>  SAFEARRAY* InputArray;
>  VARIANT* InputVariant;
>  if ((in1.vt & VT_VARIANT) && (in1.vt & VT_BYREF))

This is an incorrect way to test the type. VT_VARIANT is not a flag,
VT_BYREF is. I recommend

if (V_VT(&int1) == (VT_VARIANT | VT_BYREF) )
{...}

Quote:
>   InputVariant = in1.pvarVal;
>  else
>   InputVariant = & in1;

>  if ((! ( InputVariant->vt & VT_ARRAY)) || (! ( InputVariant->vt
> &VT_VARIANT)))

Same thing here:

if ( (V_VT(InputVariant) & VT_TYPEMASK) != VT_VARIANT ||
!V_ISARRAY(InputVariant) )
{...}

Quote:
>   return Error("Expecting an array of variants");

>  if (InputVariant->vt & VT_BYREF)

if ( V_ISBYREF(InputVariant) )

Quote:
>   hr = SafeArrayCopy(*(InputVariant->pparray), &InputArray);
>  else
>   hr = SafeArrayCopy(InputVariant->parray, &InputArray);

>  long lbound, ubound;
>  SafeArrayGetLBound(InputArray, 1, &lbound);
>  SafeArrayGetUBound(InputArray, 1, &ubound);

>  VariantInit(out1);
>  out1->vt = VT_ARRAY | VT_VARIANT;
>  out1->parray = SafeArrayCreate(VT_VARIANT, 1, InputArray->rgsabound);

>  VARIANT * InputElements, * OutputElements;
>  SafeArrayAccessData(InputArray, (LPVOID*)&InputElements);
>  SafeArrayAccessData(out1->parray, (LPVOID*)&OutputElements);

>  for(long i=lbound; i <= ubound; i++)

That's wrong. With SafeArrayAccessData, you get the pointer to the raw
data buffer inside safearray. From that point on, normal C++ rules kick
in. The loop should be

for (long i = 0; i <= ubound-lbound; ++i)

You only get away with it because you create your arrays with lbound==0.

Quote:
>  {
>   VARIANT Hold; // unused
>   VariantInit(& Hold); // have kept it from the BSTR-case,where I do
> VaraiantChangeType to process further
>   long b = InputElements[i].lVal;

Are you sure that input variants are all of type VT_I4?

Quote:
>   b++;
>   VariantInit(& OutputElements[i]);
>   OutputElements[i].vt = VT_I4;
>   OutputElements[i].lVal = b;
>   VariantClear(& Hold);
>  }
>  SafeArrayUnaccessData(out1->parray);

You missed SafeArrayUnaccessData(InputArray). You call
SafeArrayAccessData twice, so you should call SafeArrayUnaccessData
twice. Also, SafeArrayCopy creates a copy of the original array. You
never destroy it, thus you have a leak.

Quote:
>  return S_OK;
> }

> By debugging I see the for-loop is processed, and out1 structure has
correct
> safearray data (cElements, rgsbound etc).

So, what does the client see? How exactly is the data wrong?
--
With best wishes,
    Igor Tandetnik

"For every complex problem, there is a solution that is simple, neat,
and wrong." H.L. Mencken



Tue, 03 May 2005 23:31:14 GMT  
 ATL-COM-server and VBScript
Igor,

I changed as proposed in the server:
a) the three "if-statements"
b) the for-statement(the bounds)
c) added the Unaccess for the input.
(For testing I know in the server that it gets VT_I4 - all simplification is
done to locate the problem)

In the serverpart I presume I setup the output-safearray and its structure.

I verified the server againt my ASP-client, and all worked still correct.
So on to the client:

 VARIANT* parrPar  = NULL;
 parrPar    = new VARIANT[1];
 VariantInit(parrPar);
 parrPar->vt   = VT_ARRAY|VT_VARIANT;
 SAFEARRAY* psa_Par;
 SAFEARRAYBOUND tagBound[1];
 tagBound[0].lLbound  = 0;
 tagBound[0].cElements  = 1;
 psa_Par = SafeArrayCreate(VT_VARIANT,1,tagBound);

 long lngIndices[1];
 VARIANT varInput;
 VariantInit(&varInput);
 varInput.vt  = VT_I4;
 varInput.lVal  = 27;
 lngIndices[0]  = 0;
 SafeArrayPutElement(psa_Par, lngIndices, &varInput);
 parrPar->parray  = psa_Par;
 VARIANT varRes;
 VariantInit(&varRes);

 varRes = m_ICServ->resval(parrPar);
VARIANT* vv1;
 SafeArrayAccessData(varRes.parray,(LPVOID*)&vv1);
 long a = varRes.vt;
 long b = vv1[0].lVal;

When I look at "varRes.parray" after the call:
1)varRes.vt is 8204(saying the variant-array is setup?)
2)varRes.parray has cDims 65262 and the rgsbound has also undefined stuff
3) the vv1 is not accessible in the de{*filter*}.(Expression cannot be
evaluated)
and I would expect the result in the vaiable b, but the client crashes
here.???

Any ideas?
Flemming


Quote:


> > The server routinesI have are basically the same, dependent on the
> datatypes
> > as input (long-arrays,BSTR-arrays) I create a new server-name, and it
> looks:

> > STDMETHODIMP CCServ::resval(VARIANT in1, VARIANT* out1)
> > {
> >  HRESULT hr;
> >  SAFEARRAY* InputArray;
> >  VARIANT* InputVariant;
> >  if ((in1.vt & VT_VARIANT) && (in1.vt & VT_BYREF))

> This is an incorrect way to test the type. VT_VARIANT is not a flag,
> VT_BYREF is. I recommend

> if (V_VT(&int1) == (VT_VARIANT | VT_BYREF) )
> {...}

> >   InputVariant = in1.pvarVal;
> >  else
> >   InputVariant = & in1;

> >  if ((! ( InputVariant->vt & VT_ARRAY)) || (! ( InputVariant->vt
> > &VT_VARIANT)))

> Same thing here:

> if ( (V_VT(InputVariant) & VT_TYPEMASK) != VT_VARIANT ||
> !V_ISARRAY(InputVariant) )
> {...}

> >   return Error("Expecting an array of variants");

> >  if (InputVariant->vt & VT_BYREF)

> if ( V_ISBYREF(InputVariant) )

> >   hr = SafeArrayCopy(*(InputVariant->pparray), &InputArray);
> >  else
> >   hr = SafeArrayCopy(InputVariant->parray, &InputArray);

> >  long lbound, ubound;
> >  SafeArrayGetLBound(InputArray, 1, &lbound);
> >  SafeArrayGetUBound(InputArray, 1, &ubound);

> >  VariantInit(out1);
> >  out1->vt = VT_ARRAY | VT_VARIANT;
> >  out1->parray = SafeArrayCreate(VT_VARIANT, 1, InputArray->rgsabound);

> >  VARIANT * InputElements, * OutputElements;
> >  SafeArrayAccessData(InputArray, (LPVOID*)&InputElements);
> >  SafeArrayAccessData(out1->parray, (LPVOID*)&OutputElements);

> >  for(long i=lbound; i <= ubound; i++)

> That's wrong. With SafeArrayAccessData, you get the pointer to the raw
> data buffer inside safearray. From that point on, normal C++ rules kick
> in. The loop should be

> for (long i = 0; i <= ubound-lbound; ++i)

> You only get away with it because you create your arrays with lbound==0.

> >  {
> >   VARIANT Hold; // unused
> >   VariantInit(& Hold); // have kept it from the BSTR-case,where I do
> > VaraiantChangeType to process further
> >   long b = InputElements[i].lVal;

> Are you sure that input variants are all of type VT_I4?

> >   b++;
> >   VariantInit(& OutputElements[i]);
> >   OutputElements[i].vt = VT_I4;
> >   OutputElements[i].lVal = b;
> >   VariantClear(& Hold);
> >  }
> >  SafeArrayUnaccessData(out1->parray);

> You missed SafeArrayUnaccessData(InputArray). You call
> SafeArrayAccessData twice, so you should call SafeArrayUnaccessData
> twice. Also, SafeArrayCopy creates a copy of the original array. You
> never destroy it, thus you have a leak.

> >  return S_OK;
> > }

> > By debugging I see the for-loop is processed, and out1 structure has
> correct
> > safearray data (cElements, rgsbound etc).

> So, what does the client see? How exactly is the data wrong?
> --
> With best wishes,
>     Igor Tandetnik

> "For every complex problem, there is a solution that is simple, neat,
> and wrong." H.L. Mencken



Fri, 06 May 2005 16:56:58 GMT  
 
 [ 20 post ]  Go to page: [1] [2]

 Relevant Pages 

1. Using ATL Active Server Components in VBScript??

2. Accessing COM server from IE 3.02 and VBScript

3. ATL COM - Passing ATL COM classes through another ATL COM class in the same app

4. Passing array from ATL COM to VBScript client

5. ATL COM Component firing events into VBScript event sink

6. Use script control to run VBScript in ATL/COM

7. Lifetime of EXE COM server that uses DLL COM server

8. ATL7 breaks CWindowImpl/Postmessage for old COM ATL servers

9. ATL server and persistent COM objects

10. Byte Array returned from ATL COM Server to VB app

11. How to use com server in an ATL?

12. Passing a structure between a VB client and an ATL com server

 

 
Powered by phpBB® Forum Software