[英]Accessing Excel.Application objects of other excel instances in Running Object Table in C#
[英]Problems accessing the Running Object Table
在我的程序中,我使用運行對象表(ROT)來確保只運行一個程序實例。 由於我從一位不幸離開公司的開發人員那里“繼承”了這段代碼,我是解決問題的窮人。 代碼工作正常,但我們有3個客戶(39,000個)將獲得AccessDeniedException
。 每個客戶都以用戶模式運行軟件。
有什么建議可能是錯的嗎?
bool retVal = false;
IMoniker[] arrMoniker = new IMoniker[1];
IBindCtx bindCtx = null;
string displayName;
int hResult;
int mkSys;
Guid clsidRot;
bool guidCompare = false;
IntPtr number = IntPtr.Zero;
moreObjectsListed = false;
objectFromRot = null;
try
{
// check the objects in the running object table for fitting the specified class id
while ((retVal == false) && (0 == enumMoniker.Next(1, arrMoniker, number)))
{
hResult = CreateBindCtx(0, out bindCtx);
if (hResult == 0)
{
arrMoniker[0].IsSystemMoniker(out mkSys);
if (mkSys == 4)
{
try
{
// the display name is the class id of the object in the table
// --> AccessDeniedException raises here <--
arrMoniker[0].GetDisplayName(bindCtx, null, out displayName);
clsidRot = new Guid(displayName.Substring(1));
guidCompare = clsidRot.Equals(clsid);
}
catch(Exception) {}
// an object with fitting class id was found
if (guidCompare == true)
{
rot.IsRunning(arrMoniker[0]);
rot.GetObject(arrMoniker[0], out objectFromRot);
retVal = true;
}
}
}
}
}
finally
{
if (arrMoniker[0] != null)
{
moreObjectsListed = true;
Marshal.ReleaseComObject(arrMoniker[0]);
}
if (bindCtx != null)
{
Marshal.ReleaseComObject(bindCtx);
}
}
編輯:這是在ROT中注冊對象的請求代碼:
internal static extern uint RegisterActiveObject([MarshalAs(UnmanagedType.IUnknown)]object pIUnknown, ref Guid refclsid, uint flags, out uint pdwRegister);
internal const uint ActiveObjectStrong = 0;
...
NativeMethods.RegisterActiveObject(this, ref guid, NativeMethods.ActiveObjectStrong, out this.runningObjectTableRegisteredId);
編輯2:
首先是所有調查員的一個大EXCUSE,我們沒有得到AccessDeniedException它是一個System.UnauthorizedAccessException(HRESULT:0x80070005(E_ACCESSDENIED))。
其次是“調查員”Ken Brittain問題的答案: - SharePoint 不在混合中 - 我很想從ROT請求正確的對象 - 另一個提示可能是3個問題中的1個(除了39,000個正常工作)正在運行WTS上的應用程序(Windows終端服務器)
編輯3:
這是一個例外的堆棧跟蹤:(我已經翻譯了堆棧跟蹤,因為它是在德國機器上)
System.UnauthorizedAccessException: Access denied (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
at System.Runtime.InteropServices.ComTypes.IRunningObjectTable.EnumRunning(IEnumMoniker& ppenumMoniker)
at Datev.Framework.DirectStart.RunningObjectTableClientManager..ctor()
堆棧跟蹤的其余部分在我們的代碼中。 在這種情況下可標記的是在RunningObjectTableClientManager的構造函數中引發異常。 這是構造函數的代碼:
private IRunningObjectTable rot;
private IEnumMoniker enumMoniker;
public RunningObjectTableClientManager()
{
int retVal = GetRunningObjectTable(0, out this.rot);
if (retVal == 0)
{
rot.EnumRunning(out this.enumMoniker);
}
}
根據我的經驗,GUID碰撞的可能性雖然可能不太可能,但是沒有進行調查。 我采取的第一個軌道是查看可能導致AccessDeniedException
原因。 從那里向后工作,您可以看到GetDisplayName沒有顯式拋出此異常(或返回任何類似的異常)。
那是什么? 您的代碼似乎是在C#中。 除非我錯誤地使用來自C#的COM將通過主互操作。 只有兩(2)個interops暴露了我可以找到的IMoniker
接口:
你在談論一個應用程序,所以我的直覺告訴我你正在使用運行時版本。 看着這些電話我找不到任何形式的Access Denied HRESULT
或者類似的東西。 VisualStudio
互操作確實提到了有關訪問和信任的以下內容: 使用部分受信任的代碼中的庫 。 這聽起來像一條路徑,如果你正在使用Visual Studio interops,它將適用。
如果您正在使用mscorlib.dll
程序集中包含的運行時服務命名空間(根據此頁面, .NET Framework程序集可由部分受信任的代碼調用標記為可調用的部分受信任的代碼),則說明似乎不適用。
那么現在怎么辦? 我搜索了AccessDeniedException
,發現除了在MSDN中標記為過時的Microsoft.Office.Server.ApplicationRegistry.Infrastructure.AccessDeniedException類之外,沒有任何受支持的實現。 該類是在SharePoint 2010類庫下提交的。
所以這是我的問題:你使用哪個互操作? SharePoint是否在混合中? 我之前說過GUID碰撞沒有被懷疑,但現在我在質疑這個假設。 你是從ROT請求正確的對象嗎? 此對象是否在另一個進程(不是你的進程)下運行?
從該站點看 ,它可能是由於注冊表設置或由於在表中注冊的對象的安全設置:
Check "HKLM\\Software\\Network OLE\\Enabled". Fail the request if zero. Check "HKCU\\Software\\Network OLE\\Enabled". Fail the request if zero. Before performing any operation against a ROT entry (ie, IRunningObjectTable::Revoke, IRunningObjectTable::IsRunning, IRunningObjectTable::GetObject, IRunningObjectTable::NoteTimeChange, IRunningObjectTable::GetTimeOfLastChange, or when including an entry in an IEnumMoniker::Next of an IEnumMoniker returned from IRunningObjectTable::EnumRunning), check the call against the SECURITY_DESCRIPTOR available from IRunningObjectTable::Register. This will be either the value returned by the object's IActivationSecurity::GetSecurityDescriptor at the time of IRunningObjectTable::Register or will have been taken from "HKCU\\Software\\Network OLE\\DefaultROTSecurity" or "HKLM\\Software\\Network OLE\\DefaultROTSecurity" at the time of IRunningObjectTable::Register if the object did not support IActivationSecurity.
也許這不是您正在尋找的答案,但是繼承了這段代碼后,您是否已經停下來質疑這是否適合您的用例? 這是我第一次看到C#應用程序使用Com Interop來防止多個應用程序實例。 我從來沒有與Com有過良好的經歷,並且發現了類似的無法解釋或未記錄的例外情況。
為什么不看一下防止多個應用程序實例的替代技術呢? 我在過去的解決方案中使用了Mutex,從來沒有遇到過問題。 雖然我沒有過去的代碼,但是在stackoverflow之前已經多次討論過這個問題,其中有一些非常好的答案已經過同行評審和社區編輯。
例如, 在C#中使用Global Mutex有什么好的模式? '有一個很好的社區編輯答案,似乎考慮到各種奇怪的球競爭條件和線程/進程終止以及潛在的安全問題。
因此,我的建議是遠離Com Interop並轉而使用Mutex實現。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.