• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 276
  • Last Modified:

Can't Pass Structure from VBA to C COM DLL

I am trying to pass data from VBA to a C COM DLL.  The data will consist of an arra structure
TO-EXPERTS-EXCHANGE.txt
0
richtelieu88
Asked:
richtelieu88
1 Solution
 
richtelieu88Author Commented:
Sorry, I must have pressed the wrong button before I was finished with my problem description.

Iam trying to pass data from VBA to a C COM DLL.  The data will consist of an array of structures.  In this case, the attached file indicates that the size of the array is 3 structure elements.

I have no difficulty passing arrays to/from VBA / C COM DLL, but passing structures is not intuitive to me.

The attached file contains my latest attempts.
0
 
evilrixSenior Software Engineer (Avast)Commented:
In general, the way you pass structures between two different languages is to marshal the members of the structure where there are type in one language that can be mapped to the other. In other words, you can't just send a structure across the API boundaries, you'll have to serialize it in some way. Since you are using COM you will need to map the member types of the structure to appropriate native COM types.
0
 
richtelieu88Author Commented:
evil, do you have a quick example of how to do this marshaling . . . based on the TXT file I attached
0
Cloud Class® Course: Certified Penetration Testing

This CPTE Certified Penetration Testing Engineer course covers everything you need to know about becoming a Certified Penetration Testing Engineer. Career Path: Professional roles include Ethical Hackers, Security Consultants, System Administrators, and Chief Security Officers.

 
sarabandeCommented:
granted that the structure has only c types and no pointers and granted that the c com dll is responsible for filling the data, you could spare the serializing from vba to native structure and only implement the deserializing, means, to get the data to vba from buffer.

you would find out the maximum size of the array at the c side and provide an empty byte buffer of same size at the vba side. the c side then could make an appropriate cast to that buffer and fill it. after return you would have to "deserialize" the buffer as evilrix has mentioned. you would "divide" the buffer to get the structure "records". then for each record you have to parse the members and fill an appropriate equivalent vba structure.  

the following article would give sample code how you could pass the buffer (or records) to the com dll:
http://vcfaq.mvps.org/com/4.htm

Sara
0
 
richtelieu88Author Commented:
Sarabande,  A lot of what you said went in one ear and out the other . . .. but I will review the HTM article.

I *think* what you're getting at is to have the Client and Server both agree on the number *bytes* that will be passed; the Client will pass that number of bytes in one big byte array and the Server will decode that array based on the number of bytes they've both agreed to. . . . . .am I close?  or still far away in understanding???
0
 
richtelieu88Author Commented:
Sarabande, that artical appears promising.  Let me experiment with it before I award points.
0
 
sarabandeCommented:
the Client will pass that number of bytes in one big byte array and the Server will decode that array based on the number of bytes they've both agreed to. . . . . .am I close?
it is even easier. the caller passes an already allocated byte buffer of a "known" maximum size by pointer to the c function and the c function makes a "cast" on that buffer to get a variable that is an array of structures:

#define MAX_RECORDS 10
....
int some_c_function(unsigned char * buffer, unsigned int sizbuffer)
{
      typedef struct tag_mystruct
      {
            long along;
            double adouble;
            char achararray[21];
            ...
       } MYSTRUCT,  *PMYSTRUCT;
       
       PMYSTRUCT  pMyArr = NULL;

       /* check that the passed size is the required size */
       assert(sizbuffer == (sizeof(MYSTRUCT) * MAX_RECORDS));
      
      /* cast the argument buffer */
       pMyArr = (PMYSTRUCT)buffer;   
       memset(pMyArr, 0, (sizeof(MYSTRUCT) * MAX_RECORDS);

      /* from here you could use pMyArr same as a variable MYSTRUCT myArr[MAX_RECORDS]; */

Open in new window


the buffer needs to be allocated by SysAlloc at the VB or by of use of IntPtr to a Byte array which you allocated by using an appropriate marshaling function. in any case the pointer must be valid in the c dll.

if the dll is a com dll which wants a SafeArray as argument, you have a lot of choices where the simplest probably is to pass the IntPtr to the byte array via SafeArray.

Sara
0
 
richtelieu88Author Commented:
Sarabande,

Well, I followed the instructions, to the letter of the "law", in that article you sent me "http://vcfaq.mvps.org/com/4.htm" and I get the following error in VBA at the line:

scd.SendStruct  st

(Error = "Compile Error:  ByRef argument type mismatch".)

The C COM DLL compiles just fine, but VBA complains.

There's got to be a straightforward, simple, way that works that allows passing a structure pointer FROM VBA TO C COM DLL.  It can't be that complicated.

I'll study the "int some_c_function(unsigned char * buffer . . ." code you sent.

But VBA (or VB) does not allow the "ByRef" in the caller, only in the Callee.  This is beginning to get frustrating.

I'll next study
0
 
richtelieu88Author Commented:
Sarabande,

I have implemented "int some_c_function()".  It compiles just fine in the C COM DLL.

When I call this in VBA:

scd.GenericStruct  2,1

I get this error message:

"Function or interface marked as restricted, or the function uses an Automation type not supported in Visual Basic".

Does anyone have any simple VBA / C COM DLL examples that actually compile and run . . .??????
0
 
richtelieu88Author Commented:
I just got this to work:

VBA
scd.GenericStruct 2


C COM DLL
[id(7)] HRESULT GenericStruct([in]LONG a);

Let me keep grinding on this.  I need to eventually get it to work with struct pointers . . . but this is a start !  No points assigned yet !
0
 
Martin LissOlder than dirtCommented:
This question has been classified as abandoned and is closed as part of the Cleanup Program. See the recommendation for more details.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now