[OPM CE Update 9 C#] : Read and Append Linkage

I have to read and update the attributes to the element, on OPM CE Update 9. However, to find the way to do it, I am looking the potential in the below code, but during read, OPM crashes at the line provided in the code below.

            
                ReadDataBlock dataBlock = element.GetLinkage(linkageId);
                
                //OPM crashes here
                short[] dataArray = dataBlock.ReadInt16Array((int)dataBlock.Size);

                List<short> dataList = dataArray.ToList();

                dataList.Add(4204);
                dataList.Add(27070);

                short[] newdataArray = dataList.ToArray();

                WriteDataBlock newdataBlock = new WriteDataBlock();
                newdataBlock.WriteInt16Array(newdataArray);

                element.AppendLinkage(linkageId, newdataBlock);
      

As I was not able to find the way to see the content of linkages of the element in OPM CE Update 9. This is how I discovered the linkages of the element, in Microstation SS3.

Thanks in advance.

  • I was not able to find the way to see the content of linkages of the element in OPM CE

    Use key-in ANALYZE ELEMENT.

    A data linkage contains binary data.  MicroStation knows nothing about those data: the content is created and read by an application.  To read the data, you must know its structure.

    short[] dataArray = dataBlock.ReadInt16Array((int)dataBlock.Size)

    You're assuming that the data linkage contains an array of Int16 (short integers).  Make no assumptions!  Do you have a specification for the structure of that data linkage?

     
    Regards, Jon Summers
    LA Solutions

  • Hi Varsha,

    I have to read and update

    Even when it is task used by many application, you should be aware that original idea is that only original application (using unique id, assigned by Bentley) append user attributes to an element.

    Also it is not expected the data is read directly by other applications, because user attributes are unformatted binary data, where format is known only to the original application.

    the attributes to the element

    To be precise: element attributes are level, color, line weight..., whereas you discuss user attribute data (also called user linkages).

    OPM crashes at the line provided in the code below.

    I do not see any test, whether returned DataBlock is not null (e.g. because linkage id is wrong).

    As I was not able to find the way to see the content of linkages of the element in OPM CE Update 9.

    As Jon wrote, use "analyze element" key-in. But, as I wrote above, it is not expected data created by one application is read directly (or even modified) by other application.

    Regards,

      Jan

  • Hi Jan,

    Yes, it is user linkage data, and below is the mdl code, which we are interpreting

    union {                 
    	short words[110];    
    	struct {
    		char	filler[4];
    		char	grade[5];	//--- NO/YES/BOTH
    		char  	state[21];  //--- Proposed,Existing,....
    		char	district[16];
    		char	lineno[96];
    		char	cellname[28];
    		char	service[30];
    		char	diameter[10];
    	} head;	
    } U;
    
    //How it finds the index of certain attribute and then uses the index to extract further attrributes
    Private int GetCustomAttributes (MSElementDescr  *edP) {
    	int nwords,ndx,n,k;
    	char	grade[10];
    	ndx=-1;
    	mdlElmdscr_extractAttributes(&nwords,words,edP);
    	for(n=0;n<nwords;n++) if(words[n]==4205 && words[n+1]==26969) ndx=n;	//--- Find our UGL attributes ---
    	if(ndx==-1) return 0;
    	k=0;
    	for(n=ndx;n<ndx+110;n++) U.words[k++]=words[n];	
    	if(k==0) return 0;
    	return 1;
    }
    
    
    MSElementDescr  *edP;
    GetCustomAttributes(edP);
    
    // How it updates and then appends the attributes
    for(n=0;n<110;n++) U.words[n]=0;
    		for(n=0;n<nwords;n++) if(words[n]==4205 && words[n+1]==26969) ndx=n;	//--- Find our UGL attributes ---
    		if(ndx>-1) {	
    			k=0;
    			for(n=ndx;n<ndx+110;n++) U.words[k++]=words[n];	
    			if(!strcmpi(Grade,"0")) strcpy(U.head.grade,"NO");
    			if(!strcmpi(Grade,"1")) strcpy(U.head.grade,"YES");
    			if(!strcmpi(Grade,"2")) strcpy(U.head.grade,"BOTH");
    			mdlElmdscr_stripAttributes(&edP);
    			mdlElmdscr_appendAttributes(&edP,110,U.words);
    		}

    This is the linkage data of the model element. This does not contains those attributes, just gathered to view the structure of linkage data.

    Regards,

    Varsha

  • Yes, it is user linkage data, and below is the mdl code, which we are interpreting

    I would say the code is brutal low level one ;-) ... and not very robust and safe :-(

    I do not see any reason why to obtain all linkage data together as raw binary chunk, because it requires to interpret everything (linkage header, information stored in header, the data itself...).

    Preferred way is - using linkage id - to extract only required data. API takes care to interpret header data, whereas he data itself (DataBlock in NET and Interop APIs) must be interpreted by application.

    Regards,

      Jan

  • I would say the code is brutal low level one!

    I agree.  That code uses aspects of the C language (e.g. a union) that is tricky to interpret using C#.

    Preferred way is - using linkage id - to extract only required data

    The C code analyses each linkage to find that signature...

    ndx=-1;
    mdlElmdscr_extractAttributes(&nwords,words,edP);
    for(n=0;n<nwords;n++) if(words[n]==4205 && words[n+1]==26969) ndx=n;
    if(ndx>-1)
    {
      //  Found UGL linkage
    }

    The UGL linkage ID is 4205 and the application ID is 26969.  The first thing you should do in your C# is to name those magic numbers...

    public ushort UglLinkageId        { get { return 4205;  } }
    public ushort AnnotationLinkageId { get { return 26969; } }

    Use the API to find those data for you...

    ReadDataBlock linkageData = element.GetLinkage(UglLinkageId);

     
    Regards, Jon Summers
    LA Solutions

  • The C code analyses each linkage to find that signature...

    Yes, exactly ... and does it in a fragile way, that is risky to migrate from one platform (32bit) to another one (64bit).

    I guess the code itself should work both in V8i C and CE C++ code, and even in CE NET code, because short is always 2 bytes (16bit) type. But when the things are done in this way, every piece of the code must be verified a size of the used type is not different in 32 and 64bit environments.

    Regards,

      Jan

  • I believe the Size property of the datablock is returning the total number of bytes.   In your code, you are telling it to read that many shorts, most likely causing an index out of bounds error...

    I do similar code my self.

                // Check if the element has any linkage..
                if (_element == null || _element.GetLinkageCount(AppId) == 0)
                    return false;
    
                using (ReadDataBlock data = _element.GetLinkage(AppId))
                {
                    if (data.ReadByte() != LinkageId)
                        return false;
    
                
                    AttributeType type = (AttributeType) data.ReadInt16();
                    
                    // Check if the linkage is what we are looking for.
                    if (type != _attributeType)
                        return false;
    
                    _attributes = ProcessBytes(data.ReadByteArray((int) data.Size));
                }
                return true;