Hi Everyone,
I am trying to write an MDL in C/C++ that should attach Meta-Data to Elements in an external MDB-Database.
I wrote already Code to make sure that the correct Database (DB) is attached, but now I have Problems how to attach the created MSLink to an element.
There is one function to write the Attributes into the DB and retrieve the MSLink:
Private int writeObjatt ( UInt32 *mslink, char *tableName, char *objidP, char *oclassP, char *ocodeP, char *icodeP, char *statusP ) { char insertStmt[MAXSTATEMENTLENGTH]; char dbColumns[5*TAGSTRINGVALLENGTH+10]; char dbValues[5*TAGSTRINGVALLENGTH+10]; int ret=-1, test1=-1; // Writing the column-names into a string sprintf(dbColumns, "objid, oclass, ocode, icode, status"); // writing the values into a string sprintf(dbValues, "'%s','%s','%s','%s','%s'", objidP, oclassP, ocodeP, icodeP, statusP); // writing the finlal SQL-Insert-Statement into a string sprintf(insertStmt, "insert into %s (%s) values (%s)", tableName, dbColumns, dbValues); fprintf(f_log, "\t(In tab2db_writeObjatt): Insert-Statement= '%s'\n", insertStmt); // Writing into Database test1 = mdlDB_addRowWithMslink(mslink, tableName, insertStmt); if(test1 == SUCCESS) ret=SUCCESS; return ret; }
Private int CallbackFunct ( ElementRef elR, void *callbackArg, // Structur with arguments for Callback-function ScanCriteriaP scP // Pointer to ScanCriteria-Object ) { int ret=SUCCESS; int test=-1, status=-1; int elType; // Element-Typ UInt32 mslink; // MSLink-Number CallbackArgStruct *data = (CallbackArgStruct*)callbackArg; MSElementP elP; EditElemHandle eh(elR, mdlScanCriteria_getModel(scP)); // Element-Handler char t_objidP[TAGSTRINGVALLENGTH], t_oclassP[TAGSTRINGVALLENGTH], t_ocodeP[TAGSTRINGVALLENGTH]; char t_icodeP[TAGSTRINGVALLENGTH], t_statusP[TAGSTRINGVALLENGTH]; // Checking Element-Type elType = eh.GetElementType(); // Pointer to element created from ElemeHandle elP = eh.GetElementP(); if(elType==CELL_HEADER_ELM || elType==LINE_ELM || elType==LINE_STRING_ELM || elType==LINE_STRING_ELM) { [...] // Retrieve Attribute-values from element // Writing Attributes into Database using the above mentioned function test = writeObjatt(&mslink, "objatt", t_objidP, t_oclassP, t_ocodeP, t_icodeP, t_statusP); //????? How to attach the MSLink to the MSElement ?????// // REPLACING the old element instead of rewriting in reason of different Size after MSLink-Attachment ?? status = ReplaceElement (elP); //??? if(test != SUCCESS) ret=-1; } return ret; }
Hi Jon,
many thanks for your answer!
This worked - I only had to rewrite the MSElementDescr-Object afterwards, so that the Linkage was written to the DGN-File.
UInt32 filePos=NULL, newfilePos=NULL; MSElementDescr* pFeature; //used instead of MSElementDescr** ppFeature [...] // see code from Jon mdlElmdscr_appendAttributes(&pFeature, linkSize, linkage); //rewriting the changed MSElementDescr-Oject filePos = mdlElmdscr_getFilePos(pFeature); newfilePos=mdlElmdscr_rewrite(pFeature, NULL, filePos);
Many thanks for your help!
Regards,
Ines Wieland
Unknown said:The structur of DatabaseLink is not very clear for me, e.g. what is meant with 'entity' in this context
Yes, the terminology is obscure. This article about MicroStation DB linkages may help.
Entity No. is the integer associated with one of your DB tables in the mscatalog table.
mscatalog
Displayable Attribrutes (DAS) are another obscure MicroStation term used with DBs. MicroStation can automatically extract DB data and create text labels for elements having a DB linkage. You need to be familiar with MicroStation DB user interface for that to make any sense!
I've dug into our apps. for MicroStation V7, which is the last time I used MDL to create a DB element linkage. This code is C, not C++, and has been superseded.
First, some macro definitions...
#define BAD_INDEX -1#define DBLINKAGE_ARRAY_SIZE 8 /* // DB LinkProps initialisers // User bit is always 1 // Information bit is 1 to prevent new rows being inserted in DB on copy */ #define DB_LINKPROPS_INFORMATIONAL(p) \ memset (&p, 0x00, sizeof (LinkProps)); \ p.information = 1; \ p.user = 1; #define DB_LINKPROPS_NORMAL(p) \ memset (&p, 0x00, sizeof (LinkProps)); \ p.information = 0; \ p.user = 1;
This used to work...
int db_createLinkage ( short* linkage, // <= short [DBLINKAGE_ARRAY_SIZE] int linkType, // => ODBC_LINKAGE, ... ULong mslink, // => MSLINK we're going to attach char* pszTable // => Name of DB table ) { LinkProps props; int linkageSize = BAD_INDEX; int rc; // If MSLINK is zero, we don't want to attach a linkage. // Set LinkageSize to -1 as a flag if (0L == mslink || NULL == pszTable || 0 == strlen (pszTable)) { linkageSize = BAD_INDEX; } else { DB_LINKPROPS_INFORMATIONAL (props) rc = mdlDB_buildLink ( linkage, // <= database linkage &linkageSize, // <= size (words) of linkage linkType, // => ODBC_LINKAGE, etc, ...) &props, // => properties of linkage pszTable, // => table name of linkage mslink, // => MSLINK key for linkage 0); // => displayable attribute type if (SUCCESS == rc) { //TRACE3 (" built DB linkage mslink=%ld to [%s] size=%d", // mslink, pszTable, linkageSize); } else { //TRACE2 (" failed to build DB linkage mslink=%ld to [%s]", // mslink, pszTable); linkageSize = BAD_INDEX; } } return linkageSize; }
Now you can attach the DB linkage to an element...
boolean db_appendLinkage ( MSElementDescr** ppFeature, // <=> Attributed element ULong mslink // => New MSLINK ) { int linkSize = 0; if (0L < mslink) { short linkage [DBLINKAGE_ARRAY_SIZE]; // Attach DB linkage to host shape linkSize = db_createLinkage (linkage, gp_dbInfo->dbLinkage, mslink, tblFEATURE); //TRACE2 (" mslink=%ld linkSize=%d", // mslink, linkSize); mdlElmdscr_appendAttributes (ppFeature, linkSize, linkage); //TRACE (" created DB linkage"); } return (0 < linkSize); }
Regards, Jon Summers LA Solutions
Answer Verified By: Ines Wieland
It seems you have not correctly built the "link" structure, which is typically 4 or 8 words, depending on the linkage type. The "link" should be an array.
many thanks for your answer, although my Problem is not solved yet.
Im working on MicroStation V8i SS4.
The structur of DatabaseLink is not very clear for me, e.g. what is meant with 'entity' in this context, is it the number of the table in mscatalog or the ElementID? And what do I have to fill in the LinkProps-structur and as dasType? In Addition I didn't found a function that uses the DatabaseLink-structure to append that linkage to an element.
I tried the following inside the function 'writeObjatt', for which I added the Parameter 'MSElement *elP':
Private int writeObjatt ( MSElement *elP, UInt32 *mslink, char *tableName, char *objidP, char *oclassP, char *ocodeP, char *icodeP, char *statusP ) { char insertStmt[MAXSTATEMENTLENGTH]; char dbColumns[5*TAGSTRINGVALLENGTH+10]; char dbValues[5*TAGSTRINGVALLENGTH+10]; int ret=-1, test1=-1, test2=-1, test3=-1; short link; int linkLength, linkType=OLEDB_LINKAGE, dasType=1; LinkProps props; UInt32 newfilePos; // Writing the column-names into a string sprintf(dbColumns, "objid, oclass, ocode, icode, status"); //writing the values into a string sprintf(dbValues, "'%s','%s','%s','%s','%s'", objidP, oclassP, ocodeP, icodeP, statusP); // writing the final SQL-Insert-Statement into a string sprintf(insertStmt, "insert into %s (%s) values (%s)", tableName, dbColumns, dbValues); //Writing into Database test1 = mdlDB_addRowWithMslink(mslink, tableName, insertStmt); // Filling the LinkProps-Structur props.information = NEWLINK; // new linkage generation mode ? props.remote = DB_PROP_REMOTE; // ?? props.modified = DB_PROP_MODIFIED; //?? props.user = DB_PROP_USER; // ?? props.linkageClass = OLEDB_ID; //?? test2 = mdlDB_buildLink(&link, &linkLength, linkType, &props, tableName, *mslink, dasType); test3 = mdlElement_appendAttributes(elP, linkLength, &link); newfilePos = mdlElement_rewrite(elP, NULL, mdlElement_getFilePos(FILEPOS_CURRENT, NULL)); if(test1 == SUCCESS && test3 == SUCCESS) ret=SUCCESS; return ret; }
It can be compiled without Problem, but it crashes Microstation during the first element I am working on. The Problem seemed to be in line 43, where the function mdlElement_appendAttributes() is called.
Is this in reason of wrong filled LinkProps-structur and dasType, or did I misunderstood something else?
Unknown said:I am trying to write an MDL in C/C++
For what version of MicroStation?
Unknown said:How to attach the MSLink to the MSElement?
The DB interface is rather idiosyncratic. Its terminology dates from Intergraph's hierarchical database from the 1980s, and doesn't match well with relational databases.
Look at the MDL help about DatabaseLink. It defines the struct with some comments. What you need to do is to fill in a DatabaseLink with your data, then append that linkage to your element.
DatabaseLink
You may be able to use mdlDB_buildLink() to build a linkage, but either way use mdlElement_appendAttributes() to attach the linkage to your element. Rewrite the element after attaching the linkage.
mdlDB_buildLink()
mdlElement_appendAttributes()