ClassExec

From FVue
Jump to: navigation, search

As far as I'm concerned, the diatribes about DDE being too old a technology to be of any use, are a great misunderstanding. Microsoft makes excessive use of DDE to let the shell communicate with various applications (e.g. MS Office). Just search the registry for 'ddeexec' and you'll see what I mean. Most Windows applications lack the wealth of startup arguments which normally would allow you to pass information to the program during startup. ClassExec brings back this functionality to the command prompt.

ClassExec is a command line utility to:

  • start a file within its default application, e.g. classExec foo.doc
  • start a file within another default application, e.g. classExec --class .xls foo.doc
  • create a new Word document based on a specified template, passing arguments to a startup macro along the way:
    classExec my.dot --action new --command "[NewMacros.LoadFile \"C:\test.txt\"]"
  • print files
  • etcetera...

Contents

How does classExec work?

By reverse engineering I found the DDE parameters are stored in the registry like this:

shell
|- <action>
   |- command
   |- ddeexec
      |- Application
      |- Topic

or at least this is the case for Microsoft applications. ClassExec looks for these registry settings, using the filename extension or the `--class' option. For example with .dot files it goes like this with .dot being the extension and `Word.Template.8' being the classname:

HKEY_CLASSES_ROOT
|- .dot   (Default) = Word.Template.8
:
|- Word.Template.8
   |- shell
      |- <action>
         |- command
         |- ddexec
            :

If no such branch for your filename extension exists, make sure to check the 'Use DDE' checkbox within Explorer via {View|Folder Options...|File Types|Edit|Edit}. I think Windows is using the `ddeexec/Application' key to look up the actual `Application' in:

HKEY_LOCAL_MACHINE
|- Software
   |- Microsoft
      |- Windows
         |- CurrentVersion
            |- App Paths
               |- <Application>.exe

Examples

Introduction

The commands:

classExec
classExec --help

will display a help message and exit. The commands:

classExec <filename>
classExec <filename> --action open

both will open <filename>, since `open' is the default action of classExec if no action is specified. Note this is the same as the built-in Windows command:

start <filename>

The command:

classExec *

will issue the `open' action on all files in the current directory. The command:

classExec * --class .doc

will open all files in Word. You want to open all files in Excel instead? Here's the command to do so:

classExec * --class .xls

The command:

classExec C:\* D:\* --class .doc

will open all files from the C:\ directory as well as all files from the D:\ directory, in Word.

WARNING: Google AdSense Unit ID "" does not exist.
Available Unit IDs: C01, C02, C03, C04, C05, C06, C07, C08, C09, C10, S01, S02, V01, V02, V03.
Example: <google uid="C01"></google>, <google uid="C01" position="left" ></google>

Selecting browser

If you want to view a HTML file in your default browser from the command line, you could issue one of these commands:

classExec example.htm
start example.htm

But what to do if you want to view the HTML file in either Netscape Navigator or Microsoft Internet Explorer, without wanting to bother if it's the default browser or not? Here's what to do if you want to view the HTML file using Netscape Navigator:

classExec example.htm --class NetscapeMarkup

If you want to view the HTML file using Microsoft Internet Explorer, use:

classExec example.htm --class htmlFile

Word

Processing files within subdirectories

ClassExec only works on files within the specified folder. To process files within subfolders as well, the GNU utility `find.exe' can be used. Find.exe can be obtained by downloading find41b.zip from www.delorie.com/djgpp/ or by downloading utilities from unxutils.sourceforge.net.

The syntax to call classExec recursive on multiple .doc files within subdirectories would be:

find . -name *.doc -exec classExec {} --command [NewMacros.Test()] ;

Calling macro on startup

Suppose you're having a template my.dot with a macro NewMacros.LoadFile:

Sub LoadFile(as_File As String)
   MsgBox as_File + Chr$(13)
   Selection.InsertFile as_dpf
End Sub

Here's how you can start C:\test.txt in Word, base it on my.dot, and calling LoadFile on startup:

 classExec my.dot --action new --command "[NewMacros.LoadFile \"C:\test.txt\"]"

Or if you're having a macro which asks for two arguments:

Sub ShowMessages(as_Msg1 As String, as_Msg2 As String)
   MsgBox as_Msg1
   MsgBox as_Msg2
End Sub

Here's how you would call it:

classExec my.dot --action new --command "[NewMacros.ShowMessages \"Msg1\", \"Msg2\"]"

A macro with no arguments gets called like this:

classExec my.dot --action new --command "[NewMacros.ShowMessages()]"

Printing

The command:

classExec <filename>.doc --action print

will open Word and print <filename>.doc. If Word wasn't open, Word will be closed automatically after the print job is done. The command:

classExec <filename>.txt --class .doc --action print

will open Word and print <filename>.txt. If Word wasn't open, Word will be closed automatically after the print job is done. The command:

 classExec <filename>.doc --action print --noifexec

will open Word and print <filename>.doc. If Word wasn't open, Word will not be closed after the print job is done. The command:

classExec <filename>.doc --action print --ifexec

will open Word and print <filename>.doc. After the print job, Word will be closed.

Batch conversion

After you created this macro in module NewMacros of normal.dot:

Sub Convert()
   ActiveDocument.SaveAs ActiveDocument.FullName + ".rtf", _
      FileFormat:=wdFormatRTF
   ActiveDocument.Close
End Sub

here's how you could invoke classExec to convert all files in a folder to RTF:

classExec * --class .doc --command [NewMacros.Convert()]

Batch conversion, keeping date of original file

Suppose you want to convert all .doc files to .rtf.  Extra condition is you want to give the .rtf file the date of the original .doc file.  If you put the GNU utility touch.exe in the C:\Windows directory and you put the next macro Convert in the NewMacros section of normal.dot:

Sub Convert()
   Dim sFileIn, sFileOut As String

   sFileIn = ActiveDocument.FullName
   sFileOut = ActiveDocument.Path & Application.PathSeparator & _
   ActiveDocument.Name & ".rtf"

   ActiveDocument.SaveAs sFileOut, _
      FileFormat:=wdFormatRTF
   ActiveDocument.Close

   Shell "C:\Windows\touch.exe " & sFileOut & " -r " & sFileIn
End Sub

here's how you could invoke classExec to convert Word files to RTF, keeping the date of the original file:

classExec *.doc --command [NewMacros.Convert()]

Excel

Create new sheet based on another

If you want to create a new sheet, based on another sheet (book1.xls), here's how you would do so:

classExec book1.xls --action new

Calling macro on startup

Suppose you're having a file book1.xls with a macro Sheet1.HelloWorld:

Sub HelloWorld()
   MsgBox "Hello world!"
End Sub

Here's how you would start book1.xls in Excel, calling macro Sheet1.HelloWorld on startup:

classExec book1.xls --command "[Run(\"Sheet1.HelloWorld\")]"

Fill cells on startup

It looks like it isn't possible to pass arguments to an Excel macro during startup.  Anyone?  Any string you pass to the opened sheet will be inserted into the sheet.  For instance, if you say:

classExec book1.xls --command "Hello world"

the string "Hello world" will be inserted in cell A1 of book1.xls.  You can pass <tab> in the string to advance to a cell on the right. For instance if you say:

classExec book1.xls --command "Hello<tab>world"

the string "Hello" will be inserted in cell A1, whereas "world" will be inserted in cell A2.  You can pass <newline> in the string to advance to a cell underneath the current cell.  For instance, if you say:

classExec book1.xls --command "Hello<newline>world"

the string "Hello" will be inserted in cell A1, whereas "world" will be inserted in cell B1.

Access

Snapshot Viewer

Snapshot Viewer is a program that you can use to view, print, and electronically mail an Access report snapshot www.microsoft.com/accessdev/prodinfo/snapshot.htm).
To open a snapshot file:

classExec report.snp

To print a snapshot file:

classExec report.snp --action print

Be aware however, the Snapshot Viewer installation program doesn't install complete registry keys; to be specific it omits the

  • ddeexec\application
  • ddeexec\topic

keys. To make full use of ClassExec with Snapshot Viewer, make sure the following registry keys are specified:

HKEY_CLASSES_ROOT
|- SnapshotFile
   |- shell
      |- open
      |  |- command               (Default) = <Path to snapView.exe>
      |  |- ddeexec               (Default) = [open("%1")]
      |     |- application        (Default) = SnapView
      |     |- topic              (Default) = system
      |
      |- print
      |  |- command               (Default) = <Path to snapView.exe>
      |  |- ddexec                (Default) = [print("%1")]
      |     |- application        (Default) = SnapView
      |     |- topic              (Default) = system
      |
      |- printto
         |- command               (Default) = <Path to snapView.exe>
         |- ddeexec               (Default) = [printto("%1","%2","%3","%4")]
            |- application        (Default) = SnapView
            |- topic              (Default) = system

Known Problems

Setting default printer

Windows 2000/XP

You can set the default printer from the command line using rundll32 and printui.dll. For example, to select "HP DeskJet 710C" as the default printer:

rundll32 printui.dll,PrintUIEntry /y /n "HP DeskJet 710C"

For more information, see: http://www.robvanderwoude.com/2kprintcontrol.html

Word97 error: "Ambiguous name detected: TmpDDE"

When you execute a DDE command via Microsoft Word 97, Word will dynamically create a temporary module called `WordTmpDDEMod' in normal.dot with a temporary subroutine called `TmpDDE' in it. This temporary subroutine contains the DDE commands. After the subroutine exits, the temporary module will automatically be deleted.

However, you may found yourself in a situation where Word hasn't cleaned up the temporary DDE module. Here's how you can remove the temporary DDE module manually:

  1. From Microsoft Word, call the Visual Basic Editor via {Tools; Macro; Visual Basic Editor}.
  2. From the Project Explorer ({View; Project Explorer}) choose the `Normal' project from the tree root and open the `Modules' branch.
  3. Select the module called `WordTmpDDEMod' and delete it using {File; Remove WordTmpDDEMod...} (you don't need to export it before removing).

Word Viewer doesn't support DDE print

Microsoft Word Viewer 2007 or 2003 doesn't support printing via DDE. WordView 95 used to support this and even had a /p switch, but print automation has been removed from WordView 97 and up.

Up to Windows XP, Wordpad has .doc support so you might try Wordpad:

classexec word.doc --class Wordpad.Document.1 --action print

Windows Vista however, removed .doc support from Wordpad. A workaround might be to use the free and open OpenOffice:

soffice -p word.doc
classexec word.doc --class .odt --action print

Regressive Word 97 DDE functionality

According to Ted Giria, Word 97 allows not more then 256 bytes in a package whereas Word 95 allowes 127 commands at one. Also Word 95 is more stable with DDE than 97. In some situations in Word 95 where you have an error message or error return code, Word 97 yields a GPF.

Download

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

See also: Gpg: Verifying FVue releases

Release

classExec-1.03b.zip (binary), classExec-1.03b.zip.asc (signature)
classExec-1.03s.zip (sources), classExec-1.03s.zip.asc (signature)

Development

classExec-1.5.0b.zip (binary), classExec-1.5.0b.zip.asc (signature)
classExec-1.5.0s.zip (sources), classExec-1.5.0b.zip.asc (signature)

WARNING: Google AdSense Unit ID "" does not exist.
Available Unit IDs: C01, C02, C03, C04, C05, C06, C07, C08, C09, C10, S01, S02, V01, V02, V03.
Example: <google uid="C01"></google>, <google uid="C01" position="left" ></google>

Release Notes

v1.03

  • Fixed Windows NT error message "The instruction at '0x77f64b53' referenced memory at '0x0000031d'. The memory could not be 'read'", caused by 'LocalFree()' which tried to free an already freed piece of memory.

v1.02

  • Fixed error message "invalid page fault in module CLASSEXEC.EXE at 0137:00401595" when using a full classname (e.g. 'txtfile') instead of an extension (e.g. '.txt').

v1.01

  • Fixed error message "access violation on address 0xC0000005" on Windows NT, caused by dynamic determination of application name. Application name now is set fixed to "classExec".
  • Added environment string expansion to commands. E.g. the command "%SystemRoot%\system32\notepad.exe" now will get expanded to "C:\WinNt\system32\notepad.exe".
  • Enhanced error message of non-startable application with the application command line string.

v1.00

  • Initial version.

Alternatives

Windows Scripting Host

The Windows Scripting Host has some advantages though. For instance, the ability to send key strokes to an application. Here's an example VBScript to start up any argument file, print it using {File|Print}, send {ENTER} to the print dialog, and close it using {File|Close}.

Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.run WScript.Arguments(0)
On Error Resume Next
Err.Clear
Wscript.Sleep(100)
   REM Send keys: ALT-File|Print, ENTER, ALT-File|Close
WshShell.SendKeys "%FP{ENTER}%FC"

For more information, see:

'ShellExecute()' API function

If you just want to start the application associated with a given file extension, you're probably better of using the Windows API 'ShellExecute()' function. This is the summary of the Microsoft document Q170918:

"You can use the Windows API ShellExecute() function to start the application associated with a given document extension without knowing the name of the associated application. For example, you could start the Paintbrush program by passing the filename ARCADE.BMP to the ShellExecute() function."

And this is what the Visual Basic declaration looks like:

Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" ( _
   ByVal hwnd As Long, ByVal lpszOp As String, _
   ByVal lpszFile As String, ByVal lpszParams As String, _
   ByVal LpszDir As String, ByVal FsShowCmd As Long _
) As Long

'Start' command line function

If you - from the command prompt - just want to start the application associated with a single file without knowing the name of the associated application, you can use the start function from the command prompt, e.g.:

start arcade.bmp

This is what the help message (start /?) has to say:

Runs a Windows program or an MS-DOS program.

   START [options] program [arg...]
   START [options] document.ext

   /m[inimized] Run the new program minimized (in the background).
   /max[imized] Run the new program maximized (in the foreground).
   /r[estored]  Run the new program restored (in the foreground). [default]
   /w[ait]      Does not return until the other program exits.


Word Batch Conversion Wizard

Microsoft includes the Batch Conversion Wizard with Word.  It allows you to do a conversion to/from Word format on a folder full of files.  If Word is fully installed, there will be a file called convert8.wiz, in .\Program Files\Microsoft Office\Office\Macros.  Double-click it and follow the instructions.

Links

Dynamic Data Exchange (DDE) and NetDDE FAQ
Extensive information about DDE

Comments

blog comments powered by Disqus

Personal tools
Google