implement OleLoadPictureFile

Jeremy Drake wine at
Mon Nov 17 18:07:54 CST 2008

On Tue, 18 Nov 2008, Michael Karcher wrote:

> > Note that the IDL defines the VARIANT parameter as "optional".  If the
> > filename is not specified, you should pass a NULL stream to
> > OleLoadPicture.
> How do I know? I think you shouldn't have told these detail. I might
> know what happens if I pass in VARIANTs of type VT_ERROR or VT_NULL,
> like lplpdispPicture is unchanged, set to NULL or Windows crashes. But
> there seems no legal way for me to find out what happens inside
> Microsoft's oleaut32.dll. If it were an inter-dll call, relay or snoop
> might bring me to the conclusion that you are right, but I just pretend
> I never read that. Just write a couple of tests for different variant
> types (VT_NULL, VT_ERROR, VT_BSTR). If they crash on Windows, put them
> in an if(0) block with an appropriate comment.

Right.  Oops.  I may actually have mis-remembered that, so it's good you
didn't read that :P.  I thought I had read on the MSDN that NULL stream
meant that it would create an empty IPicture, but checking again it
doesn't.  I should have said that the unspecified parameter would result
in an empty picture, and let you go from there.  BTW, this case is tested
in my tests...  It may have been the " This is equivalent to calling
OleCreatePictureIndirect(NULL, ...)followed by IPersistStream::Load" from
the MSDN page that I was misremembering.

> > Also, there is an OleLoadPictureFileEx, which adds the same 3 additional
> > paramters as OleLoadPictureEx adds over OleLoadPicture.  You can probably
> > guess how that works...
> Do a three-way-merge of OleLoadPicture to OleLoadPictureEx and
> OleLoadPicture to OleLoadPictureFile and you arrive at
> OleLoadPictureFileEx, probably.

Or call one from the other and save the code duplication.

> > For the non-Ex versions, it may help you to know about the constant
> > LP_DEFAULT in olectl.h, which means "do the default thing" to the
> > extra params of the Ex version.
> MSDN documents LP_DEFAULT only for the palette in OleLoadPictureFileEx,
> but follows your points in the documentation for OleLoadPictureEx. It
> might have been that the the desired size should be just zero (which
> LP_DEFAULT happens to be) to get the default.
> > As far as the "standard OLE file stream object", if you know of one please
> > let me know.  AFAIK, it is a pretty major oversight in the OLE IStream
> > APIs that there is not a function to create an IStream given a file (name
> > or handle).
> Oops. I just assumed there was one, but you seem to be right. One could
> try whether the Windows FileMoniker works on objects that don't
> implement IPersistFile but just IPersistStream and thus
> IMoniker::BindToObject from the FileMoniker does what we want. But this
> is a very dangerous approach, as you can't tell BindToObject the CLSID
> to use, but just the IID you want, and the Wine implementation will
> happily activate and load *any* file type you pass in, and notice after
> loading that the object loaded does not support the IPicture interface.
> I don't know what ugly things can happen on IPersistStream::Load given
> some CLSIDs no one thinks about in the moment (maybe XML documents that
> cause an internet access to fetch the DTD), but I think some Media
> Player/Outlook security vulnerabilities we had some years ago are
> related to implementing things like this (that was IIRC attachments of
> the name ".WAV" that are associated with windows media player; windows
> media player checked magic numbers in that file, completely forgetting
> about the file a wave file finding "MZ" in the beginning and acting
> "appropriately). You will see whether OLELoadPictureFile does that if
> you do a relay trace with native oleaut32 and builtin ole32, as the
> CreateFileMoniker call would cross DLL boundaries. Please don't tell me
> that you know that Microsoft did it another way, even if you probably
> do.

OK, I won't.

> > I've always had to roll my own wrapper around the file APIs,
> > or use a hack like the one in OleLoadPictureFilePath.
> You probably mean OleLoadPictureFile. I am not going to look at your
> patch, so I don't know what hack you meant. If the hack was your idea,
> feel free to describe it. If the hack is inspired by the disassembly,
> please don't tell any Wine developer how that hack worked.

No, I meant a hack in OleLoadPicturePath, as implemented in wine.  I
surely would not mention a hack I derived from the disassembly.

> > Quite.  Also in olectl.h are the error codes that these functions
> > could return.  Unfortunately, I think it will be necessary to make some
> > sort of manual translation between the GetLastError returns from the
> > file APIs and these errors.  Without spelling out the mappings from the
> > disassembly, it will probably be nearly impossible to get all of the cases
> > exactly right.
> You shouldn't even have told that the mapping is done directly in
> OleLoadPictureFile and not some lower layer invoked by
> OleLoadPictureFile, except if you are sure from a relay trace. Of
> course, if Wine developers find that *somewhere* error codes seem to be
> mapped, they are free to do the mapping in OleLoadPictureFile.

I'm pretty sure I didn't tell you that.  I meant that there must be
somewhere the mapping is done, and that I didn't see any obvious numerical
relationships betweeen the codes that would imply some sort of
mathematical transformation (hence, manual).

> > I think that, as long as you are familiar with the APIs for dealing with
> > VARIANTs, this should be a very simple task.
> You might want to do the following test, if possible: Put the image into
> a file named "33" (without extension or anything) and call
> OleLoadPictureFile with a variant containing "33" as string value to
> verify that OleLoadPictureFile is able to load images without extension
> based on their magic bytes. If that works, retry with a variant
> containing the integer "33". If it still works, chances are *VERY* high
> that we need VariantChangeType. If it fails, we know that
> VariantChangeType is not the way to go.

Right.  I was planning to do this.

> > I would provide details
> > about how to deal with the VARIANT, but it may be misinterpreted as
> > knowledge gained from the disassembler.  So I'll just leave you with a
> > couple of links to MS docs.
> If you tell me whether VariantChangeType should be used here or not, it
> *is* knowledge gained from the disassembler, so it is exactly right you
> don't tell me that. Write good testcases instead that make me infer how
> to implement it. Thanks for the pointers to MSDN. I didn't know about

The VT_ERROR/DISP_E_PARAMNOTFOUND is one of the test cases I have

More information about the wine-devel mailing list