Recently I've been looking at how the IDispatch works. Below is an example of how an automation client may call a method of an automation server object, which implements IDispatch:
HRESULT hresult;
IDispatch * pdisp = (IDispatch *)NULL;
DISPID dispid;
OLECHAR * szMember = "color";
// Code that sets a pointer to the dispatch (pdisp) is omitted.
hresult = pdisp->GetIDsOfNames(
IID_NULL,
&szMember,
1, LOCALE_SYSTEM_DEFAULT,
&dispid);
pdisp->Invoke(
dispid,
...
)
When implementing a server, this suggests to me that you could implement GetIDOfNames as:
HRESULT GetIDsOfNames(
REFIID riid,
LPOLESTR *rgszNames,
UINT cNames,
LCID lcid,
DISPID *rgDispId
){
rgDispId = 10;
return S_OK;
};
In this way we tell the client, essentially, that all method calls are okay, and all method calls will call method with DISPID==10.
myObject->a();
myObject->ab();
myObject->abc();
myObject->abcd();
//^^ Are all valid and will all call DispID 10.
So my question is, Can we somehow store the name that was called, such that our DispID 10 method, will know which method is being called?
Note: The ultimate goal of this is to build a COM server which has the ability to be a COM server for other COM clients, which might lack the capability/knowledge of being COM servers themselves.
Related
I have created this function in app delegate file. I want to call a function of app delegate in callback.
Is there any way please suggest.
-(void) monitor{
FSEventStreamRef stream = FSEventStreamCreate(NULL,
&feCallback,
&cntxt,
pathsToWatch,
kFSEventStreamEventIdSinceNow,
1,
kFSEventStreamCreateFlagWatchRoot );
}
static void feCallback(ConstFSEventStreamRef streamRef,
void* pClientCallBackInfo,
size_t numEvents,
void* pEventPaths,
const FSEventStreamEventFlags eventFlags[],
const FSEventStreamEventId eventIds[])
{
NSLog(#"The file changed!");
// need to to call app delegate function
}
As FSEventStreamCreate is only available on macOS, you may do it the following way:
// call this in init of your app delegate
FSEventStreamContext cntxt = {0, (__bridge void *)(self), NULL, NULL, NULL};
// call FSEventStreamCreate as in your code
// keep a reference to the stream so you can stop and start it later
Then in your callback the AppDelegate will be in:
YourAppDelegateClass* appDele = (__bridge YourAppDelegateClass*)pClientCallBackInfo;
The whole mechanism for FSEvents is quite complex, we had to schedule it on the right run loop and work with ARC and type casting. The callback is outside of ObjectiveC, you won't be able to use Cocoa but only CFString and other Core Foundation types. It's also helpful to not only read the documentation but look at the FSEvents.h within the Framework (context menu on any of the functions and then Jump to definition: There is more to read than in the documentation). And depending on your distribution, also work with the App Store Sandbox and security scoped bookmarks.
I have a task, that includes grabbing some text that lie inside a third party ActiveX component that's embedded inside Internet Explorer webpage using "OBJECT id=S_DetectCom codeBase=xxxx.cab ..."
i have the .cab file having the activeX dlls(4 dlls)
i'm not familiar with OLE and activeX, but doing some research and trials , i could get an IDispatch to ActiveX object by the following steps :-
1- get handle to IE tab having class "Internet Explorer_Server"
2- get IHTMLDocument2 using ObjectFromLresult
3- get IHTMLElementCollection from IHTMLDocument2
4- get IDispatch from IHTMLElementCollection with element of name "S_DetectCom"
what lies in mind, is getting the typelib from DLLs to know the methods,... and their parameters
by try and error find which dll in the cab is embedded into that web page
right now i'm stuck, as i don't know how to reach Invoke to call methods from IDispatch i got
i'd appreciate if somebody could help me with ideas and implementation below is the code part that gets IDispatch from hwnd
int msg;
DWORD lRes = NULL ;
IHTMLDocument2 *pDoc= NULL;
IHTMLElementCollection *pElement = NULL ;
IHTMLInputTextElement *ppvInput ;
IDispatch *ppvDisp;
ITypeInfo *TypeInfo = NULL ;
VARIANT ObjName ;
_variant_t index = NULL;
HRESULT hr;
LRESULT lr ;
UINT cntTypeInf= NULL ;
long pItems = NULL;
BSTR pszOptText[200];
OleInitialize(NULL);
msg = RegisterWindowMessage(L"WM_HTML_GETOBJECT");
lr = SendMessageTimeout(hwnd, msg, 0, 0, SMTO_ABORTIFHUNG, 1000, &lRes);
hr = ObjectFromLresult((LRESULT)lRes, IID_IHTMLDocument2, 0, (void**)&pDoc);
hr = pDoc->get_all( &pElement );
BSTR BStrObjName = _com_util::ConvertStringToBSTR((const char *)"S_DetectCom");
ObjName.vt = VT_BSTR ;
ObjName.bstrVal = BStrObjName ;
hr = pElement->item( ObjName , index , &ppvDisp );
if (hr == S_OK && ppvDisp)
{
hr = ppvDisp->GetTypeInfoCount(&cntTypeInf);
hr = ppvDisp->GetTypeInfo(NULL , NULL , &TypeInfo);
// to do here
}
If you are using WM_HTML_GETOBJECT to get the HTML document you are definitely not an expected caller, since you are out of the current thread. The ActiveX is probably not thread-safe.
Anyway, if you can get a proxy plugin to execute in the IE's Tab thread (probably by installing a BHO), here are the steps to access the ActiveX's properties and methods. It is for accessing an Adobe Flash ActiveX but you can change file name in the import statement to import interfaces from the ocx file.
If I were you instead of trying to use COM directly I'd write a FireBreath plugin, which would then work on firefox, etc as well as IE (it implements an ActiveX Control as well as a NPAPI plugin).
That will do all of the IDispatch stuff for you, and then you can tie into the lower level classes (look at IDispatchAPI) to get the direct COM handle for the element after you grab it and do a queryinterface for the interface you need.
If nothing else you could use the IDispatchAPI class as an example of how to access IDispatch methods.
I've encountered a problem with the XBAP Script Interop feature that was added in WPF 4. It involves a combination of the following:
Accessing members of a script object from .NET
Running .NET code in a callback invoked from JavaScript
Running in Partial trust
This seems to be a "pick any two" scenario... If I try and do all three of those things, I get a SecurityException.
For example, combining 1 and 3 is easy. I can put this into my hosting web page's script:
function ReturnSomething()
{
return { Foo: "Hello", Bar: 42 };
}
And then in, say, a button click handler in my WPF code behind, I can do this:
dynamic script = BrowserInteropHelper.HostScript;
if (script != null)
{
dynamic result = script.ReturnSomething();
string foo = result.Foo;
int bar = result.Bar;
// go on to do something useful with foo and bar...
}
That works fine, even in a partial trust deployment. (I'm using the default ClickOnce security settings offered by the WPF Browser Application template in Visual Studio 2010, which debugs the XBAP as though it were running in the Internet zone.) So far, so good.
I can also combine 2 and 3. To make my .NET method callable from JavaScript, sadly we can't just pass a delegate, we have to do this:
[ComVisible(true)]
public class CallbackClass
{
public string MyMethod(int arg)
{
return "Value: " + arg;
}
}
and then I can declare a JavaScript method that looks like this:
function CallMethod(obj)
{
var result = obj.MyMethod(42);
var myElement = document.getElementById("myElement");
myElement.innerText = "Result: " + result;
}
and now in, say, a WPF button click handler, I can do this:
script.CallMethod(new CallbackClass());
So my WPF code calls (via BrowserInteropHelper.HostScript) my JavaScript CallMethod function, which in turn calls my .NET code back - specifically, it calls the MyMethod method exposed by my CallbackClass. (Or I could mark the callback method as a default method with a [DispId(0)] attribute, which would let me simplify the JavaScript code - the script could treat the argument itself as a method. Either approach yields the same results.)
The MyMethod callback is successfully called. I can see in the debugger that the argument passed from JavaScript (42) is getting through correctly (having been properly coerced to an int). And when my method returns, the string that it returns ends up in my HTML UI thanks to the rest of the CallMethod function.
Great - so we can do 2 and 3.
But what about combining all three? I want to modify my callback class so that it can work with script objects just like the one returned by my first snippet, the ReturnSomething function. We know that it's perfectly possible to work with such objects because that first example succeded. So you'd think I could do this:
[ComVisible(true)]
public class CallbackClass
{
public string MyMethod(dynamic arg)
{
return "Foo: " + arg.Foo + ", Bar: " + arg.Bar;
}
}
and then modify my JavaScript to look like this:
function CallMethod(obj)
{
var result = obj.MyMethod({ Foo: "Hello", Bar: 42 });
var myElement = document.getElementById("myElement");
myElement.innerText = "Result: " + result;
}
and then call the method from my WPF button click handler as before:
script.CallMethod(new CallbackClass());
this successfully calls the JavaScript CallMethod function, which successfully calls back the MyMethod C# method, but when that method attempts to retrieve the arg.Foo property, I get a SecurityException with a message of RequestFailed. Here's the call stack:
at System.Security.CodeAccessSecurityEngine.Check(Object demand, StackCrawlMark& stackMark, Boolean isPermSet)
at System.Security.CodeAccessSecurityEngine.Check(PermissionSet permSet, StackCrawlMark& stackMark)
at System.Security.PermissionSet.Demand()
at System.Dynamic.ComBinder.TryBindGetMember(GetMemberBinder binder, DynamicMetaObject instance, DynamicMetaObject& result, Boolean delayInvocation)
at Microsoft.CSharp.RuntimeBinder.CSharpGetMemberBinder.FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion)
at System.Dynamic.DynamicMetaObject.BindGetMember(GetMemberBinder binder)
at System.Dynamic.GetMemberBinder.Bind(DynamicMetaObject target, DynamicMetaObject[] args)
at System.Dynamic.DynamicMetaObjectBinder.Bind(Object[] args, ReadOnlyCollection`1 parameters, LabelTarget returnLabel)
at System.Runtime.CompilerServices.CallSiteBinder.BindCore[T](CallSite`1 site, Object[] args)
at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
at XBapDemo.CallbackClass.MyMethod(Object arg)
That's the whole trace as reported by the exception. And above CallbackClass.MyMethod, Visual Studio is showing two lots of [Native to Managed Transition] and an [AppDomain Transition] - so that's the whole of the stack. (Apparently we're on a different thread now. This callback is happening on what the Threads panel describes as a Worker Thread - I can see that the Main Thread is still sat inside my WPF button click handler, waiting for the call to the JavaScript CallMethod function to return.)
Apparently the problem is that the DLR has ended up wrapping the JavaScript object in the ComBinder which demands full trust. But in the earlier case where I called a JavaScript method via HostScript and it returned me an object, the HostScript wrapped it in a System.Windows.Interop.DynamicScriptObject for me.
The DynamicScriptObject class is specific to WPFs XBAP script interop - it's not part of the usual DLR types, and it's defined in PresentationFramework.dll. As far as I can tell, one of the jobs it does is to make it possible to use C#'s dynamic keyword to access JavaScript properties without needing full trust, even though those properties are being accessed through COM interop (which usually requires full trust) under the covers.
As far as I can tell, the problem is that you only get these DynamicScriptObject wrappers for objects that are returned from other DynamicScriptObject instances (such as HostScript). With callbacks, that wrapping doesn't seem to occur. In my callback, I'm getting the sort of dynamic wrapper C# would normally give me in plain old COM interop scenarios, at which point, it demands that I have full trust.
Running it with full trust works fine - that would be the "1 and 2" combination from the list above. But I don't want to have full trust. (I want 1, 2, and 3.) And outside of callback situations, I can access JavaScript object members just fine. It seems inconsistent that I can access a JavaScript object just fine most of the time, but accessing an identical object in a callback is forbidden.
Is there a way around this? Or am I doomed to run my code in full trust if I want to do anything interesting in a callback?
I haven't done XBAP in a while, but I am curious if it is the dynamic type that could be causing the issue. Try changing the dynamic parameter to type object and see if it will work.
[ComVisible(true)]
public class CallbackClass
{
public string MyMethod(object arg)
{
return "Arg is: " + arg.ToString();
}
}
I am developing a COM surrogate object in C, it will be used by my applications to call the UAC elevation dialog for certain actions that require administrative rights.
The plan is to make this it export a function that takes a pointer to a function with a variable number of arguments and executes it in a different context. This way, an application can use this object to perform some actions with admin rights, all they need to do is use that object and pass it a pointer to the function that has to be executed with said rights.
This works partially, calling CoCreateInstance goes fine, the function pointer is passed and my function is executed.
However, when I create an instance of this object using the COM Elevation Moniker archive, and Microsoft's sample code for CoCreateInstanceAsAdmin, problems occur.
Here is the code:
HRESULT CoCreateInstanceAsAdmin(HWND hwnd, REFCLSID rclsid, REFIID riid, __out void ** ppv)
{
// Manual implementation of CreateInstanceAsAdmin
CComPtr<IBindCtx> 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<IMoniker> 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;
}
Calling CoCreateInstanceAsAdmin fails with "Class not registered".
The object is registered by creating the following registry keys (here's the body of the REG file)
[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]
I suppose that some registry entries are missing - that's the conclusion I reach when reading the error message. However, this list of registry keys was compiled after exploring the documentation on MSDN and other sites - so I am pretty certain that nothing was missed.
Among the things I've tried to solve this is to implement it via ATL (such that registration is automated). That works, but the problem is that I can't pass a funtion pointer to the MIDL generated function prototype.
I tried to pass it using the VARIANT type:
v.vt = VT_PTR;
void (*myptr)(void);
myptr = &DoTheStuff;
v.byref = myptr;
hr = theElevated->CoTaskExecuter(0, v);
as result I get "Invalid argument type".
Could someone shed some light on the subject? Perhaps what I am trying to achieve is not possible by design?
I believe the issues you are having is by design and that the intent of window's security improvements were to help avoid potential security risks.
Microsoft doesn't really want you to elevate your privileges if it can stop you from doing so. Executing arbitrary functions as a privileged user shouldn't be easy in any way if Windows is even a decently secured system. You might could try impersonating a different user using tokens and getting better access that way, but even then it would be a stretch. If I remember right, user impersonations won't even guarantee that you'll get full access. The best solution in this case is just to use the super user account and properly request the correct privileges.
I have written a webmethod that returns the list of the Users althought the service works fine, when I call it from the page the methods in the webservice have return type as void.
What you might be thrown off by is that web service calls in Silverlight must be handled asynchronously.
When you define a WebMethod, say for example you have one called DoWork on a Class called WorkMan. Your code in the Silverlight would end up looking like:
WorkManSoapClient client = new WorkManSoapClient();
client.DoWorkCompleted += new EventHandler<DoWorkCompletedEventArgs>(this.DoWorkCompleteHandler); // where DoWorkCompletedHandler handles the callback.
Then you call your actual method and allow the callback to process the result.
client.DoWorkAsync();
If your webmethod returns a value, your EventArg object will have a Result property that you can leverage for the result.
One final note: a personal stylistic thing but I like lambda expressions rather than generating a whole new method for the callback. I might write something like the following:
WorkManSoapClient client = new WorkManSoapClient();
client.DoWorkCompleted += (s,e) => {
if(e.Result != null){
object foo = e.Result;
}
};
client.DoWorkAsync();