Link to home
Start Free TrialLog in
Avatar of mridey
mridey

asked on

How to access the interface of an OLE object inside Powerpoint

First a bit of background:

If you launch Microsoft Powerpoint, create an empty presentation, add an empty slide, insert an Object of type "Microsoft Word Document".

You are now in edit mode in the OLE document ie Word. Type a bit of text, just enough to make a line without wrapping to the next line.

Press the escape key. You're back in the powerpoint environment. Click on the object you have just created and resize it down in width using the mouse.

What you can see is that the text is compressed. IE the shape is scaled rather than the object. Use undo to get it back to its previous size.

Now right-click on the object and select Object->Edit. You're back in edit mode. Use the mouse once again to resize the object. What you should see is the text wrapping around to the next line as the control gets smaller. keep it smaller and press escape.

Now you're back in powerpoint with the control smaller and the text wrapped around.

Ok, so all this to make a clear point. There are two sizes when dealing with an object. The Object size and the Shape size. In Edit mode, you resize the object and the text gets reformatted. In normal mode, you resize the shape and the image of the object gets stretched/compressed.

Now let's talk programming:

I need to insert text into a powerpoint presentation programatically. I have this code:

                    shape = shapes->AddOLEObject(
                                                        (float)m_Line_X,   //Left
                                                        (float)m_Line_Y,   //Top
                                                        (float)m_Line_W,   //Width
                                                        (float)m_Line_H,   //Height
                                                        _T(""),              //Classname
                                                        _bstr_t((LPCTSTR)m_Line_FileName),            //FileName
                                                        Office::msoFalse,    //DisplayAsIcon
                                                        _T(""),              //IconFileName
                                                        (long)0,             //IconIndex
                                                        _T(""),              //IconLabel
                                                        Office::msoFalse     //Link
                                                        );
                    if (shape == NULL) return S_FALSE;

This inserts fine but the height and width parameters create a streched/compressed image rather than setting the OLE object size.

So I need to call AddOLEObject with Height and Width set to 0 (that's OK) then I need to resize the Object, not the shape.

Now the question:

Given a PowerPoint::ShapePtr shape, I can call shape->PutHeight() and shape->PutWidth() but that resizes the Shape, how do I resize the object iei how to I simulate programmatically going to "object/Edit" context menu and resizing the object while in edit mode?

I can call shape->OLEFormat and I get a PowerPoint::OLEFormatPtr instance and then I can call Object and I get a IDispatchPtr on the Object (or so I think) but is that the right where and where do I go from there to resize the object ?

Any code, C++, MFC, ATL, VB, VBA will do. I just need so info on the interface(s) to use, I guess.

Thanks
Avatar of DanRollins
DanRollins
Flag of United States of America image

That's an excellent statement of the problem.

Sorry, I'm out of my depth, but nobody else has chimed in yet so... It seems to me that in the non-edit mode, all you are doing is resizing (scaling) the metafile snapshot of the object.  What you want to do is to ask the object to reformat itself and redraw itself with the new size.  Wouldn't something like

   ActiveDocument.Shapes(1).Update()

be part of that?

I just spent a bunch of time messing around with an embedded WordPad object in Ms Word, and there is definitely some non-intuitive stuff going on.  For one thing, the width of the Wordpad doc does not affect the wrap point -- I had to adjust its ruler.  Also, there are a bunch of MsWord settings such as 'clipping' and especially aspect-ratio locking, etc that affect the results.

I saw a snippet of code that might re relevant here:

http://msdn.microsoft.com/library/en-us/office97/html/web/006.asp

    Dim appPPT As PowerPoint.Application
    Set embeddedPres = Worksheets(1).Shapes(1)
    embeddedPres.OLEFormat.Activate
    Set appPPT =   embeddedPres.OLEFormat.Object.Object.Application

But I don't understand it.  I thought it looked intersting.

-- Dan
Avatar of mridey
mridey

ASKER

You're not far off ...

FYI, in my case the object is in a variable called 'shape' so the code would look like shape->OLEFormat->Activate(). This triggers the editing mode (equivalent to selecting Object/Edit in the context menu) but that's where I'm stuck.

Also since I embed Word into Powerpnt, shape->OLEFormat->Object->Application returns a handle to Microsoft Word. Or some code similar to that.

So I'm still searching how to resize that OLE object in edit mode. I think it doesn't matter if it's word or other OLE objects.

Also you said something I might be interested in. You worked on embedding Wordpad in MSWord, I'd like to try that in Powerpoint but I haven't figured how to do it. When I try purely in Powerpoint to insert a Wordpad object, I get an error from Powerpoint telling me that the OLEServer was unable to complete the operation. Did you call AddOLEObject in Word to create Wordpad and if so with what parameters ?

Thanks
I used the MS Word's Insert/Object menu command.  It was in the list of embed-able objects.  Then later I could click on it and select edit object it would bring up a menu-mondified version of WordPad.  There was one limitation:  Both MsWord and WordPad are associatred with RTF files so when I tried to embed an RTF file (Create object from file), it used an embeded Word document rather than an embedded WordPad document.

-- Dan
Avatar of mridey

ASKER

Yes, I have the same problem. I can either call AddOLEObject with a file name and then Microsoft Word is used, or I can call AddOLEObject with a progid "Wordpad.Document.1" and then a Wordpad object is created but empty.
Would you know in VBA how to load a RTF file into a Wordpad object once created ? Have you managed to do this in Word? I'm using Powerpoint but the VB scripting is similar.
No, (other than perhaps re-assigning MsWord's association for RTF files).   I just typed some text.  The buttonbar works and you can make text italics or colored, etc.

-- Dan
Avatar of mridey

ASKER

I've played with the Wordpad object but I realised that it's not transparent and for powerpoint, it's critical so I'm stuck using Word to add RTF content into powerpoint.

Back to square one, I need to resize the Word OLE Object ....

Sorry I don't have the time to test this out.

I would think that to stretch/compress in Powerpoint, you would set the height, top, etc .... properties of the Shape class in Powerpoint.

To get line wrap, my suspicion would be to adjust the height, top, etc ... properties of the OleObject (Object) or failing that, adjust the properties of Application.  I do believe Word (Application class) does have width and "size" properties.

Hope this helps.  Again, sorry I don't have the time to play around with this but it does sound interesting.

Cheers,

Keenez
Avatar of mridey

ASKER

That's where I'm stuck.
I can access the OLE Object using shape.OLEFormat.Object but that returns an 'Object' with no information on the interface. In C++ I get an IDispatch interface.
I'm tryiong to find out how to resize this OLEObject. I don't think it's Word specific. I'm just not familiar with OLE objects in general.
Any clue ?
Even though you get an "Object", I think you can still set its properties (even though no information shows up on the interface because the interface is unknown - it could also have been an Excel object, right???).  The "Object->Application" is really the "Word Application" Object so all of its properties that apply to the Word Application Object should also work with the "Object->Application" object.  I think this is sort of like inheritance even though none of the methods and properties are defined.

Cheers,

Keenez

BTW ... I know I'm mixing VB and C++ lingo so please forgive me.  I originally saw this question in the VB part.
ASKER CERTIFIED SOLUTION
Avatar of keenez
keenez

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of mridey

ASKER

Got it !!!

Thanks to VB and its debugger, I created a small macro in Powerpoint and placed a breakpoint after the call to AddOLEObject. I then used the runtime debugger to browse the properties of the Object available via OLEFormat.Object. Sure enough it's a Word object.

Now the trick to get word to resize rather than the shape to strech is to adjust the PageWidth of the Object since Powerpoint will scale the word object within the Shape rectangle to make the page width fit.

Here's the VBScript code for example:

ActivePresentation.Slides(1).Shapes.AddOLEObject 0, 0, -1, -1, "", "somefile.rtf", msoFalse, "", 0, "", msoFalse
ActivePresentation.Slides(1).Shapes(1).OLEFormat.Activate
ActivePresentation.Slides(1).Shapes(1).LockAspectRatio = msoFalse
ActivePresentation.Slides(1).Shapes(1).ScaleHeight 1, msoTrue, msoScaleFromTopLeft
ActivePresentation.Slides(1).Shapes(1).ScaleWidth 1, msoTrue, msoScaleFromTopLeft
LeftMargin = ActivePresentation.Slides(1).Shapes(1).OLEFormat.Object.PageSetup.LeftMargin
RightMargin = ActivePresentation.Slides(1).Shapes(1).OLEFormat.Object.PageSetup.RightMargin
ActivePresentation.Slides(1).Shapes(1).OLEFormat.Object.PageSetup.PageWidth = 800 + LeftMargin + RightMargin
ActivePresentation.Slides(1).Shapes(1).Width = 800

This resizes the shape AND the word object to 800 pixels.

Also since the Word objects are not documented in the Powerpoint object browser, you can launch word and go to the VBScript window and look at the Object Browser there. That helps a bit too.

Avatar of mridey

ASKER

Thanks for the push in the right direction.
Dang, my last post got dumped somehow.
I found some documentation on the OLEObject object here:

  http://msdn.microsoft.com/library/en-us/rtfbox98/html/vbobjOLEObjectObjectOLEObjectsCollection.asp

It may be applicable.

-- Dan
Avatar of mridey

ASKER

Keenez,

reply to the VB side if you want to collect the rest of the points.

Marc
Avatar of mridey

ASKER

Thanks Dan,

I'll study the use of RichTextBox since I would prefer it to using Word (it's an overkill to just support RTF).
If it's the same control as Wordpad, I may not be able to load my file into it or to get it to display transparent.

Marc
Avatar of mridey

ASKER

And here's the C++ code tested:

//Add a Word object to the slide with a default size.
shape = shapes->AddOLEObject(
                                        (float)m_Line_X,   //Left
                                        (float)m_Line_Y,   //Top
                                        (float)m_Line_W,   //Width
                                        (float)m_Line_H,   //Height
                                        _T(""),              //Classname
                                        _bstr_t((LPCTSTR)m_Line_FileName),            //FileName
                                        Office::msoFalse,    //DisplayAsIcon
                                        _T(""),              //IconFileName
                                        (long)0,             //IconIndex
                                        _T(""),              //IconLabel
                                        Office::msoFalse     //Link
                                        );
if (shape == NULL) return S_FALSE;
shape->Select(Office::msoTrue);

// Resize the OLE object
// This is important, do not just resize the shape, resize the OLE object !!!

shape->PutLockAspectRatio(Office::msoFalse);
PowerPoint::OLEFormatPtr ole;
ole = shape->OLEFormat;
if (ole != NULL)
{
     ole->Activate();
     IDispatchPtr disp;
     disp = ole->Object;
     if (disp != NULL)
     {
          Word::_DocumentPtr word;
          disp->QueryInterface(&word);
          if (word != NULL)
          {
               Word::PageSetupPtr pagesetup;
               pagesetup = word->PageSetup;
               if (pagesetup != NULL)
               {
                    float left = pagesetup->GetLeftMargin();
                    float right = pagesetup->GetRightMargin();
                    pagesetup->PutPageWidth(((float)m_Line_W) + left + right);
               }
          }
     }
}
presentation->Application->ActiveWindow->Selection->Unselect();

shape->PutLockAspectRatio(Office::msoFalse);
shape->ScaleHeight(1,Office::msoTrue,Office::msoScaleFromTopLeft);
shape->PutWidth(m_Line_W);

shape = NULL;
Avatar of mridey

ASKER

and on a minor note, accessing the OLE Object and activating it, selecting slides and so on is only possible if the presentation is visible otherwise you get a bunch of COM exception so create the Powerpoint application object like this:

// Create the Powerpoint object
hr = app.CreateInstance(_T("PowerPoint.Application"),NULL,CLSCTX_LOCAL_SERVER);
if (FAILED(hr)) return hr;

app->PutVisible(Office::msoTrue);
app->PutWindowState(PowerPoint::ppWindowMinimized);

I'm glad I could help.
-- Dan
I don't know if this will work or not but try commenting out the ole->activate and see if everything works.  If it does, then you won't need to make it visible.  I'm not quite sure if you need to activate it to load up the appropriate application.

Cheers,

Keenez
Avatar of mridey

ASKER

I tried it but since I'm accessing the Word interface and the Word Object and I'm asking Word to change the content, I need to activate the object. Until it is activated, Word is not launched.
It's a minor inconvenience, I just launch powerpoint it minimized.
which way do u think is the best to do it..anyone