Storing the Roadmap of an Object using Solid Edge API

Reference Keys in Solid Edge

Many Solid Edge automation users would like to store the roadmap of an object so that they can get the same object back across different sessions. In this article, I will walk you through the recommended way to achieve this in Solid Edge.

Roadmap can be stored for many objects such as Body, Curve, Face, Edge, Vertex, etc. In this example, I am assuming that the entity for which user would like to store the roadmap is “Face”.

What is a ReferenceKey ? How can I get ReferenceKey of a face?

ReferenceKey is mainly used in automation and it’s the ID of an object in Solid Edge. Automation users can get this ID with the help of  GetReferenceKey method available on that object. GetReferenceKey method returns an array of bytes. This key can be stored and used later to get the same object back. The most important thing is this key can be used across multiple sessions.

Below is the sample code to get the ReferenceKey of a face in C++.  You can use it for objects on which GetReferenceKey method is available.

FacePtr pFacePtr = pFaces->Item(IndexFace);
SAFEARRAY* sapInputRefKey = NULL;
pFacePtr->GetReferenceKey(&sapInputRefKey);

Where to store ReferenceKey? How?

Now that the user got ReferenceKey, the next question is where to store it so that it can be accessed via automation as and when required. Please don’t store the ReferenceKey in a separate file to avoid the possibilities of file being deleted/modified in future. It should be stored such that it’s not easily accessible interactively.

I would recommend storing it to AddInsStorage so that the valid ReferenceKey will be available via automation anytime in future. AddInsStorage property is available for all types of Solid Edge files. Since Solid Edge also uses COM Structured Storage to store data, it’s safe to save user data here as well.

Here’s the sample code to open the file storage and add a new stream:

PartDocumentPtr pPartDoc1;
_bstr_t bstrDocName1; 
// empty string will cause GetDocPtr to retrieve the active document
GetDocPtr(bstrDocName1,pPartDoc1);
if (!pPartDoc1)
return E_FAIL;
if(NULL == pStorage)
	pStorage = pPartDoc1->GetAddInsStorage(L"MyStorage1", 0);

// Create a new stream in the storage.
hr = pStorage->OpenStream(L"Info1", NULL, STGM_DIRECT | STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);

if(NULL == pStream)
	pStorage->CreateStream(L"Info1", STGM_DIRECT | STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream);

// sapInputRefKey is the ReferenceKey of face.
SaveAddInStorageInfo(pDoc,sapInputRefKey);

The byte array that you get from GetReferenceKey method can’t be stored as is. You will have to convert it to string as shown in sample code below.

void SaveAddInStorageInfo(LPDISPATCH theDocument, SAFEARRAY* sapInputRefKey)
{
	SolidEdgeDocumentPtr pDocument = NULL;
	pDocument = theDocument;
	// Get SE ReferenceKey Data....
	SAFEARRAY* pSERefKey = sapInputRefKey;
	VARTYPE vt;
	// Get the VARTYPE of the data stored inside the SAFEARRAY.
	SafeArrayGetVartype(pSERefKey, &vt);
	// This should be VT_UI1 (byte).
	if (vt != VT_UI1)
	return;

	// Get the number of dimensions in the SAFEARRAY.
	UINT uiDim = SafeArrayGetDim(pSERefKey);
	// This should be just 1.
	if (uiDim != 1)
	return;

	long lLBound = 0, lUBound = 0;
	// Obtain the lower and upper bounds of dimension 1 of the SAFEARRAY.
	SafeArrayGetLBound(pSERefKey, 1, &lLBound);
	SafeArrayGetUBound(pSERefKey, 1, &lUBound);

	// At present, I am assuming that every ReferenceKey lLBound equal to '0' & lUBound should always greater then '0'.
	if ((lLBound != 0) || (lUBound <= 0))
	return;

	// Connect to the addin storage specifying the storage name.
	// Add RefKey Byte data .............
	for (long l = lLBound; l <= (lUBound ); l++)
	{
		byte byValue = 0;
		SafeArrayGetElement(pSERefKey, &l, (void*)&byValue);
		ULONG pcbWritten = 0;
		pStream->Write(&byValue, sizeof(byte), &pcbWritten);
	}	
	
}

Please note that it must to commit the stream after writing the data as shown below.

pStream->Commit(STGC_DEFAULT | STGC_OVERWRITE); 

How to read ReferenceKey from storage and highlight the face?

Once the data is stored in File storage the next step is to read the data from storage. The code below will read the data from storage, convert it back to byte array, and then bind it using BindKeyToObject to highlight the face.

for (long IndexFace = 0; IndexFace < nFaceCount; ++IndexFace)
{
FacePtr pFacePtr = pFaces->Item(IndexFace + 1);					
variant_t oVarPersist = NULL;
long sizeToRead = 0;
pStream->Read(&sizeToRead, sizeof(long), &pcbRead);
			
SAFEARRAYBOUND  rgsabound[] = { sizeToRead,0 };

//set data type variant going to hold
oVarPersist.vt = VT_ARRAY | VT_UI1;
//create safe array from above data
oVarPersist.parray = SafeArrayCreate(VT_UI1, 1, rgsabound);
					
for (long index = 0; index <= sizeToRead; index++)
		{
			byte bref = 0;
			pStream->Read(&bref, sizeof(byte), &pcbRead);
						
			hr = SafeArrayPutElement(oVarPersist.parray, &index, (void*)&bref);
		}
			LPDISPATCH lpDispObj = NULL;
			pPartDoc1->BindKeyToObject(&(oVarPersist.parray), &lpDispObj);
			pPartDoc1->GetSelectSet()->Add(lpDispObj);
}

I hope you’ll find this information useful. Happy Coding. 😊

Comments

One thought on “Storing the Roadmap of an Object using Solid Edge API

Leave a Reply