I am currently working in a company offering GIS solutions, and using ArcGIS tools on a daily basis. One of their main products is an ArcMap extension, which I am assigned on to correct some remaining bugs (my configuration being Windows 8 , ArcGIS 10.1 and Visual Studio 2008). It was impossible to open a custom mxd file by double clicking it. The file was loaded without the custom solvers, displaying a "naked" network.
With lots of debugging and experimenting, I finally "solved" the problem using the ApplicationInitialized event, and loading the file from here with IApplication.OpenDocument if the application was launched from a double click. The idea was to let the file be loaded with the default method, and then load it the right way by triggering our own implementation of IPersistStream.Load.
It worked fine at first, but with a particular file the load fails in ArcMap by double clicking it, displaying the following message: screenshot here
The file can be loaded from ArcMap with File>Open or the initial browsing panel, is recent and not corrupted.
Since the problem is happening right after our implementation of IExtension.Startup, I tried anything I could in this method but I finally understood it isn't supposed to contain file manipulations. Then I tried to force ArcMap to always open a new file on start, but it didn't work either.
The class loading the extension:
public class OurExtension : IExtension, IExtensionConfig, IPersistVariant
{
[ComRegisterFunction()]
[ComVisible(false)]
static void RegisterFunction(Type registerType)
{
// Required for ArcGIS Component Category Registrar support
ArcGISCategoryRegistration(registerType);
}
[ComUnregisterFunction()]
[ComVisible(false)]
static void UnregisterFunction(Type registerType)
{
// Required for ArcGIS Component Category Registrar support
ArcGISCategoryUnregistration(registerType);
}
public void Shutdown()
{
//TODO: Clean up resources
application = null;
}
public void Startup(ref object initializationData)
{
application = initializationData as IApplication;
if (application == null)
{
return;
}
//Listening to document events
SetUpDocumentEvent(application.Document);
//Listening to the initialized status event of the application
(application as IApplicationStatusEvents_Event).Initialized += new IApplicationStatusEvents_InitializedEventHandler(ApplicationInitialized);
//Language configuration
// ....
}
public void Load(IVariantStream stream)
{
//TODO: Load persisted data from document stream
Marshal.ReleaseComObject(stream);
}
public void Save(IVariantStream stream)
{
//TODO: Save extension related data to document stream
Marshal.ReleaseComObject(stream);
}
#region EVENTS
//Wiring.
private ESRI.ArcGIS.ArcMapUI.IDocumentEvents_Event m_docEvents = null;
private void SetUpDocumentEvent(ESRI.ArcGIS.Framework.IDocument myDocument)
{
m_docEvents = myDocument as ESRI.ArcGIS.ArcMapUI.IDocumentEvents_Event;
m_docEvents.NewDocument += new ESRI.ArcGIS.ArcMapUI.IDocumentEvents_NewDocumentEventHandler(OnNewDocument);
m_docEvents.BeforeCloseDocument += new ESRI.ArcGIS.ArcMapUI.IDocumentEvents_BeforeCloseDocumentEventHandler(onBeforeCloseDocument);
}
public void OnNewDocument()
{
if (!newDocumentCreated)
{
//Not listening to this event anymore ensures no error will come from this handler later on
m_docEvents.NewDocument -= new ESRI.ArcGIS.ArcMapUI.IDocumentEvents_NewDocumentEventHandler(OnNewDocument);
}
//If a new document is created, the boolean must become true to avoid re-loading the file from this class
newDocumentCreated = true;
}
public bool onBeforeCloseDocument()
{
//If the new document hasn't been created and the current one is being closed, it means it was loaded as a NetworkAnalyst document
if (!newDocumentCreated)
{
//Setting the current document as clean before closing avoids the opening of the Save Dialog Box
IDocumentDirty2 dirtyDocument = application.Document as IDocumentDirty2;
dirtyDocument.SetClean();
//Not listening to this event anymore ensures no error will come from this handler later on
m_docEvents.BeforeCloseDocument -= new ESRI.ArcGIS.ArcMapUI.IDocumentEvents_BeforeCloseDocumentEventHandler(onBeforeCloseDocument);
}
return false;
}
public void ApplicationInitialized()
{
System.Diagnostics.Debug.WriteLine("ApplicationInitialized");
//When the application is fully initialized, if a new document hasn't been created, then the double clicked file isn't loaded properly yet
if (!newDocumentCreated)
{
//Retrieve the double clicked file path from the application parameters
ESRI.ArcGIS.Framework.ITemplates templates = application.Templates;
doubleClickedFilePath = templates.get_Item(templates.Count - 1);
//If the file path is correct, a new document is created (without user input and with the default template), then the double clicked file is opened
//IApplicationDocument.OpenDocument is the method triggering the event that leads to calling the MobiAnalyst implementation of IPersistStream.Load (in Persist.cs)
if (File.Exists(doubleClickedFilePath))
{
application.NewDocument(false, templates.get_Item(0));
application.OpenDocument(doubleClickedFilePath);
}
}
//Not listening to this event anymore ensures no error will come from this handler later on
(application as IApplicationStatusEvents_Event).Initialized -= new IApplicationStatusEvents_InitializedEventHandler(ApplicationInitialized);
}
}
And a part of the Persist.cs file:
public partial class OurSolver : IOurSolver, INASolver, INASolverSettings2, IPersistStream
{
public void GetClassID(out Guid classID)
{
classID = Type.GetTypeFromProgID("MobiAnalystSolverCOM.MobiAnalystSolver").GUID;
}
public int IsDirty()
{
if (PersistDirty)
return 1;
else
return 0;
}
public void Load(IStream paramStream)
{
// Load properties into a property set
IPropertySet properties = new PropertySetClass();
(properties as IPersistStream).Load(paramStream);
//Get back all loaded values into C# system arrays
object propertyNames;
object propertyValues;
properties.GetAllProperties(out propertyNames, out propertyValues);
System.Array propNameArray = (System.Array)propertyNames;
System.Array propValuesArray = (System.Array)propertyValues;
// Use this property set to populate variables
//For each parameter, check existence first
int index = System.Array.IndexOf(propNameArray, "m_eOutputConnectivity");
if (index >= 0) { outputConnectivity = (OutputConnectivityEnum)(propValuesArray.GetValue(index)); }
//And so forth
// ...
}
}
So now that I have (I hope) clearly explained the context and the problem, my question is: is it possible to load a custom extension generated mxd with our own loading method right from the start, preventing ArcMap to load it any other way ? or to force it to launch from a double clicked file as it launches from the .exe ? Maybe even to correct the file if this is a known problem, but I couldn't find anything clear about it.