我找到了一个解决方案,它遍历运行时对象表 (ROT) 以获取与 Visio 文档 (".vdx") 对应的所有名字对象并获取它们对应的 VSO.Document 对象(使用 VSO=Microsoft.Office.Interop.Visio);使用 VSO.Document 对象,我可以从 Document.Application 属性中获取 VSO.Application 对象。
从 Andrew Baker 的这篇文章:http ://www.vbusers.com/codecsharp/codeget.asp?ThreadID=69&PostID= 1,我创建了一个 ROTUtil 实用程序/帮助类:
/// <summary>
/// The COM running object table utility class.
/// </summary>
public class ROTUtil
{
#region APIs
[DllImport("ole32.dll")]
private static extern int GetRunningObjectTable(int reserved,
out UCOMIRunningObjectTable prot);
[DllImport("ole32.dll")]
private static extern int CreateBindCtx(int reserved,
out UCOMIBindCtx ppbc);
[DllImport("ole32.dll", PreserveSig = false)]
private static extern void CLSIDFromProgIDEx([MarshalAs(UnmanagedType.LPWStr)] string progId, out Guid clsid);
[DllImport("ole32.dll", PreserveSig = false)]
private static extern void CLSIDFromProgID([MarshalAs(UnmanagedType.LPWStr)] string progId, out Guid clsid);
[DllImport("ole32.dll")]
private static extern int ProgIDFromCLSID([In()]ref Guid clsid, [MarshalAs(UnmanagedType.LPWStr)]out string lplpszProgID);
#endregion
#region Public Methods
/// <summary>
/// Converts a COM class ID into a prog id.
/// </summary>
/// <param name="progID">The prog id to convert to a class id.</param>
/// <returns>Returns the matching class id or the prog id if it wasn't found.</returns>
public static string ConvertProgIdToClassId(string progID)
{
Guid testGuid;
try
{
CLSIDFromProgIDEx(progID, out testGuid);
}
catch
{
try
{
CLSIDFromProgID(progID, out testGuid);
}
catch
{
return progID;
}
}
return testGuid.ToString().ToUpper();
}
/// <summary>
/// Converts a COM class ID into a prog id.
/// </summary>
/// <param name="classID">The class id to convert to a prog id.</param>
/// <returns>Returns the matching class id or null if it wasn't found.</returns>
public static string ConvertClassIdToProgId(string classID)
{
Guid testGuid = new Guid(classID.Replace("!", ""));
string progId = null;
try
{
ProgIDFromCLSID(ref testGuid, out progId);
}
catch (Exception)
{
return null;
}
return progId;
}
/// <summary>
/// Get a snapshot of the running object table (ROT).
/// </summary>
/// <returns>A hashtable mapping the name of the object in the ROT to the corresponding object
/// <param name="filter">The filter to apply to the list (nullable).</param>
/// <returns>A hashtable of the matching entries in the ROT</returns>
public static Hashtable GetActiveObjectList(string filter)
{
Hashtable result = new Hashtable();
int numFetched;
UCOMIRunningObjectTable runningObjectTable;
UCOMIEnumMoniker monikerEnumerator;
UCOMIMoniker[] monikers = new UCOMIMoniker[1];
GetRunningObjectTable(0, out runningObjectTable);
runningObjectTable.EnumRunning(out monikerEnumerator);
monikerEnumerator.Reset();
while (monikerEnumerator.Next(1, monikers, out numFetched) == 0)
{
UCOMIBindCtx ctx;
CreateBindCtx(0, out ctx);
string runningObjectName;
monikers[0].GetDisplayName(ctx, null, out runningObjectName);
if (filter == null || filter.Length == 0 || runningObjectName.IndexOf(filter) != -1)
{
object runningObjectVal;
runningObjectTable.GetObject(monikers[0], out runningObjectVal);
result[runningObjectName] = runningObjectVal;
}
}
return result;
}
/// <summary>
/// Returns an object from the ROT, given a prog Id.
/// </summary>
/// <param name="progId">The prog id of the object to return.</param>
/// <returns>The requested object, or null if the object is not found.</returns>
public static object GetActiveObject(string progId)
{
// Convert the prog id into a class id
string classId = ConvertProgIdToClassId(progId);
UCOMIRunningObjectTable prot = null;
UCOMIEnumMoniker pMonkEnum = null;
try
{
int Fetched = 0;
// Open the running objects table.
GetRunningObjectTable(0, out prot);
prot.EnumRunning(out pMonkEnum);
pMonkEnum.Reset();
UCOMIMoniker[] pmon = new UCOMIMoniker[1];
// Iterate through the results
while (pMonkEnum.Next(1, pmon, out Fetched) == 0)
{
UCOMIBindCtx pCtx;
CreateBindCtx(0, out pCtx);
string displayName;
pmon[0].GetDisplayName(pCtx, null, out displayName);
Marshal.ReleaseComObject(pCtx);
if (displayName.IndexOf(classId) != -1)
{
// Return the matching object
object objReturnObject;
prot.GetObject(pmon[0], out objReturnObject);
return objReturnObject;
}
}
return null;
}
finally
{
// Free resources
if (prot != null)
Marshal.ReleaseComObject(prot);
if (pMonkEnum != null)
Marshal.ReleaseComObject(pMonkEnum);
}
}
然后这是我的类中获取实例的方法:
/// <summary>
/// This strategy of getting the VSO.Application instances uses the appropriate file monikers
/// from the Runtime Object Table to get the VSO.Document object and hence the VSO.Document.Application
/// property.
/// </summary>
/// <param name="allInstances"></param>
protected void GetInstancesROTStrategy(IList<VSO.Application> allInstances)
{
// Iterate through all the objects in the ROT
string filter = ".vdx";
Hashtable runningObjects = ROTUtil.GetActiveObjectList(filter);
Hashtable appInstances = new Hashtable();
// Display the object ids
foreach (DictionaryEntry de in runningObjects)
{
// get visio document file monikers
string progId = de.Key.ToString();
object getObj = ROTUtil.GetActiveObject(progId);
if (getObj != null)
{
// try to cast the object to a VSO.Document
VSO.Document doc = getObj as VSO.Document;
if (doc != null)
{
VSO.Application app = doc.Application;
// only add to results IList if not duplicate
if (!appInstances.ContainsKey(app.WindowHandle32))
{
appInstances.Add(app.WindowHandle32, app);
allInstances.Add(app);
}
}
}
}
}