|
Hi All,
I have posted this message earlier on the ASP.Net forum, I did not notice there is a separate forum for Co Componenets. However I am moving the post to here, please have a look, any help would be much appreciated.
I am using a third Party Com Component in my ASP.NET application. I dont have much experience with COM Components and I think I have messed up here. Please help.
The Com component has a method which looks like following in the ILDASM:
.method public hidebysig newslot specialname virtual
instance class [stdole]stdole.IPicture
marshal( interface )
get_Preview([in] float64 rWorldMinX,
[in] float64 rWorldMinY,
[in] float64 rWorldMaxX,
[in] float64 rWorldMaxY,
[in] int32 dwPicWidth,
[in] int32 dwPicHeight,
[in] int32 PicType) runtime managed internalcall
In my code behind, I am using
object ComObjLateBound;
Type ComObjType;
ComObjType= Type.GetTypeFromCLSID(new Guid("{89251546-3F1C-430D-BA77-F86572FA4EF6}"));
ComObjLateBound= Activator.CreateInstance(ComObjType);
double viewMaxX = (double)ComObjType.InvokeMember("ViewMaxX", BindingFlags.Default | BindingFlags.GetProperty, null, ComObjLateBound, new object[] { });
double viewMaxX = (double)ComObjType.InvokeMember("ViewMaxY", BindingFlags.Default | BindingFlags.GetProperty, null, ComObjLateBound, new object[] { });
double viewMaxX = (double)ComObjType.InvokeMember("ViewMinX", BindingFlags.Default | BindingFlags.GetProperty, null, ComObjLateBound, new object[] { });
double viewMaxX = (double)ComObjType.InvokeMember("ViewMinY", BindingFlags.Default | BindingFlags.GetProperty, null, ComObjLateBound, new object[] { });
int imagewidth, imageheight, pictype;
imagewidth = 1280; imageheight = 800; pictype = 1;
object[] previewDetails = new object[7];
previewDetails[0] = viewMinX;
previewDetails[1] = viewMinY;
previewDetails[2] = viewMaxX;
previewDetails[3] = viewMaxY;
previewDetails[4] = imagewidth;
previewDetails[5] = imageheight;
previewDetails[6] = pictype;
IPicture picture = (IPicture)ComObjType.InvokeMember("get_Preview", BindingFlags.Default | BindingFlags.InvokeMethod, null, ComObjLateBound, previewDetails);
this fails with a COM Exception like
{"Unknown name. (Exception from HRESULT: 0x80020006 (DISP_E_UNKNOWNNAME))"}
with an ErrorCode of -2147352570 if that means something.
Now this is strange, because the exception type and Error Code remains exactly the same if I use any name instead of "get_Preview".
the COM component also has a Preview Property which looks the following in ILDASM:
.property class [stdole]stdole.IPicture Preview(float64,
float64,
float64,
float64,
int32,
int32,
int32)
I have also tried to use this property to get the IPicture value like:
IPicture picture = (IPicture)ComObjType.InvokeMember("Preview", BindingFlags.Default | BindingFlags.GetProperty, null, ComObjLateBound, previewDetails);
But it also falis with a message that Exception has been thrown by the target of an invocation.
Please note, I am not able to use early binding on this component as it gives me an error message -
Unable to cast COM object of type '<>' to interface type '<>'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{}' failed due to the following error: No such interface supported.
I think I am doing something wrong here. Can you please point out what it is?
Thanks in advance.
|
|
|
|
|
Hi,
you wrote that you look at the COM component with ILDASM - but you probably examined the generated CLR-interop rather than the real COM component. Since you can't do early binding with that interop, it must have been already messed up, so I would not rely on the information provided by it.
To see what's really provided by the COM object you could have a look at the type library, using e.g. OLE-COM Object Viewer (OleView.exe) from Windows SDK.
|
|
|
|
|
tom-englert wrote: Since you can't do early binding with that interop, it must have been already
messed up, so I would not rely on the information provided by it.
Thanks tom-englert for your response. Sorry for replying late. I was working on a different module during this time.
you are right, I have examined the CLR-interop version of the component in ILDASM. But I wont say the component has been messed up as I can achieve desired results from the component with the exact same codes in case of a winforms application. In winforms both early binding and latebinding is working for me. I am also able to talk to the Component through Javascript block. But I need this component to run on my codebehind.
I've tried installing OleView previously, but I am using Win7 in my development environment, It seems OleView is not supported in Win 7.
|
|
|
|
|
If that works in WinForms, then you maybe have a threading problem.
The main thread of WinForms runs in STA, and if your object is designed for STA too ("ThreadingModel=Apartment" in the registry) everything is fine.
But if you call that code from an MTA thread, the interface for the object has to be marshaled, which I assume is not supported by your interface.
|
|
|
|
|
Thanks Tom,
I checked the registry, and you are right again. The value of ThreadingModel is defined as Apartment in there. So does that mean there is no way I can access the component in an asp.net codebehind? is there a workarround for this issue?
|
|
|
|
|
|
Hi again,
I have finally got this COM object to work, but some problem still remains. I changed the code as following:
...
using System.Threading;
namespace...
protected void Button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(STAOperation));
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
}
public void STAOperation()
{
CSViewerRL.ViewerClass csv = new ViewerClass();
csv.Open(filePath, 0, 0);
}
this code works, but once in a while, I am getting a strange error while debugging, which states AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
generally the app runs fine the first time I try to debug, but this error occures mostly on the second or third time I press f5 from my VS while the ASP.Net server is still running. and generally it goes away if I stop the server and run again. I think this problem is because of this new STA thread. Maybe I am not handling the new thread correctly. Or there is some other thing I should look into? Can someone point out whatshould I do under this circumstance?
|
|
|
|
|
Maybe you should limit the objects lifetime to the lifetime of the thread. Currently the object is destroyed at any time by the GC in the GC thread.
Try calling Marshal.ReleaseComObject before the thread ends, to guarantee a deterministic lifetime of the object.
|
|
|
|
|
nilarya wrote: I have also tried to use this property to get the IPicture value like:
IPicture picture = (IPicture)ComObjType.InvokeMember("Preview", BindingFlags.Default | BindingFlags.GetProperty, null, ComObjLateBound, previewDetails);
But it also falis with a message that Exception has been thrown by the target of an invocation.
It's right way, but you should use the reversed order of arguments.
previewDetails[6] = viewMinX; and so on.
With best wishes,
Vita
|
|
|
|
|
Hi,
I am trying to create a 64 bit COM server in visual studio 2008 on win7 x64 machine.
Here are the steps I am following:
1. Open Visual Studio.
2. Create ATL Project
3. On ATL Project wizard in application settings select Executable(EXE) then Finish
4. Then Build->Configuration Manger change Platform to x64
5. Build the project.
6. On output window everything seems ok but if I take a look at buildLog.htm then there is a error 'errro PRJ0019: A tool returned an error code from "Performing registration"'.
Even I tried to register from command prompt (with admin rights) but it is not registering. Neither error message nor success message.
|
|
|
|
|
Make sure that the DllRegisterServer function exists and is exported. For a function to be exported, it must have an entry in the .def file.
Note: In Visual Studio 2005, the VC++ compiler does not add the .def file name in the project settings by default. Provide a name to the .def file in the project settings. I am not sure if this has changed in Visual Studio 2008.
"Don't confuse experts with facts" - Eric_V
|
|
|
|
|
Try opening Visual Studio with elevated privileges.
|
|
|
|
|
Using Excel object library, I have written an application which capture all events.
I have an issue in event called SheetCalculate.
SheetCalcuate event returns IDispatch*. From IDispatch* , I am trying to get sheet name or function cell change for which event is triggered.
Please guide me if any one worked on this.
Thanks in advance.
|
|
|
|
|
You can use QueryInterface on the IDispatch interface to get at the desired interface -
IDesiredInterface* pI;
pDispatch->QueryInterface(IID_IDesiredInterface, (LPVOID*)&pI); Or you can use the CComQIPtr smart pointer -
CComQIPtr<IDesiredInterface> pI(pDispatch);
|
|
|
|
|
This is a small project skeleton (VC2008 project)
http://www.autohotkey.net/~T800/CopyPath_test.zip
for a menu shell extension.
The problem is that InsertMenu in QueryContextMenu returns TRUE but fails(?), inserting only one menu item when it's supposed to insert two.
No matter what I do I get only one menu item. I tried combinations with menu separators to no avail.
I don't know what's wrong, as far as I can tell everything should work fine.
But then again, I made stupidly simple mistakes before.
Have a look at the code inside zip, I am going blind with this one.
------------------------------------------------------------------------------
Nevermind, I got it, I needed to provide unique verbs for menu entries inside IShellExtInit::GetCommandString() , like it's explained here.
|
|
|
|
|
i have MSHTML::IHTMLDocument2Ptr pointer loaded with html document.there i can see all style sheets,images,iframe object. iframe object again will contain "src" attributes with source location. i want all iframe or frame objects "src" attributes from html document....
please help me
|
|
|
|
|
After you get all the frame elements using the get_frames method, iterate through each of the frames using the IHTMLFramesCollection2::item method. Query the IHTMLElement on the returned IDispatch pointer. Then use the IHTMLElement::getAttribute method to get the value of the src attribute.
|
|
|
|
|
Hi, all!
I had met a problem when I developing an addin for Excel. I want to create a new OLE control which developed by myself into Excel sheet. But an error occurred when I add it.
I had try to do this by two ways. One is to call the method "Add" of the class "OLEObjects". Another is to call the method "AddOLEObject" of the class "Shapes". Both are all failure.
When I call OLEObject.Add, an exception was throwed which said a com_error occured in Excel. The code I used is as below:
CComPtr<MSEXCEL::_Workbook> spBook;
HRESULT hr = m_spAppExcel->get_ActiveWorkbook(&spBook);
if(spBook == NULL)
{
return;
}
CComPtr<MSEXCEL::Sheets> spSheets;
spBook->get_Sheets(&spSheets);
CComPtr<MSEXCEL::OLEObjects> spObjs;
CComVariant vtIndex(1);
spSheets->get_Item(vtIndex,(IDispatch**)&spObjs);
VARIANT vtResult;
VariantInit(&vtResult);
CComVariant ClassType(_MYPROGID);
CComVariant vtFalse(VARIANT_FALSE);
CComVariant left,top;
int x,y;
GetInsertPosX(x,y);
left=x; top = y;
CComVariant vEmpty(DISP_E_PARAMNOTFOUND, VT_ERROR);
CComPtr<MSEXCEL::_OLEObject> pObj;
try
{
pObj = spObjs->Add(ClassType,vEmpty,vtFalse,vtFalse,vEmpty,vEmpty,vEmpty,left,top,g_iCtrlInitWidth,g_iCtrlInitHeight);
if(pObj == 0)
{
return;
}
}
catch(...)
{
DWORD dwError = GetLastError();
TCHAR info[10];
wnsprintf(info,10,L"%x",dwError);
MessageBox(NULL,info,L"Error",MB_OK);
return;
}
When I call Shapes.AddOLEObject, the calling is success. But the value it returned can't be converted to the pointer I need. The code is as below:
CComPtr<MSEXCEL::_Workbook> spBook;
HRESULT hr = m_spAppExcel->get_ActiveWorkbook(&spBook);
if(spBook == NULL)
{
return;
}
CComPtr<MSEXCEL::_Worksheet> spSheet;
spBook->get_ActiveSheet((IDispatch**)&spSheet);
CComPtr<MSEXCEL::Shapes> spShapes;
spSheet->get_Shapes(&spShapes);
ATLASSERT(spShapes);
VARIANT vtResult;
VariantInit(&vtResult);
CComVariant ClassType(_MYPROGID);
CComVariant vtFalse(VARIANT_FALSE);
CComVariant left,top;
int x,y;
GetInsertPosX(x,y);
left=x; top = y;
CComVariant vEmpty(DISP_E_PARAMNOTFOUND, VT_ERROR);
CComPtr<MSEXCEL::Shape> spCtrl;
spCtrl = spShapes->AddOLEObject(ClassType,vEmpty,vEmpty,vtFalse,vEmpty,0,vEmpty,left,top,g_iCtrlInitWidth,g_iCtrlInitHeight);
if(spCtrl == 0)
{
return;
}
CComPtr<MSEXCEL::OLEFormat>spOleFormat;
spOleFormat = spCtrl->get_OLEFormat();
IDispatch *pObj;
pObj = spOleFormat->get_Object();
CComQIPtr<ICASign> cpCASign(pObj);
if(cpCASign == 0)
{
return;
}
When I use the second way, I had found the constructor of CCASign had been executed. But when constructor is return, the value of cpCASign is still zero. I think maybe ICASign isn't matched with CCASign. But this object can be inserted into Word correctly. When adding this object into word, the same procedure is done. The value after converted is correct. So I don't know the reason of this error. I hope someone could be kind to help me. Thank you!
There is some white cloud floating on the blue sky. That's the landscape I like.
|
|
|
|
|
CComPtr<MSEXCEL::OLEFormat>spOleFormat;
spOleFormat = spCtrl->get_OLEFormat();
IDispatch *pObj;
pObj = spOleFormat->get_Object();
CComQIPtr<ICASign> cpCASign(pObj);
change that to ...
CComPtr<MSEXCEL::OLEFormat>spOleFormat;
spOleFormat = spCtrl->get_OLEFormat();
CComPtr<IDispatch> pObj;
pObj = spOleFormat->get_Object();
CComPtr<ICASign> cpCASign;
HRESULT hr=pObj.QueryInterface(&cpCASign);
and at least you'll have a error code to work with
|
|
|
|
|
Problem still exist. The value of hr is "E_NOINTERFACE". I feel very strange that the same operation can completed within Word. I check the interface declaration of CCASign many times. No mistake was found. Please continue to help me! Thank you!
There is some white cloud floating on the blue sky. That's the landscape I like.
|
|
|
|
|
what's the object written using?
if it's ATL, use the _ATL_DEBUG_QI to watch for it being queried
Not done much with Excel or Word, but it wouldn't surprise me if they use separate threading models, and the E_NOINTERFACE you're getting is because it can't get to an IMarshall interface
have a look at http://msdn.microsoft.com/en-us/library/ms687205(v=vs.85).aspx[^]
|
|
|
|
|
My control is written in C++. I had read the article you recommand. My control's ThreadModel is Single-Threaded apartment. I had tried the other key-word. Only "Apartment" and "Both" can work. I think maybe I hadn't implement some methods, so the conversion is failure. I hope you can list all methods I must implement. Thank you!
There is some white cloud floating on the blue sky. That's the landscape I like.
|
|
|
|
|
ok - first things first - you need to find out if this is the problem
If you're using ATL, enable the _ATL_DEBUG_QI define for the project - this will show you what your project is being queried for (as long as you are running your object under the debugger)
If you're not using ATL, you'll have to change your QueryInterface method so it prints out interfaces that are requested, that it doesn't support
|
|
|
|
|
![Go to Parent](https://www.codeproject.com/App_Themes/CodeProject/Img/arrow-up24.png) I had add _ATL_DEBUG_QI define in my project. Then message below is output:
CComClassFactory - IUnknown
CComClassFactory - IClassFactory2 - failed
CComClassFactory - IClassFactory
CCASign - IDispatch
CCASign - IConnectionPointContainer
CCASign - IProvideClassInfo
CCASign - IConnectionPointContainer
CCASign - IProvideClassInfo
CCASign - IOleObject
CCASign - IOleControl
CCASign - {049948D1-5686-11CF-8E0D-00AA00A74C5C} - failed
CCASign - IPersistStreamInit
CCASign - IConnectionPointContainer
CCASign - IProvideClassInfo
CCASign - IOleContainer - failed
CCASign - IDataObject
CCASign - IPersistPropertyBag - failed
CCASign - IRunnableObject - failed
ATL: IDataObjectImpl::QueryGetData not implemented.
_CrtDbgReport: String too long or IO ErrorCCASign - IRunnableObject - failed
CCASign - {049948D1-5686-11CF-8E0D-00AA00A74C5C} - failed
CCASign - {049948D1-5686-11CF-8E0D-00AA00A74C5C} - failed
CCASign - IRunnableObject - failed
ATL: IDataObjectImpl::QueryGetData not implemented.
_CrtDbgReport: String too long or IO ErrorCCASign - IRunnableObject - failed
CCASign - IPersistStreamInit
These message are output when calling Shapes.AddOleObject. I check the interface marked as fail. Such interfaces are not needed to implement except "{049948D1-5686-11CF-8E0D-00AA00A74C5C}". I don't know what interface is "{049948D1-5686-11CF-8E0D-00AA00A74C5C}". My own interface is registered already. And its CLSID isn't {049948D1-5686-11CF-8E0D-00AA00A74C5C}. Is this the reason of problem?
There is some white cloud floating on the blue sky. That's the landscape I like.
|
|
|
|
|
your addoleobject call is succeeding
You need to look at the debug trace when you call
HRESULT hr=pObj.QueryInterface(&cpCASign);
because that's the call that is failing
|
|
|
|
|