Archicad C++ API
About Archicad add-on development using the C++ API.

How to deal with string array parameters?

Anonymous
Not applicable
Hey everyone,

i am trying to wrap my head arround how to handle string arrays in memo params. Example:

UInt32 totalParams = BMGetHandleSize((GSConstHandle)memo.params) / sizeof(API_AddParType);
for (int i=0; i<totalParams ;i++){
    GS::UniString pname = (*memo.params).name;
    GS::Array<GS::UniString> conditions = {"param1" ,"param2"};
    
    if (conditions.Contains(pname)){
        WriteReport("dim1: %d", (*memo.params).dim1);
        WriteReport("dim2: %d", (*memo.params).dim2);
        
        UInt32 numArrayItems = BMGetHandleSize((GSConstHandle)(*memo.params).value.array) / sizeof(double);
        WriteReport("num array items: %i", numArrayItems);
        
        API_AddParType* pAddPar = &(*memo.params);
        double** arrHdl = reinterpret_cast<double**>(pAddPar->value.array);
        for (Int32 k = 0; k < pAddPar->dim1; k++){
            for (Int32 j = 0; j < pAddPar->dim2; j++){
                
                switch((*memo.params).typeID){
                        
                    case APIParT_RealNum:
                        WriteReport("realnum");
                        WriteReport("value %f", (*arrHdl)[k * pAddPar->dim2 + j]);
                        break;
                    case APIParT_CString:
                        WriteReport("cstring");
                        WriteReport("value: %s", "??????????");
                        break;
                }  
            }
        }
    }
}
This is working for arrays with APIParT_RealNum value type but im having trouble retrieving the full cstring values. Part of this comes down to me not really understanding the structure and types of the value array and my porbably my basic C++ knowledge. How are numerical and string values stored there? I would be very glad for some explanation and hints!

Thanks a lot in advance!
3 REPLIES 3
Ralph Wessel
Mentor
You may not need to unpack the contents of the parameter memo, depending on what you want to do. If you want to change a parameter value, for example, you can call ACAPI_Goodies with APIAny_ChangeAParameterID. What would you like to do with parameters?
Ralph Wessel BArch
Software Engineer Speckle Systems
Anonymous
Not applicable
Ralph wrote:
You may not need to unpack the contents of the parameter memo, depending on what you want to do. If you want to change a parameter value, for example, you can call ACAPI_Goodies with APIAny_ChangeAParameterID. What would you like to do with parameters?
I basically want to replace some arrays in an LibPart instance. According to the second post from Oleg in this this thread https://archicad-talk.graphisoft.com/viewtopic.php?f=23&t=58610&p=275992&hilit=array+parameter#p275992 i need to realocate the array and change the dim values. However i thought it would be best to start with reading out the current values of the array first and then trying to change them. In the LibPart_Test example is a great example for allocating and filling an new array but it is only done with real numbers. So my trouble right now is that i don't know how the the char values are stored (for real numbers it's just simple doubles) and how to get the length of the string array element. This kind of works:

Int32 ind = 0;

if((*memo.params).typeID == APIParT_RealNum){
    for (Int32 k = 0; k < pAddPar->dim1; k++){
        for (Int32 j = 0; j < pAddPar->dim2; j++){
            value = (Int32) ((double *) *(*memo.params).value.array) [ind];
            valueStr = nullptr;
            ind ++;
            
            WriteReport("value %f", value);
        }
    }
}

if((*memo.params).typeID == APIParT_CString){
    UInt32 num_chars;
    num_chars = BMGetHandleSize((GSConstHandle)(*memo.params).value.array)/ sizeof(char);
    WriteReport("num chars: %i", num_chars);
    for(int j=0; j<num_chars;j++){
        
        value = 0.0;
        valueStr = *(*memo.params).value.array + ind;
        ind += strlen (valueStr) + 1;
        
        WriteReport("val: %s", valueStr);
    }
}
but num_chars is allways the same and not specific to the string array element.
Any help would be aprecciated!

Edit: I found that using UTF16Char instead of char gives me the correct number of signs in the string array (including the two split signs as pointed out in the API documentation)
num_chars = BMGetHandleSize((GSConstHandle)(*memo.params).value.array)/ sizeof(UTF16Char);
Anonymous
Not applicable
I was able to read out the string values like this:

char* valueStr;
double value;
GS::Array<GS::UniString> StrArrValues;
GS::UniString ValueString;

Int32 ind = 0;

if((*memo.params).typeID == APIParT_RealNum){
    for (Int32 k = 0; k < (*memo.params).dim1; k++){
        for (Int32 j = 0; j < (*memo.params).dim2; j++){
            value = (Int32) ((double *) *(*memo.params).value.array) [ind];
            valueStr = nullptr;
            ind ++;
            WriteReport("val %i:", k * (*memo.params).dim2 + j);
            WriteReport("%f", value);
        }
    }
}

if((*memo.params).typeID == APIParT_CString){
    UInt32 num_chars;
    num_chars = BMGetHandleSize((GSConstHandle)(*memo.params).value.array)/ sizeof(UTF16Char);
    for(int j=0; j<num_chars;j++){
        
        value = 0.0;
        valueStr = *(*memo.params).value.array + ind;
        //valueStr = *(*addPars).value.array + ind;
        if(*valueStr == '\0'){
            StrArrValues.Push(ValueString);
            ValueString = "";
            
            ind += 2;
        }else{
            ValueString.Append(valueStr);
            ind += strlen (valueStr) + 1;
        }
    }
    for(int j=0; j<StrArrValues.GetSize();j++){
        WriteReport("val %i:", j);
        WriteReport("%s", UniStringToConstCString(StrArrValues));
    }
}
It works but i guess i this is not the way it is supposed to be done isn't it?