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
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

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.
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.
richtelieu88Author Commented:
evil, do you have a quick example of how to do this marshaling . . . based on the TXT file I attached
Exploring SharePoint 2016

Explore SharePoint 2016, the web-based, collaborative platform that integrates with Microsoft Office to provide intranets, secure document management, and collaboration so you can develop your online and offline capabilities.

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:

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???
richtelieu88Author Commented:
Sarabande, that artical appears promising.  Let me experiment with it before I award points.
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];
       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.


Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
richtelieu88Author Commented:

Well, I followed the instructions, to the letter of the "law", in that article you sent me "" 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
richtelieu88Author Commented:

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 . . .??????
richtelieu88Author Commented:
I just got this to work:

scd.GenericStruct 2

[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 !
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.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today

From novice to tech pro — start learning today.