Re: Confused about ATL and SafeArrays

From: Richard Dixson (please_at_replyhereonly.com)
Date: 03/03/04


Date: Wed, 3 Mar 2004 18:00:07 -0500

Your sample code was a tremendous help!

However I am seeing some very odd behavior I was hoping you could clear
up.

Here is what I am doing, followed by some specific questions...

I put together a test method using your sample method, IDL, and .h
entries from the previous post in this thread. This compiled just fine.

However from ASP I would get a vbscript "type mismatch" error when
trying to call the CheckNames method.

My ASP code looks like this:
 <%
   set obj = Server.CreateObject("my.object")
   dim name(4)
   name(0) = "This"
   name(1) = "is"
   name(2) = "a"
   name(3) = "test!"
   result = obj.CheckNames(name)
 %>
 <html>done</html>

The type mismatch always occurs on the line "result =
obj.CheckNames(name)".

So then I tried replacing that line with:
  result = obj.CheckNames(Array("This", "is", "a", "test!"))

And still got the type mismatch error.

Then I changed the IDL definition from:
  [id(1), HRESULT CheckNames([in] SAFEARRAY(BSTR) *Names, [out,retval]
SAFEARRAY(VARIANT_BOOL) *Results);

to
  [id(1), HRESULT CheckNames([in] SAFEARRAY(VARIANT) *Names,
[out,retval] SAFEARRAY(VARIANT_BOOL) *Results);

and changing it from BSTR to VARIANT made a slight difference. With it
set to VARIANT instead of BSTR it WOULD now call the CheckNames method
without the type mismatch error when I used this line from ASP:
  result = obj.CheckNames(Array("This", "is", "a", "test!"))

However when I try to use:
   result = obj.CheckNames(name)
it STILL gives me the type mismatch error (with it set to VARIANT in the
IDL, the Array function works to call the method but passing in the name
array does not). As a side note, If I do IsArray(name) it does return
true.

First two questions:

Question 1: Why am I not able to use SAFEARRAY(BSTR) in the IDL to get
the name array from an ASP page?

Question 2: Why does changing it from SAFEARRAY(BSTR) to
SAFEARRAY(VARIANT) then let me call it using the Array function, but
still not pass it in as an array (i.e. CheckNames(name))? Am I
declaring things wrong from ASP or have things set up wrong in my C++
code?

Ok, now it gets even more odd... In stepping through the code when I do
call it with CheckNames(Array("x","y", "etc")) the index into the
SAFEARRAY is all messed up. Consider for example this line from your
sample:
   if( 'A' <= *pNamesdata[i] && *pNamesdata[i] <= 'L' )

I expect that pNamesdata[0] is the first element in the safe array,
pNamesdata[1] is the second, and so on. HOWEVER I've found that the
first element is actually at position 2, and each element is then 4
positions higher.

For example when I call this method with:
  result = obj.CheckNames(Array("This", "is", "a", "test!"))
it turns out that pNamesdata has values as follows:
  pNamesdata[0] = ""
  pNamesdata[1] = ""
  pNamesdata[2] = "This"
  pNamesdata[3] = ""
  pNamesdata[4] = ""
  pNamesdata[5] = ""
  pNamesdata[6] = "is"
  pNamesdata[7] = ""
  pNamesdata[8] = ""
  pNamesdata[9] = ""
  pNamesdata[10] = "a"
  pNamesdata[11] = ""
  pNamesdata[12] = ""
  pNamesdata[13] = ""
  pNamesdata[14] = "test!"

So that this brings me to question 3: What is the heck is going on with
that ordering???

This is very bizarre and confusing. I really hope someone out there can
clarify what is going on and tell me how to correct this.

P.S. I also tried calling CheckNames from a VB sample just to make sure
it wasn't a problem specific to ASP. The results were very similar in
that the array passed in was being read with pNamesdata[x] shown as
above. The only difference with VB was that it would let me pass in the
array by name, unlike ASP that seems to want to call the method only
when using the Array function to create the array. Very, very strange.

P.S.S. Just dawned on me - perhaps this "skip by 4 positions with
pNamesdata[x] is related to using a VARIANT, whereas your sample was
designed to use an array of BSTRs? If so then how can I pass in arrays
from ASP with the IDL defined as SAFEARRAY(BSTR) since it won't let me
due to type mismatch errors?

Any suggestions? Thanks a ton in advance!!

For reference, here is my IDL, .h and full sample method I am using:

[id(1), HRESULT CheckNames([in] SAFEARRAY(VARIANT) *Names, [out,retval]
SAFEARRAY(VARIANT_BOOL) *Results);

STDMETHOD(CheckNames)(/*[in]*/ SAFEARRAY* *Names, /*[out,retval]*/
SAFEARRAY* *Results);

STDMETHODIMP CBrowserObj::CheckNames(SAFEARRAY* *Names, SAFEARRAY*
*Results)
{

HRESULT hr;
VARTYPE vt;
SafeArrayGetVartype( *Names, & vt );

if( vt != VT_VARIANT )
{
 hr = E_INVALIDARG;
}
else
{
 CComBSTR * pNamesdata = NULL;
 hr = ::SafeArrayAccessData( *Names, (void**)&pNamesdata );
 if( SUCCEEDED(hr) )
 {
  UINT nDim = SafeArrayGetDim( *Names ); // Number of
dimensions
  CComBSTR ans;

  SAFEARRAYBOUND* psabound = new SAFEARRAYBOUND[nDim];
  if( psabound == NULL )
  {
   hr = E_OUTOFMEMORY;
  }
  else
  {
   int totalSize = 1;
   int i = 1;
   SafeArrayGetLBound( *Names, i, &
psabound[0].lLbound );
   LONG lUbound;
   SafeArrayGetUBound( *Names, i, & lUbound );
   psabound[0].cElements = lUbound -
psabound[0].lLbound + 1;
   *Results = SafeArrayCreate( VT_BOOL, nDim,
psabound );
   if( *Results == NULL )
   {
    hr = E_OUTOFMEMORY;
   }
   else
   {
    VARIANT_BOOL * pResultsdata = NULL;
    hr = ::SafeArrayAccessData( *Results,
(void**)&pResultsdata );
    if( SUCCEEDED(hr) )
    {
     for(int i = 0; i < totalSize; i++)
     {
      if( 'A' <= *pNamesdata[i] && *pNamesdata[i]
<= 'L' )
    pResultsdata[i] = VARIANT_TRUE;
      else
    pResultsdata[i] = VARIANT_FALSE;
     }
     SafeArrayUnaccessData( *Results );
    }
    SafeArrayUnaccessData( *Names );
   }
      }
  }
 }

return hr;
}

<eom>



Relevant Pages

  • Calling a COM+ component over ASP
    ... I try to call the component over ASP. ... I've got a array in the parameters of the COM+ method. ... string boType, string userName, bool storeDocument, stringparameters) ... Ich benutze JavaScript auf der ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Is this a good idea?
    ... I've been programming ASP for 5 years and am now learning PHP. ... it's handy as you can directly access any data in the array ... There are times when it's better to dump a table into an array - like when you have a lot of processing to do on multiple items and want to release mysql resources. ...
    (comp.lang.php)
  • Re: How do I store an array of data between pages?
    ... I'm building an ASP page which allows uses to add items to an invoice ... : an array of records. ... This will submit the data to an ASP script to be validated. ... without even the implied warranty of merchantability ...
    (microsoft.public.inetserver.asp.general)
  • Re: Passing Array From ASP to C#
    ... > Could someone please post how to pass an array from ASP ... > I have this code in ASP: ... > Dim arrBefore ... > obj.MyMethod arrBefore, arrAfter, lngId ...
    (microsoft.public.dotnet.framework.interop)
  • confused about image colorspaces
    ... I'd like to write a small applet to display astronomical images. ... customary in astronomy, for us an image is an array imgof real ... a lookup table (LUT) of R G B values (the LUT is also chosen by the ... As example this is the equivalent IDL codes (the Java R G B values will ...
    (comp.lang.java.programmer)

Quantcast