Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / Interop / August 2008

Tip: Looking for answers? Try searching our database.

Marshal.QueryInterface returning E_NOINTERFACE

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Heath Kelly - 09 Jul 2007 18:12 GMT
I use the ReadClassStg API call to find out what application owns a given
storage.  In my test case it is Word.

//4) Determine the CLSID of the COM object that owns the IStorage.
Guid clsid = new Guid();
ReadClassStg(storage, ref clsid);

I then create a instance of Word as follows:

//5) Use the CLSID to instantiate the COM object using interop.
Type type = Type.GetTypeFromCLSID(clsid);
Object comObj = Activator.CreateInstance(type);

This works fine and I can see that an instance of Word is loaded into my
object.

//6 Return a pointer to the objects IUnknown interface.
IntPtr pIUnk = Marshal.GetIUnknownForObject(comObj);
IntPtr p;
Int32 result = Marshal.QueryInterface(pIUnk, ref clsid, out p);

Why is Marshal.QueryInterface always returning the hresult E_NOINTERFACE?  p
is always 0.  Not sure what I am doing wrong.  Can anyone help?

Heath.
Michael Phillips, Jr. - 12 Jul 2007 00:26 GMT
> Int32 result = Marshal.QueryInterface(pIUnk, ref clsid, out p);

> Why is Marshal.QueryInterface always returning the hresult E_NOINTERFACE?
> p
> is always 0.  Not sure what I am doing wrong.  Can anyone help?

You need to request an interface that is exposed by this COM object.

For example, you may request an IStream interface, an IDataObject, etc.
"ref clsid" is not a valid IID of an Interface.

>I use the ReadClassStg API call to find out what application owns a given
> storage.  In my test case it is Word.
[quoted text clipped - 22 lines]
>
> Heath.
Heath Kelly - 12 Jul 2007 12:30 GMT
Thanks Michael your advice has taken me a step closer to my goal.   However,
I'm still not sure if I am doing this correctly.  I can now load the COM
object from the storage but when it comes to saving it out to file I get an
E_FAIL.

//6) Get a pointer to the IPersistStorage Interface.
Guid IID_IPersistStorage = typeof(IPersistStorage).GUID;
IntPtr pIUnk = Marshal.GetIUnknownForObject(comObj);
IntPtr ptrStorage;
Int32 r = Marshal.QueryInterface(pIUnk, ref IID_IPersistStorage, out
ptrStorage);
//r = S_OK

//7) Load the COM object from the storage.
IPersistStorage per =
(IPersistStorage)Marshal.GetObjectForIUnknown(ptrStorage);
r = per.Load(Marshal.GetIUnknownForObject(storage));
//r = S_OK

//8) Get a pointer to the IPersistFile Interface.
Guid IID_IPersistFile = typeof(IPersistFile).GUID;
IntPtr ptrFile;
r = Marshal.QueryInterface(pIUnk, ref IID_IPersistFile, out ptrFile);
//r = S_OK

//9) Save the file to disk.
IPersistFile perFile = (IPersistFile)Marshal.GetObjectForIUnknown(ptrFile);
r = perFile.Save(@"D:\Data\Result\Output.doc", true);
//r = E_FAIL

Any further advice?

Regards,
Heath

> > Int32 result = Marshal.QueryInterface(pIUnk, ref clsid, out p);
>
[quoted text clipped - 33 lines]
> >
> > Heath.
Heath Kelly - 12 Jul 2007 14:22 GMT
I've since realised that Office documents are saving correctly and that it is
only certain other file types held within the Storage that don't save
properly.  Probably something to do with their host application.  Will look
into it further.

> Thanks Michael your advice has taken me a step closer to my goal.   However,
> I'm still not sure if I am doing this correctly.  I can now load the COM
[quoted text clipped - 68 lines]
> > >
> > > Heath.
Michael Phillips, Jr. - 12 Jul 2007 14:34 GMT
It is not clear to me what your goal is.

A compound document file is laid out as a file system with directories as
storage objects and files as streams.

The storage objects are not real directories.  They represent individual com
storage objects.
The files are not real files they are data represented as a stream.

> //9) Save the file to disk.
> IPersistFile perFile =
> (IPersistFile)Marshal.GetObjectForIUnknown(ptrFile);
> r = perFile.Save(@"D:\Data\Result\Output.doc", true);
> //r = E_FAIL

What are you trying to save?

If for example, there was an embedded object such an excel spreadsheet.
You would instantiate the excel object and load its storage via the
IPersistStorage interface.

You would then create a new compound document via StgCreateDocfile and then
use OleSave to save the excel storage
object and all of its associated streams.

The clsid of the com object is written to the storage object.  It is that
clsid that you use to instantiate the com object.

Each embedded object in your Word document has a different format.  Some
objects are packaged like embedded pdf files.
For pdf files the above will not work.  You would have to extract the
"Contents" stream and use the windows file system api
to write the file.
Heath Kelly - 16 Jul 2007 18:06 GMT
Michael, my goal is to extract all documents embedded within any given
compound document.  Here is the current revision of my code:

//6) Get a pointer to the IPersistStorage Interface.
//comObj = Word, Excel, etc.
Guid IID_IPersistStorage = typeof(IPersistStorage).GUID;
IntPtr pIUnk = Marshal.GetIUnknownForObject(comObj);
IntPtr ptrStorage;
Int32 r = Marshal.QueryInterface(pIUnk, ref IID_IPersistStorage, out
ptrStorage);

//7) Load the COM object from the storage.
IPersistStorage per =
(IPersistStorage)Marshal.GetObjectForIUnknown(ptrStorage);
r = per.Load(Marshal.GetIUnknownForObject(store));

//8) Create new storage and save to disk.
IStorage temp;
StgCreateDocfile(@"D:\Data\Result\Output" + count,    
STGM.READWRITE|STGM.SHARE_EXCLUSIVE|STGM.CREATE, 0, out temp);
OleSave(per, temp, false);

I understand that this approach will not work for all documents.  For
non-office documents I have a different approach where I where I write the
"CONTENTS" stream to the file system.  This works for PDFs for example.

The above approach works perfectly for all office document types except
Excel.  Excel documents are created, however they seem to be lacking some
information and will not open natively.  I can "fix" them by dragging them
into IE, where they can be viewed, and then saving them.  This work around is
not acceptable to me.  

Excel storages are associated with the clsid of Excel.Application.  However,
I can't get an IPersistStorage interface for this object, instead I need to
use the clsid of Excel.Sheet to get any joy here at all.  Wondering if my
problem is somehow related.

Regards,
Heath.

> It is not clear to me what your goal is.
>
[quoted text clipped - 29 lines]
> "Contents" stream and use the windows file system api
> to write the file.
Michael Phillips, Jr. - 17 Jul 2007 01:13 GMT
> The above approach works perfectly for all office document types except
> Excel.  Excel documents are created, however they seem to be lacking some
> information and will not open natively.  I can "fix" them by dragging them
> into IE, where they can be viewed, and then saving them.  This work around
> is
> not acceptable to me.

It works for excel also.  However the excel spreadsheet is marked as hidden.

There are two ways to solve the problem.

1) Use OLE Automation to create an "Excel.Application" ole object and get
the global Windows collection and mark the hidden window as "visible".
   This approach is not very fast as the Excel application must be present
on the system and it takes somes time to load.  Using IDispatch is
cumbersome.
2) Use the IStream to find the "WINDOW1" record in the "Workbook" stream.
The record is defined as 0x003D.  Once found you load the record.
   The record has an options bit field.
   Here is the structure:
   typedef struct _WINDOW1_RECORD
   {
          //short window1Marker;  // Should be 0x003D
          //short recordSize;   // size of record in bytes,
biff2-biff4(8bytes),biff5-biff8(18bytes)
          short hpos;
          short vpos;
          short height;
          short width;
          short options;  // bit 1, 0 - visible, 1 - hidden
          short idxActiveWkSheet;
          short idxVisibleTab;
          short selectedWkSheet;
          short widthTabBar;
   } WINDOW1_RECORD;
   It is a "short".  If you set it to 0,  and then save the stream, the
excel spreadsheet will be visible.

> Michael, my goal is to extract all documents embedded within any given
> compound document.  Here is the current revision of my code:
[quoted text clipped - 74 lines]
>> "Contents" stream and use the windows file system api
>> to write the file.
Punit Gajera - 26 Aug 2008 17:22 GMT
hello,
i m punit gajera, jr. programmer
i m working on structure compound office objects.

i want to extract compound objects just like i have 123.xls in it 2 zip file and 1 .doc file is thr

i want to extract all the files with in 123.xls..

same functionality in all office documents..

can u help me??

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.