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.
Varsha Reddy said: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.
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.
Varsha Reddy said:short[] dataArray = dataBlock.ReadInt16Array((int)dataBlock.Size)
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?
Int16
Regards, Jon Summers LA Solutions
Hi Varsha,
Varsha Reddy said: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.
Varsha Reddy said: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).
Varsha Reddy said: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).
Varsha Reddy said: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
Bentley Accredited Developer: iTwin Platform - AssociateLabyrinth Technology | dev.notes() | cad.point
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.
Varsha
Varsha Reddy said: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.
Jan Šlegr said: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#.
union
Jan Šlegr said: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);
Jon Summers said: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.
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;