Solved

Launching Winword

Posted on 1999-01-28
26
1,192 Views
Last Modified: 2012-06-27
Hi,

I'm trying to open a Winword session from C++ with the following code:

if (bNewSession)
{      
 sTemplate = "\"" + sTemplate + "\"";  // for long filenames
 if (bHide)
   hErrorCode = ShellExecute ( hParent, "open", "winword.exe", sTemplate, NULL, SW_MINIMIZE);
 else
   hErrorCode = ShellExecute ( hParent, "open", "winword.exe", sTemplate, NULL, SW_SHOWNORMAL);
}else
 if (bHide)
   hErrorCode = ShellExecute ( hParent, "open", sTemplate, NULL, NULL,SW_MINIMIZE);
 else
   hErrorCode = ShellExecute ( hParent, "open", sTemplate, NULL, NULL,  SW_SHOWNORMAL);

It is working fine except in the case:
bNewSession = true and bHide = true

I have a Word session running, and I am expecting to load the template in the current session but in background.
I also tried  SW_SHOWNA without any success.
The idea is to call winword to print a document within an application.
I also tried GetActiveWindow and SetActiveWindow with no more success.

Any idea?
Serge
 
0
Comment
Question by:SergeD
  • 10
  • 5
  • 5
  • +3
26 Comments
 

Author Comment

by:SergeD
ID: 1185385
Sorry Lads,

you understood I made a mistake. The incorrect case is:
- bNewSession = False
- bHide = True

Sorry for that
Serge
0
 
LVL 22

Expert Comment

by:nietod
ID: 1185386
The last parameter is used only when a new application is started.  That parameter is used in the application's start-up information.   (and the application may ignore it.)   If the application is already running, the parameter is going to be ignored.    

what is it that you are hoping to achieve?  perhaps there is another way.
0
 

Author Comment

by:SergeD
ID: 1185387
I have a Word template that contains macros for editing, printing, ....

From an application, I'd like to launch Winword on a default template (with the macros) and if the required action is EDIT, then I'm expecting Winword to be in the foreground, and if the action is PRINT, then I'm expecting Winword to be in the background.

The different macros are used to replace some fields in the document and then wait for user interaction for EDIT action. Of course, the Minimise action could be include in the macro on PRINT action, but I'd prefer not to see Word in this case instead of to see the macros doing their job, and then to minimse word.

I know it looks a bit complicated, but...

Thanx
Serge

0
 
LVL 22

Expert Comment

by:nietod
ID: 1185388
And what exactly is the problem that you are experiencing?  Is a running copy of word becoming activated (which you don't want)?  It is that an active copy is not becoming inactive?
0
 

Author Comment

by:SergeD
ID: 1185389
Well...

I'd like the active copy of Word to process in background for printing.

0
 
LVL 22

Expert Comment

by:nietod
ID: 1185390
But what does that mean?  Do you want the active word window to minimize?  What does it do now, does it become active and then prints?  
0
 

Author Comment

by:SergeD
ID: 1185391
At the moment, the word session is activated, displayed on the foreground, and the document is processed (fields replaced, and document printed). When the printing process is finished the Word session stays there and my calling application is behind.
I'd like to the same process, but to be able to continue my stuff in my application. In the meantime, the document could be processed in the back.

Kind of spooler...
0
 
LVL 22

Expert Comment

by:nietod
ID: 1185392
I don't think you can prvent that, but you can use WaitForInputIdel() to make sure that the target application (word) is done with its initialization (makes sure it already has been activated and moved to the foreground.),  then try to reactivate your own window.  

If you want to use WaitForInputidle, you will need the process handle.  For that you will have to use ShellExecuteEx().
0
 
LVL 2

Expert Comment

by:wpd
ID: 1185393
Basically, you have very little control over the application when it is started with ShellExecute(Ex). So you have 2 solutions :



1. Use CreateProcess which will give you better control :



/* begin code */

PROCESS_INFORMATION pi;

STARTUP_INFO si;



memset(&pi,0,sizeof(pi));

memset(&si,0,sizeof(si));

si.cb = sizeof(si);

si.dwFlags = STARTF_USESHOWWINDOW; // whatever you like

si.wShowWindow = SW_SHOW; // SW_MINIMIZE, etc...

if (CreateProcess(NULL, cmdLine, NULL, NULL, FALSE,    

        NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi))

          WaitForInputIdle(pi.hProcess, INFINITE);        

/* end code */



2. But I'd strongly suggest launching Word as an OLE server, instead. It may sound scary at first (if you're not used to it), but I think it makes perfect sense considering your problem. That way, you'll have full control over what's happening.



The pseudo-code below will show you how :



HRESULT    hr;

CLSID      clsId;

LPUNKNOWN  punk;

LPDISPATCH pdisp = NULL;



// Get CLSID for WORD OLE Server

CLSIDFromProgID(OLESTR("WORD.Application"), &clsId);

// see if server's already running

hr = GetActiveObject (cldid, NULL, &punk);

// if hr == NOERROR, then the app is running

if (FAILED(hr)) {

  // Launch process through OLE

  hr = CoCreateInstance (clsId, NULL, CLSCTX_SERVER,

                     IID_IUnknown, (void FAR * FAR *)&punk);

}

// at that point, punk contains a valid IUnknown for word

punk->QueryInterface(IID_IDispatch, (void FAR * FAR *)&pdisp);

// not needed anymore

punk->Release();

// At that point, Word has started but is invisible



OK. Now you have "pdisp", which is the IDispatch for the Word application. This interface gives you access to the complete object model, as described in the docs or the Type Library. "pdisp" is the C++ equivalent of "app" in the following VB statement :



Dim app as Object

Set app = CreateObject("Word.Application")



Once you're here, you can :



Show/Hide the application : app.Visible = True/False

(VB Code, same in C++ but longer !)

Open a file : app.Documents.Open ("foo.doc")

Print the current document : app.Printout (...)

Quit the app : app.quit



You could even do your text editing from your application, without the user ever seeing it.



NB : If you're using MFC, you have wrapper classes that makes the code much easier to read, and shorter too.



Hope it helps.


0
 
LVL 10

Expert Comment

by:viktornet
ID: 1185394
Just use SetForgroundWindow(This);

-Viktor
--Ivanov
0
 

Author Comment

by:SergeD
ID: 1185395
Thanx wpd for the code.

It works fine but unfortunately it is not what I'm looking forward. I don't want to create a new process, but using the current session (I don't want to launch Winword each single time I have a document to process.). For the OLE server, it is surely a good solution, but honnestly it is too scary. I'm not enough familiar in C++ to go in that way.

As Nietod suggested, I have tried the following functions:
Response = ShellExecuteEx( &sei );
wResponse = WaitForInputIdle( sei.hProcess, INFINITE);
Response = SetForegroundWindow (hParent);

It could work, but the WaitForInputIdle stop its execution when Word is loaded, and unfortunately not when the template is loaded. So, what is happening is:
- I press the PRINT button on my App
- Word is displayed on screen (I supposed I cannot avois that)
- My App is displayed 1 seconde (SetForegroundWindow)
- Word goes back in front to load the document
Final State: Word is in front and my App lost the focus.

I could of course add a Wait(X_Secondes), but the processing time of my document is not  constant and it is not really nice.

I'm still investigate the Waitxxx functions.

Thank you anyway
Serge
0
 
LVL 1

Expert Comment

by:jim_pettinato
ID: 1185396
Wouldn't this work just as you wish if you used the "print" action instead of the "open" action?

0
 
LVL 10

Expert Comment

by:viktornet
ID: 1185397
jim_pettinato, even if you use the "print" operation (that's what actually you gotta do) WinWord will still open and your app would be behind... That's why you need to work out the WAIT function that will wait till you get evetything done and you can then set the focus on your app...
0
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 

Author Comment

by:SergeD
ID: 1185398
Victornet,

you are right, but the WaitForIdle funtion waits for Winword to be loaded, not for the document. So, that means:
1. the focus is on MyApp
2. Winword goes in front for loading
3. MyApp goes back in front once Word is loaded
4. Winword goes back in front when the document is loaded

I should apply the WaitForIdle on Word and on its child.
Thanx anyway
Serge
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1185399
Use something like this...

ShellExecute(0, "print", "ThePathToTheFile", NULL, NULL, SW_SHOWNORMAL);
//do some waiting....
//SetForegroundWindow(MyHandle);
0
 

Author Comment

by:SergeD
ID: 1185400
Sure that I could wait for X seconds before to set the App in the foreground.
But the documents to process might be from different sizes and is it reasonable to slow the process of small documents?
I would prefer to get a solution like:
- Wait for Word Idle
- Get Word child
- Wait for Word child Idle
- Set MyAPP in the foreground

Is there a way to do that?

Ta,
Serge
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1185401
I'm sure there is a way, but not that i know of :(

well you could try this...

read the name of the file of the DOC...

e.g.

test.doc

then wait until there is a window with the caption that read something like this...

WinWord - test.doc

or something like that.. you just see how it writes it on the caption.. then get that handle and wait for the idle state of that window...

I hope this helps. I can't think of any other way... :(

-Viktor
--Ivanov
0
 
LVL 2

Expert Comment

by:wpd
ID: 1185402
I still think the OLE technique I proposed would have been much less trouble, more reliable, and quicker, too :)
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1185403
if the OLE technique works, then it's okay to use it, but i don't think it's quicker,,,,

-Viktor
--Ivanov
0
 
LVL 1

Expert Comment

by:calixto
ID: 1185404
You can use OLE to access the WinWord (I supposed that you are using MFC, some changes are needed to run without MFC)

TRy the following code:

{
   COleVariant var1( "My template.dot" );
   COleVariant var2( (short)false, VT_BOOL );

   Application app;

   COleException e;
   CLSID clsid;
   LPUNKNOWN lpUnk;
   LPDISPATCH lpDispatch;

   if ( CLSIDFromProgID( OLESTR( "Word.Application" ), &clsid ) != NOERROR )
      return;

   if ( GetActiveObject( clsid, NULL, &lpUnk ) == NOERROR )
   {
      HRESULT hr = lpUnk->QueryInterface( IID_IDispatch, (LPVOID*)&lpDispatch );
     
      lpUnk->Release();

      if ( hr == NOERROR )
         app.AttachDispatch( lpDispatch, TRUE );
   }

   if ( app.m_lpDispatch == NULL && !app.CreateDispatch( clsid, &e ) )
      return;

   Documents docs( app.GetDocuments() );

   // create a document from a template
   //
   docs.Add( var1, var2 );

   _Document doc = app.GetActiveDocument();

   COleVariant fname( "my document.doc" );
   COleVariant none( DISP_E_PARAMNOTFOUND, VT_ERROR );

   doc.SaveAs( fname, none, none, none, none, none, none, none, none, none,none );
   
   app.Quit( none, none, none );
}

The classes Application, Documents, _Document can be imported from msword8.tbl located in the Office directory.

The documentation of this classes are the same of the Word VBA.

0
 

Author Comment

by:SergeD
ID: 1185405
Sorry,

WPD already tried this answer. Thanx anyway.
I'll give the points to WPD who gave me the most complete answer.

Ta
Serge

0
 
LVL 22

Expert Comment

by:nietod
ID: 1185406
Then you need to reject the current answer.
0
 
LVL 2

Expert Comment

by:wpd
ID: 1185407
Calixto's solution is the same as mine except that it needs MFC, type libs, etc. I've followed this thread with a lot of interest but I can't help thinking that OLE is your only way out. I'll re-post the solution if you want :)
0
 

Author Comment

by:SergeD
ID: 1185408
Sorry Lads,

I sent the comment and forgot to tick "Reject"
Here you go

Thanx
Serge
0
 
LVL 2

Accepted Solution

by:
wpd earned 50 total points
ID: 1185409
Answer was already submitted above.
Hope all goes well...

PS : If you're to implement an OLE solution, don't forget the "reference counting" mechanism. Examples using VB code :

Set app = CreateObject("Word.Application")
/* Word is launched, interface is not visible */
Set app = Nothing /* WINWORD process is unloaded */

but

Set app = CreateObject("Word.Application")
/* Word is launched, interface is not visible */
app.Visible = True /* shows the interface */
Set app = Nothing /* reference count is decremented but WINWORD is still alive */
/* User chooses "Quit" in the interface */
/* => Word is unloaded */

Also :

Set app = CreateObject("Word.Application")
/* Word is launched, interface is not visible */
app.Visible = True /* shows the interface */

/* User chooses "Quit" in the interface */
/* => Word is not unloaded because the VB app holds a reference to it */

And so on...



0
 

Author Comment

by:SergeD
ID: 1185410
Thanx,

I'll try to implement your solution when I will have a bit of time...

Serge
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Often, when implementing a feature, you won't know how certain events should be handled at the point where they occur and you'd rather defer to the user of your function or class. For example, a XML parser will extract a tag from the source code, wh…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now