CComSafeArray
-
Hi! I have an activeX control, which should send variuous arrays to the client. What I have done, is to wrap these arrays into a CComSafeArray and then send it as a pointer to a VARIANT. How can I then on client side determine which datatypes the array consists of? Whether it is int, long, double, float and so on?
-
Hi! I have an activeX control, which should send variuous arrays to the client. What I have done, is to wrap these arrays into a CComSafeArray and then send it as a pointer to a VARIANT. How can I then on client side determine which datatypes the array consists of? Whether it is int, long, double, float and so on?
The variant type should tell you on the client (if your ActiveX control is putting them together correctly). For instance, the VT of the VARIANT would be VT_ARRAY | VT_I4 for longs, VT_ARRAY | VT_I2 for shorts, etc. It could be VT_ARRRAY | VT_VARIANT, which means that each element of the array is a variant itself, which agains means you'll have to test the VT.
-
The variant type should tell you on the client (if your ActiveX control is putting them together correctly). For instance, the VT of the VARIANT would be VT_ARRAY | VT_I4 for longs, VT_ARRAY | VT_I2 for shorts, etc. It could be VT_ARRRAY | VT_VARIANT, which means that each element of the array is a variant itself, which agains means you'll have to test the VT.
thanks for good answer! I have some other questions as well; 1) Will memcpy be a good approach to this task? If so, how will the code look then? My array consist of approx. 15000 elements. 2) How do I send an array of user defined structure elements?
-
thanks for good answer! I have some other questions as well; 1) Will memcpy be a good approach to this task? If so, how will the code look then? My array consist of approx. 15000 elements. 2) How do I send an array of user defined structure elements?
For question #1, maybe. It depends on how your data is stored. You can get a void * back from the safearray, then cast it to the type, the memcpy it: void *pData; SafeArrayAccessData(sa,&pData); memcpy((LPBYTE)pData,pMyByteArray,sizeof(BYTE)*numElements); or something similar. Question 2: This gets trickier. Different schools of thought: 1.) don't do that. Define the struct in IDL, define the interface to return those (say, maybe an Item property with an index). 2.) Someone has a gun to your head and says they'll kill you if you don't (only acceptable reason to do it this way): Create an array of variants. Each variant then in and of itself contains a safearray of bytes, which is one element in your array of structs. Version 2 of this, create a variant that is an array of bytes and memcpy the whole thing. If this is for something production, I highly suggest doing something different than blobbing it. It's much more extensible to have a collection interface that returns interfaces for each structure your defining: ActiveX Control | |----- property Item([in]long index, [out,retval] IStruct **ppIStruct) interface IStruct | |--- property name |--- property address etc etc, mapping a property value in IStruct to the value of your structure. If your using something like ATL, you might want to look at a tear-off interface for implementing this. Just a thought.
-
For question #1, maybe. It depends on how your data is stored. You can get a void * back from the safearray, then cast it to the type, the memcpy it: void *pData; SafeArrayAccessData(sa,&pData); memcpy((LPBYTE)pData,pMyByteArray,sizeof(BYTE)*numElements); or something similar. Question 2: This gets trickier. Different schools of thought: 1.) don't do that. Define the struct in IDL, define the interface to return those (say, maybe an Item property with an index). 2.) Someone has a gun to your head and says they'll kill you if you don't (only acceptable reason to do it this way): Create an array of variants. Each variant then in and of itself contains a safearray of bytes, which is one element in your array of structs. Version 2 of this, create a variant that is an array of bytes and memcpy the whole thing. If this is for something production, I highly suggest doing something different than blobbing it. It's much more extensible to have a collection interface that returns interfaces for each structure your defining: ActiveX Control | |----- property Item([in]long index, [out,retval] IStruct **ppIStruct) interface IStruct | |--- property name |--- property address etc etc, mapping a property value in IStruct to the value of your structure. If your using something like ATL, you might want to look at a tear-off interface for implementing this. Just a thought.
Thx! I am very happy by your answers! But I must admit that I dont follow you all the time! I am quite new to c++. Would you mind to give me a short example on the memcpy stuff? For instance how to do it with an array of doubles, and then send it to client? And regarding question 2, you say; "Each variant then in and of itself contains a safearray of bytes, which is one element in your array of structs." Why should it contain bytes and not doubles for instance? Last question; How would a code snipp for the idl look like? Lets say I have the following stucture: Code: typedef struct somePoints{ int a,b,c; } MY_STRUCT; I have the "somePoints" elements arranged in an array and have this get method; Code: MY_STRUCT *getArrayP(void) { return arrayP; } So by using CComSafeArray, how would you send this array? So far I have been iterating through the struct elements one by one, and then inserting a, b and then c. By doing is this way I feel that I put a lot of responsibility on the client, because he has to know that element i*3+0 is my a, i*3+1 is b and i*3+2 is c. Any way of improving this, at least making it easier for client? Cheers
-
Thx! I am very happy by your answers! But I must admit that I dont follow you all the time! I am quite new to c++. Would you mind to give me a short example on the memcpy stuff? For instance how to do it with an array of doubles, and then send it to client? And regarding question 2, you say; "Each variant then in and of itself contains a safearray of bytes, which is one element in your array of structs." Why should it contain bytes and not doubles for instance? Last question; How would a code snipp for the idl look like? Lets say I have the following stucture: Code: typedef struct somePoints{ int a,b,c; } MY_STRUCT; I have the "somePoints" elements arranged in an array and have this get method; Code: MY_STRUCT *getArrayP(void) { return arrayP; } So by using CComSafeArray, how would you send this array? So far I have been iterating through the struct elements one by one, and then inserting a, b and then c. By doing is this way I feel that I put a lot of responsibility on the client, because he has to know that element i*3+0 is my a, i*3+1 is b and i*3+2 is c. Any way of improving this, at least making it easier for client? Cheers
Well, it's extremely uncommon to have a structure with uniform data types. Most structs are more like struct { int value; float fvalue; short somethingElse; etc., etc. } Now, for your case, I'd do one of two approaches. The big question is do you have to support scripting environments? Option 1) Using the interface Define the structure in IDL. This looks pretty much identical to you C structure definition. Define a method that returns these: For instance, in your IDL struct MY_STRUCT{ long a; long b; long c; }; //as a method on your COM object [propget, id(1)] HRESULT Item([in[ Index,[out,retval] struct MyDataType* blah); And implement from there. Option 2) Using a big safearray Create a safearray of variants (one for each structure), then each variant is a safearray of VT_I4. It's up to your client to know what the order of each value means, which means that this approach is fairly brittle.
-
Well, it's extremely uncommon to have a structure with uniform data types. Most structs are more like struct { int value; float fvalue; short somethingElse; etc., etc. } Now, for your case, I'd do one of two approaches. The big question is do you have to support scripting environments? Option 1) Using the interface Define the structure in IDL. This looks pretty much identical to you C structure definition. Define a method that returns these: For instance, in your IDL struct MY_STRUCT{ long a; long b; long c; }; //as a method on your COM object [propget, id(1)] HRESULT Item([in[ Index,[out,retval] struct MyDataType* blah); And implement from there. Option 2) Using a big safearray Create a safearray of variants (one for each structure), then each variant is a safearray of VT_I4. It's up to your client to know what the order of each value means, which means that this approach is fairly brittle.
Thanks! This helped me a lot! Now this is hopefully my last post to this thread! Lets say I have the following code on client:
CComVariant varArray; // Get the array from the server my_readCtrl.getArray(&varArray); // Decide the datatype of the Variant // Attach the safe array if(varArray.vt==VT_I1) { CComSafeArray saFromVariant; } else if(varArray.vt==VT_R8) { CComSafeArray saFromVariant; } saFromVariant.Attach (varArray.parray);
This results in an compilation error since saFromVariant is not declared. That is obviously because the declarations are inside if statements. How to avoid this but still declared it correct? Thx -
Well, it's extremely uncommon to have a structure with uniform data types. Most structs are more like struct { int value; float fvalue; short somethingElse; etc., etc. } Now, for your case, I'd do one of two approaches. The big question is do you have to support scripting environments? Option 1) Using the interface Define the structure in IDL. This looks pretty much identical to you C structure definition. Define a method that returns these: For instance, in your IDL struct MY_STRUCT{ long a; long b; long c; }; //as a method on your COM object [propget, id(1)] HRESULT Item([in[ Index,[out,retval] struct MyDataType* blah); And implement from there. Option 2) Using a big safearray Create a safearray of variants (one for each structure), then each variant is a safearray of VT_I4. It's up to your client to know what the order of each value means, which means that this approach is fairly brittle.
I think I want to go for option 1 here. Can you show me how to write the code for the idl stuff? Thanks