我正在開發一個COM代理項目 C中的對象,它將被我的應用程序用於爲需要管理權限的某些操作調用UAC提升對話框。未能在Windows上創建高程COM對象Seven
計劃是讓它導出一個函數,該函數將一個指針指向具有可變數量參數的函數,並在不同的上下文中執行它。這樣,一個應用程序就可以使用這個對象來執行一些具有管理權限的動作,他們所需要做的就是使用該對象並將它傳遞給必須用所述權限執行的函數的指針。
這部分工作,呼籲CoCreateInstance進展良好,函數指針傳遞和我的函數執行。但是,當我使用CoCreateInstanceAsAdmin創建此對象的實例時,會發生問題;這裏是代碼:
HRESULT CoCreateInstanceAsAdmin(HWND hwnd, REFCLSID rclsid, REFIID riid, __out void ** ppv)
{
// Manual implementation of CreateInstanceAsAdmin
CComPtr BindCtx;
HRESULT hr = CreateBindCtx(0,&BindCtx);
BIND_OPTS3 bo;
memset(&bo, 0, sizeof(bo));
bo.cbStruct = sizeof(bo);
bo.grfMode = STGM_READWRITE;
bo.hwnd = hwnd;
bo.dwClassContext = CLSCTX_LOCAL_SERVER;
hr = BindCtx->SetBindOptions(&bo);
if (SUCCEEDED(hr))
{
// Use the passed in CLSID to help create the COM elevation moniker string
CComPtr Moniker;
WCHAR wszCLSID[50];
WCHAR wszMonikerName[300];
StringFromGUID2(rclsid,wszCLSID,sizeof(wszCLSID)/sizeof(wszCLSID[0]));
//Elevation:Administrator!new
hr = StringCchPrintfW(wszMonikerName, sizeof(wszMonikerName)/sizeof(wszMonikerName[0]), L"Elevation:Administrator!new:%s", wszCLSID);
if (SUCCEEDED(hr))
{
// Create the COM elevation moniker
ULONG ulEaten = 0;
ULONG ulLen = (ULONG)wcslen(wszMonikerName);
LPBC pBindCtx = BindCtx.p;
hr = MkParseDisplayName(pBindCtx,wszMonikerName,&ulEaten,&Moniker);
if (SUCCEEDED(hr) && ulEaten == ulLen)
{
// Use passed in reference to IID to bind to the object
IDispatch * pv = NULL;
hr = Moniker->BindToObject(pBindCtx,NULL,riid,ppv);
}
}
}
return hr;
}
調用CoCreateInstanceAsAdmin失敗 「類未註冊」。
目的是通過創建以下注冊表項註冊(這裏的REG文件的主體)
[HKEY_CLASSES_ROOT\COMsurrogate]
@="COMsurrogate Class"
[HKEY_CLASSES_ROOT\COMsurrogate\CurVer]
@="COMsurrogate.1"
[HKEY_CLASSES_ROOT\COMsurrogate\CLSID]
@="{686B6F70-06AE-4dfd-8C26-4564684D9F9F}"
[HKEY_CLASSES_ROOT\CLSID\{686B6F70-06AE-4dfd-8C26-4564684D9F9F}]
@="COMsurrogate Class"
"LocalizedString"="@C:\\Windows\\system32\\COMsurrogate.dll,-101"
"DllSurrogate"=""
[HKEY_CLASSES_ROOT\CLSID\{686B6F70-06AE-4dfd-8C26-4564684D9F9F}\ProgID]
@="COMsurrogate.1"
[HKEY_CLASSES_ROOT\CLSID\{686B6F70-06AE-4dfd-8C26-4564684D9F9F}\VersionIndependentProgID]
@="COMsurrogate"
[HKEY_CLASSES_ROOT\CLSID\{686B6F70-06AE-4dfd-8C26-4564684D9F9F}\InprocServer32]
@="@C:\\windows\system32\COMsurrogate.dll"
"ThreadingModel"="Apartment"
[HKEY_CLASSES_ROOT\CLSID\{686B6F70-06AE-4dfd-8C26-4564684D9F9F}\NotInsertable]
[HKEY_CLASSES_ROOT\CLSID\{686B6F70-06AE-4dfd-8C26-4564684D9F9F}\Programmable]
我想,一些註冊表項丟失 - 這就是結論讀取錯誤信息,當我到達。但是,在瀏覽MSDN和其他站點上的文檔之後,編譯了這個註冊表項列表 - 所以我非常確定沒有錯過任何東西。
我嘗試解決這個問題的事情是通過ATL實現它(例如註冊是自動的)。這是有效的,但問題是我無法將函數指針傳遞給MIDL生成的函數原型。
我嘗試使用VARIANT類型傳遞:
v.vt = VT_PTR;
void (*myptr)(void);
myptr = &DoTheStuff;
v.byref = myptr;
hr = theElevated->CoTaskExecuter(0, v);
的結果我得到 「無效的參數類型」。
難道有人會對這個問題有所瞭解嗎?也許我想通過設計來實現這一點是不可能的?
Yuck。這是否應該作爲一個單獨的過程運行?這是在64位版本的Windows上嗎?空白的DllSurrogate是x64 Win7上的一個問題。沒有任何AppID或代理/存根的標誌。參考:http://msdn.microsoft.com/en-us/library/ms686606%28VS.85%29.aspx – 2010-11-10 13:49:26
Yuck!這件事是一個巨大比例的安全漏洞。如果你需要用提升的權限執行代碼,那麼給它一個固定的函數來執行。讓它執行任意函數指針意味着你可能已經提升了原來的程序! – 2010-11-10 18:58:25
您無法將有意義的指針傳遞給進程外COM對象,但「進程外」位應該將此提示給那個人。在這種情況下,你可以做的最好的事情是擁有一個預先註冊的對象,它可以完成工作,並且可以跨越邊界進行編組,但是最好還是先提升COM對象。至於錯誤,請仔細檢查它是否在HKEY_LOCAL_MACHINE中註冊(導航到Software \ Classes \ CLSID \ ...)而不是HKEY_CURRENT_USER。如果它在當前用戶那麼提升的用戶由於他們在vista +中實現COM的方式而看不到它。 – tyranid 2010-11-10 23:34:30