VC本身不支持这种参数传递,怎么还要传递到VC中去?

解决方案 »

  1.   

    to ha1101:SAFEARRAY我试了很多,但不知道究竟该怎样定义和操作,有没有例子代码看看啊?MSDN里面找出来的我都试不出来,不知道是怎么回事。
    to glcs:有没有具体方法可参考?
      

  2.   

    一个例子,用到了ParamArray:
    http://www.freevbcode.com/code/APIByName.zip
      

  3.   

    ================================
    7:  Passing and Returning Arrays
    ================================When  an  array  is  passed  to a DLL function, Visual Basic actually 
    passes  a  pointer  to  a  pointer  to a  SAFEARRAY  structure, or an 
    LPSAFEARRAY FAR *. SafeArrays  are  structures  that  are used in OLE 
    2.0. Visual Basic 4.0 uses SafeArrays internally to store arrays. SafeArrays  contain  information  about the  number of dimensions and 
    their bounds. The  data  referred by an array descriptor is stored in
    column-major  order  (i.e.  the  leftmost  dimension  changes first), 
    which  is the  same  scheme  used by Visual Basic, but different than 
    that  used   by  PASCAL  or  C. The  subscripts  for  SafeArrays  are 
    zero-based.The OLE 2.0  APIs can be used to access and manipulate the array. The 
    following table lists the Visual Basic APIs used to reference arrays, 
    and the OLE 2.0 equivalents.Visual Basic API OLE API
    -------------------------------------------------------------
    VBArrayBounds SafeArrayGetLBound/SafeArrayGetUBound
    VBArrayElement SafeArrayGetElement
    VBArrayElemSize SafeArrayGetElemsize
    VBArrayFirstElem N/A
    VBArrayIndexCount SafeArrayGetDimThe OLE API function SafeArrayGetDim returns the number of dimensions 
    in   the   array,   and   the   functions    SafeArrayGetLBound   and 
    SafeArrayGetUBound  return  the  lower  and  upper bounds for a given 
    array  dimension. All of  these functions require a parameter of type 
    LPSAFEARRAY, in order to describe the target array.The first function in this example shows how to get the dimension and 
    bound information of a Visual Basic array (of strings) that is passed 
    to a  DLL. It  also  creates  a new  array, copies  an element of the 
    passed  in array  into the  corresponding  index  location in the new 
    array. It  then  modifies  the  string  element  at  this  same index 
    location  in the original passed in array (which is reflected back in 
    VB). Finally  it  stores  the new  array in a Variant and returns the 
    same to VB. The  second  function  is a  shorter version  of the first one. It is 
    slightly different, in that all the elements from the passed-in array 
    are  copied into the new array automatically. In both cases, however, 
    for  string  arrays  in the  32-bit  version of VB4, you should first 
    convert the string to Unicode. This is required because, VB4 (32-bit) 
    uses Unicode to store strings internally, however it converts them to 
    ANSI  on  the  way  in to a  DLL. It will normally convert it back to 
    Unicode  on the way  out of  the DLL; but  since  the string is being 
    copied into an array that has been *NEWLY CREATED INSIDE THE DLL*, VB
    will not know enough to do the conversion. This is not required  when
    compiling the DLL for 16-bits because, the 16-bit version of VB4 uses
    ANSI strings internally.This  example  demonstrates  passing and returning arrays of strings. 
    But  it can  easily  be  modified to work for arrays of any permitted 
    datatype. The  only  modifications  that have to be made are changing 
    the Declare statements and the VT_XXXX flags to match the appropriate 
    type.  And  of  course,  you  don't  have   to  worry  about  Unicode 
    conversions when dealing with non-string data-types.
    16\32-Bit Example
    -----------------#include <windows.h>
    #include <ole2.h>
    #include <stdio.h>#ifdef _WIN32 
      #define CCONV _stdcall
      #define NOMANGLE
    #else
      #define CCONV FAR PASCAL _export
      #define NOMANGLE EXTERN_C
      #include <stdlib.h>
      #include <compobj.h>    
      #include <dispatch.h> 
      #include <variant.h>
      #include <olenls.h>  
    #endif// hold the SAFEARRAY pointer to be returned in a Variant
    LPSAFEARRAY lpsa1;
    LPSAFEARRAY lpsa2;NOMANGLE VARIANT CCONV ProcessArray(LPSAFEARRAY FAR *ppsa)
    {
    VARIANT vnt;
    unsigned int i, cdims;
    char buff[40];
    long rgIndices[] = {0,1,2};
    BSTR element = NULL; cdims = SafeArrayGetDim(*ppsa); // Must initialize variant first
    VariantInit(&vnt);         // Create an array descriptor
    if (SafeArrayAllocDescriptor (cdims, &lpsa1) != S_OK)
    {
        MessageBox (NULL, "Can't create array descriptor. \n
    Will return an empty variant", "Error!", MB_OK);
        lpsa1 = NULL;
    } // Specify the size and type of array elements
    if (lpsa1)
    {
        lpsa1->cbElements = sizeof(BSTR);
        lpsa1->fFeatures = FADF_BSTR;
    } // Get the bound info for passed in array, display it and
    // store the same in the array to be returned in a variant
    for (i=1; i <= cdims; i++)
    {
        long Lbound, Ubound;     SafeArrayGetLBound (*ppsa, i, &Lbound);
        SafeArrayGetUBound (*ppsa, i, &Ubound);

        if (lpsa1)
        {
    lpsa1->rgsabound[cdims-i].cElements= Ubound-Lbound+1;
    lpsa1->rgsabound[cdims-i].lLbound = Lbound;
        }       sprintf (buff, "Index %d: Lbound = %li, Ubound = %li\n",
         i, Lbound, Ubound);
        MessageBox (NULL, buff, "SafeArrayInfo from DLL", MB_OK);
    }
       
    if (!lpsa1)
        return vnt; // Allocate space for the actual array elements
    if (SafeArrayAllocData (lpsa1) != S_OK)
    {
        MessageBox (NULL, "can't create array elements","Error!", 
    MB_OK);
        return vnt;
    } // Get the value of the string element at (0,1,2). This will
    // be an ANSI string.
    SafeArrayGetElement (*ppsa, rgIndices, &element); #ifdef _WIN32
        // Convert this to Unicode, as VB4 (32-bit) will not do
        // so for you, as the string is inside an array *NEWLY
        // CREATED* inside the DLL!
        unsigned int length = SysStringByteLen(element);
        BSTR wcElement = NULL;

        wcElement = SysAllocStringLen(NULL, length*2);
        MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,(LPCSTR)element 
    , -1, (LPWSTR)wcElement, length*2);     // Put this Unicode string into the corresponding
        // location in the array to be returned in a variant
        lpsa1->fFeatures ^= FADF_BSTR;
        SafeArrayPutElement (lpsa1, rgIndices, &wcElement); 
        lpsa1->fFeatures |= FADF_BSTR;
    #else
        // Put the (ANSI) string back into the corresponding
        // location in the array to be returned
        SafeArrayPutElement (lpsa1, rgIndices, element); 
    #endif SysFreeString (element);
    element = SysAllocString((BSTR)"Good Bye"); // Modify the same element (0,1,2) of the passed-in array
    SafeArrayPutElement (*ppsa, rgIndices, element);
    SysFreeString (element); // store the array to be returned in a variant
    vnt.vt = VT_ARRAY|VT_BYREF|VT_BSTR;
    vnt.pparray = &lpsa1;    return vnt;
    }NOMANGLE VARIANT CCONV CopyArray(LPSAFEARRAY FAR *ppsa)
    {
    VARIANT vnt;
    BSTR element = NULL;
    long rgIndices[] = {0,1,2}; // Must initialize variant first
    VariantInit(&vnt);         // copy the passed-in array to the array to be returned in
    // variant
    SafeArrayCopy (*ppsa, &lpsa2);

    // Get the value of the string element at (0,1,2). This will
    // be an ANSI string.
    SafeArrayGetElement (lpsa2, rgIndices, &element); #ifdef _WIN32
        // Convert this to Unicode, as VB4 (32-bit) will not do
        // so for you, as the string is inside an array *NEWLY
        // CREATED* inside the DLL!
        unsigned int length = SysStringByteLen(element);
        BSTR wcElement = NULL;

        wcElement = SysAllocStringLen(NULL, length*2);
             MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,(LPCSTR)element
    , -1, (LPWSTR)wcElement, length*2);     // Put this Unicode string back into the corresponding
        // location in the array to be returned
        SafeArrayPutElement (lpsa2, rgIndices, wcElement); 
        SysFreeString (wcElement);
    #else
        // Put the (ANSI) string back into the corresponding
        // location in the array to be returned
        SafeArrayPutElement (lpsa2, rgIndices, element); 
    #endif SysFreeString (element);
    element = SysAllocString((BSTR)"Hello Again!"); // Modify the same element (0,1,2) of the passed-in array
    SafeArrayPutElement (*ppsa, rgIndices, element);
    SysFreeString (element); // store the array to be returned in a variant
    vnt.vt = VT_ARRAY|VT_BYREF|VT_BSTR;
    vnt.pparray = &lpsa2;    return vnt;
    }
    The following Visual Basic code calls the above two array functions:
    #If Win32 Then    Private Declare Function ProcessArray Lib "vb4dll32.dll"(a() As _ 
    String) As Variant
        Private Declare Function CopyArray Lib "vb4dll32.dll" (a() As _
    String) As Variant#Else    Private Declare Function ProcessArray Lib "vb4dll16.dll"(a() As _ 
    String) As Variant
        Private Declare Function CopyArray Lib "vb4dll16.dll" (a() As _
    String) As Variant#End If
    Private Sub ArrayTest()    Dim a(4, 5, 6) As String
        Dim v1 As Variant
        Dim v2 As Variant    a(0, 1, 2) = "Hello!"    Print VarType(v1)
        v1 = ProcessArray(a())
        Print VarType(v1)    MsgBox v1(0, 1, 2), vbInformation, "Element Value of Array _
       Returned In Variant - 1"
        MsgBox a(0, 1, 2), vbInformation, "Modified Element Value of _
       Passed-in Array - 1"    v2 = CopyArray(a())
        Print VarType(v2)    MsgBox v2(0, 1, 2), vbInformation, "Element Value of Array _
       Returned In Variant - 2"
        MsgBox a(0, 1, 2), vbInformation, "Modified Element Value of _
       Passed-in Array - 2 "End Sub