Xdata Handler Null when running AUDIT
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Another day, another bug!
One of my users has possibly lost a good amount of work from this bug unfortunately. They were working yesterday, saved and closed their file, only to open it this morning and get a Warning to stop opening and run Recover, as 300+ errors were detected.
After running Recover from the prompts, it noted that 10+ items were fixed and left alone. But 300+ items were deleted which is where the loss of work came from.
If I dont run Recover when I open the file I still see all the items deleted, but when I run Audit I get this
Command: AUDIT
Fix any errors detected? [Yes/No] <N>:
Auditing Header
Auditing Tables
Auditing Entities Pass 1
Pass 1 36300 objects auditedAcDbLine(2F283D) XData Handle Unknown Null
AcDbLine(2F283D) was not repaired.
AcDbLine(2F283E) XData Handle Unknown Null
AcDbLine(2F283E) was not repaired.
AcDbLine(2F283F) XData Handle Unknown Null
AcDbLine(2F283F) was not repaired.
AcDbLine(2F2840) XData Handle Unknown Null
AcDbLine(2F2840) was not repaired.
AcDbLine(2F2841) XData Handle Unknown Null
AcDbLine(2F2841) was not repaired.
AcDbLine(2F2842) XData Handle Unknown Null
AcDbLine(2F2842) was not repaired.
AcDbLine(2F2843) XData Handle Unknown Null
AcDbLine(2F2843) was not repaired.
AcDbLine(2F2844) XData Handle Unknown Null
AcDbLine(2F2844) was not repaired.
Pass 1 90600 objects auditedAcDbLine(37A137) XData Handle Unknown Null
AcDbLine(37A137) was not repaired.
Pass 1 90800 objects auditedAcDbArc(37A7B4) XData Handle Unknown Null
AcDbArc(37A7B4) was not repaired.
AcDbArc(37A80C) XData Handle Unknown Null
AcDbArc(37A80C) was not repaired.
AcDbArc(37A886) XData Handle Unknown Null
AcDbArc(37A886) was not repaired.
Pass 1 108700 objects audited
Auditing Entities Pass 2
Pass 2 36300 objects auditedAcDbLine(2F283D) XData Handle Unknown Null
AcDbLine(2F283D) was not repaired.
AcDbLine(2F283E) XData Handle Unknown Null
AcDbLine(2F283E) was not repaired.
AcDbLine(2F283F) XData Handle Unknown Null
AcDbLine(2F283F) was not repaired.
AcDbLine(2F2840) XData Handle Unknown Null
AcDbLine(2F2840) was not repaired.
AcDbLine(2F2841) XData Handle Unknown Null
AcDbLine(2F2841) was not repaired.
AcDbLine(2F2842) XData Handle Unknown Null
AcDbLine(2F2842) was not repaired.
AcDbLine(2F2843) XData Handle Unknown Null
AcDbLine(2F2843) was not repaired.
AcDbLine(2F2844) XData Handle Unknown Null
AcDbLine(2F2844) was not repaired.
Pass 2 90600 objects auditedAcDbLine(37A137) XData Handle Unknown Null
AcDbLine(37A137) was not repaired.
Pass 2 90800 objects auditedAcDbArc(37A7B4) XData Handle Unknown Null
AcDbArc(37A7B4) was not repaired.
AcDbArc(37A80C) XData Handle Unknown Null
AcDbArc(37A80C) was not repaired.
AcDbArc(37A886) XData Handle Unknown Null
AcDbArc(37A886) was not repaired.
Pass 2 108700 objects audited
I'm not sure where to start investigating. I use XData a fair bit in our plugin, and the items that were deleted where a bunch of line items that would have had XData assigned to them from one of the plugins process'.
I only have a few ExtensionMethods for working with XData, so I'll leave those here. This is the first time this has happened. But I have been having the Warning Errors pop up after opening, but recover usually fixes the problems without deleting anything. That problem occurs when using SaveAs and renaming the file.
I'm wondering if I should move to using ExtensionDictionaries instead of XData.
public static void EraseXData(this DBObject dbObject)
{
if (dbObject == null) return;
if (!dbObject.IsWriteEnabled)
{
dbObject.UpgradeOpen();
}
dbObject.XData = new ResultBuffer
{
new TypedValue((int)DxfCode.ExtendedDataRegAppName,
WBtoolsInitializer.WarmboardToolsRegAppName)
};
}
public static void EraseXDataValue(this DBObject dbObject, string key)
{
if (dbObject == null) return;
if (!dbObject.IsWriteEnabled)
{
dbObject.UpgradeOpen();
}
RemoveKeyValue(dbObject);
void RemoveKeyValue(DBObject dbObj)
{
ResultBuffer buffer = new ResultBuffer();
bool hasAppName = true;
if (dbObj.XData != null)
{
foreach (var data in dbObj.XData.AsArray())
{
if (data.TypeCode == (short)DxfCode.ExtendedDataRegAppName)
{
if ((string)data.Value == WBtoolsInitializer.WarmboardToolsRegAppName)
hasAppName = false;
}
if (data.TypeCode == (short)DxfCode.ExtendedDataAsciiString && data.Value is string dataString)
{
if (dataString.Contains(key)) continue;
}
buffer.Add(data);
}
}
//only adds regAppName if not added already
if (hasAppName) buffer.Add(new TypedValue((int)DxfCode.ExtendedDataRegAppName, WBtoolsInitializer.WarmboardToolsRegAppName));
dbObj.XData = buffer;
}
}
public static string FindStringXDataValue(this DBObject dbObject, string searchTerm)
{
try
{
if (dbObject == null || dbObject.XData == null) return string.Empty;
foreach (TypedValue entry in dbObject.XData.AsArray())
{
if (!entry.TypeCode.Equals((int)DxfCode.ExtendedDataAsciiString)) continue;
if (!(entry.Value is string entryValue)) continue;
string[] splitValue = entryValue.Split(',');
if (splitValue.Length < 2) continue;
if (!splitValue[0].Equals(searchTerm)) continue;
return splitValue[1];
}
return string.Empty;
}
catch
{
return string.Empty;
}
}
public static void SetStringXDataValue(this DBObject dbObject, string key, string value)
{
if (dbObject == null || value == null || value == string.Empty) return;
if (!dbObject.IsWriteEnabled)
{
dbObject.UpgradeOpen();
}
AddValueToEnd(dbObject);
void AddValueToEnd(DBObject dbObj)
{
ResultBuffer buffer = new ResultBuffer();
bool hasAppName = true;
if (dbObj.XData != null)
{
foreach (var data in dbObj.XData.AsArray())
{
if (data.TypeCode == (short)DxfCode.ExtendedDataRegAppName)
{
if ((string)data.Value == WBtoolsInitializer.WarmboardToolsRegAppName)
hasAppName = false;
}
if (data.TypeCode == (short)DxfCode.ExtendedDataAsciiString && data.Value is string dataString)
{
if(dataString.Contains(key)) continue;
}
buffer.Add(data);
}
}
//only adds regAppName if not added already
if (hasAppName) buffer.Add(new TypedValue((int)DxfCode.ExtendedDataRegAppName, WBtoolsInitializer.WarmboardToolsRegAppName));
buffer.Add(new TypedValue((int)DxfCode.ExtendedDataAsciiString, $"{key},{value}"));
dbObj.XData = buffer;
}
}
/// <summary>
/// This method will try to find a long value at the key given. This long will try to convert to a handle.
/// This handle will try to convert to an ObjectId.
/// If successful, will return true and assigned id.
/// </summary>
/// <param name="dbObject">Object who's XData will be looked at</param>
/// <param name="key">the key the long was stored at</param>
/// <param name="id">if not found will be ObjectId.Null</param>
/// <returns></returns>
public static bool TryGetLinkedObjectId(this DBObject dbObject, string key, out ObjectId id)
{
string handleVal = dbObject.FindStringXDataValue(key);
if (!long.TryParse(handleVal, out long handleLong))
{
id = ObjectId.Null;
return false;
}
Handle handle = new Handle(handleLong);
ObjectId objectId = new ObjectId();
if (!Active.Database.TryGetObjectId(handle, out objectId))
{
id = ObjectId.Null;
return false;
}
id = objectId;
return true;
}
public static void TrySetObjectIdLink(this DBObject dbObject, string key, ObjectId other)
{
Handle otherHandle = other.Handle;
dbObject.SetStringXDataValue(key, otherHandle.Value.ToString());
}