Assigning a file type to an Application on Windows/de: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
(Sub-category)
 
(12 intermediate revisions by 3 users not shown)
Line 1: Line 1:
[[Category:Snippets]]
[[Category:Snippets::Misc]]
[[Category:German]]
[[Category:German]]
 
{{LangSwitch}}
'''Deutsch''' | [[Assigning_a_file_type_to_an_Application_on_Windows|English]]
 
[toc align_right="yes" depth="3"]
 
= Einen Dateitypen unter Windows mit einem Programm verknüpfen =
= Einen Dateitypen unter Windows mit einem Programm verknüpfen =


== Technischer Hintergrund ==
== Technischer Hintergrund ==


Dateitypen werden unter Windows in der Registry definiert. Zunächst einmal ist da der Eintrag "<extension&amp;amp;gt;" in HKCR,
Dateitypen werden unter Windows in der Registry definiert. Zunächst einmal ist da der Eintrag "<extension>" in HKCR,
welcher den Namen des Dateityps enthält. In HKCRamp;lt;file type name&amp;amp;gt; sind die diversen Aktionen definiert.
welcher den Namen des Dateityps enthält. In HKCRamp;lt;file type name> sind die diversen Aktionen definiert.


Dies bedeutet, es gibt eine Dateinamenerweiterung '''gidoc''', deren Dateien "MDI Text Editor Document" heißen. Diese Dokumente sollen mit einem Programm geöffnet weden, welches sich hier befindet: E:.exe. Die Datei selbst soll ein Parameter sein.
Dies bedeutet, es gibt eine Dateinamenerweiterung '''gidoc''', deren Dateien "MDI Text Editor Document" heißen. Diese Dokumente sollen mit einem Programm geöffnet weden, welches sich hier befindet: E:.exe. Die Datei selbst soll ein Parameter sein.
Line 45: Line 41:
Mit diesen Einstellungen startet Windows den Prozess, welcher auf der Kommandozeile übergeben wird und sendet eine WM_DDE_INITIATE-Broadcast-Nachricht. Das entsprechende MDI-Programm muss auf diese Nachricht reagieren, dann WM_DDE_EXECUTE-Nachrichten und, falls nötig, eine WM_DDE_TERMINATE-Nachricht behandeln. Falls die Reaktionen auf die DDE-Nachrichten nicht korrekt sind, zeigt Windows entsprechende Fehlermeldungen an.
Mit diesen Einstellungen startet Windows den Prozess, welcher auf der Kommandozeile übergeben wird und sendet eine WM_DDE_INITIATE-Broadcast-Nachricht. Das entsprechende MDI-Programm muss auf diese Nachricht reagieren, dann WM_DDE_EXECUTE-Nachrichten und, falls nötig, eine WM_DDE_TERMINATE-Nachricht behandeln. Falls die Reaktionen auf die DDE-Nachrichten nicht korrekt sind, zeigt Windows entsprechende Fehlermeldungen an.


h2. Und so geht es
==Und so geht es==


Normalerweise registriert ein Programm seine Dateitypen während seines Setup-Vorgangs (es ändert die Windows Registry).
Normalerweise registriert ein Programm seine Dateitypen während seines Setup-Vorgangs (es ändert die Windows Registry).
Line 56: Line 52:
Dieser Vorgang und der entsprechende Code sind immer gleich, nur die Schlüssel in der Registrx und die Behandlung der DDE-Befehle unterscheiden sich von Programm zu Programm. Deswegen habe ich eine Klasse erstellt, die all diese immer gleichen Dinge abhandelt. Man kann sie als Basisklasse anstelle von QMainWindow benutzen. Die neue Klasse heißt '''DocumentWindow'''.
Dieser Vorgang und der entsprechende Code sind immer gleich, nur die Schlüssel in der Registrx und die Behandlung der DDE-Befehle unterscheiden sich von Programm zu Programm. Deswegen habe ich eine Klasse erstellt, die all diese immer gleichen Dinge abhandelt. Man kann sie als Basisklasse anstelle von QMainWindow benutzen. Die neue Klasse heißt '''DocumentWindow'''.


h2. Wie man die DocumentWindow-Klasse benutzt
==Wie man die DocumentWindow-Klasse benutzt==


Wenn du ein (MDI-) Editor-Programm erstellen willst, kann du deine Hauptfenster-Klasse von DocumentWindow, anstatt von QMainWindow, ableiten. Wenn ein MDI-Programm werden soll, solltest zusätzlich die virtuelle Methode <code>ddeOpenFile()</code> reimplementieren.
Wenn du ein (MDI-) Editor-Programm erstellen willst, kann du deine Hauptfenster-Klasse von DocumentWindow, anstatt von QMainWindow, ableiten. Wenn ein MDI-Programm werden soll, solltest zusätzlich die virtuelle Methode <code>ddeOpenFile()</code> reimplementieren.


Das folgende Beispiel baut auf dem "Qt MDI Example":http://doc.qt.nokia.com/4.7/mainwindows-mdi.html auf.
Das folgende Beispiel baut auf dem [http://doc.qt.io/qt-4.8/qt-mainwindows-mdi-example.html Qt MDI Example] auf.


<code>
<code>
Line 67: Line 63:
protected:
protected:
  virtual void ddeOpenFile(const QString&amp;amp; filePath);
  virtual void ddeOpenFile(const QString& filePath);
}
}
</code>
</code>
Line 86: Line 82:
  …
  …
}
}
</code>endcode
@endcode
<code>
</code>


… und <code>ddeFileOpen()</code> reimplementiert werden:
… und <code>ddeFileOpen()</code> reimplementiert werden:


</code>
<code>
void MainWindow::ddeOpenFile(const QString&amp;amp; filePath)
void MainWindow::ddeOpenFile(const QString& filePath)
{
{
  MdiChild '''child = createMdiChild();
  MdiChild '''child = createMdiChild();
Line 105: Line 101:
  }
  }
}
}
<code>
</code>


Das wars auch schon. Jetzt sollte es reichen das Programm zu starten und schon ist der Dateityp ".gidoc" mit deinem Programm verknüpft. Wenn man auf eine solche Datei im Windows-Explorer doppelklickt, sollte das Dokument entweder in einem schon laufenden Prozess geöffnet werden, oder aber, wenn dein Programm noch nicht läuft, sollte es zunächst gestartet werden und dann darin geöffnet werden. Wenn dein Programm ein Fenster-Icon in seiner Resource hat (Keine qrc-Datei! Eine Windows-Resource-Datei'''.rc), dann sollte dieses Icon von nun an für Dateien des verknüpften Dateityps angezeigt werden.
Das wars auch schon. Jetzt sollte es reichen das Programm zu starten und schon ist der Dateityp ".gidoc" mit deinem Programm verknüpft. Wenn man auf eine solche Datei im Windows-Explorer doppelklickt, sollte das Dokument entweder in einem schon laufenden Prozess geöffnet werden, oder aber, wenn dein Programm noch nicht läuft, sollte es zunächst gestartet werden und dann darin geöffnet werden. Wenn dein Programm ein Fenster-Icon in seiner Resource hat (Keine qrc-Datei! Eine Windows-Resource-Datei'''.rc), dann sollte dieses Icon von nun an für Dateien des verknüpften Dateityps angezeigt werden.
Line 113: Line 109:
=== DocumentWindow.h ===
=== DocumentWindow.h ===


</code>
<code>
// ————————————————————————————————-
// ————————————————————————————————-
/**
/**
  * <code>file
  * @file
  * </code>brief
  * @brief
  * <code>author Gerolf Reinwardt
  * @author Gerolf Reinwardt
  * </code>date 30. march 2011
  * @date 30. march 2011
  *
  *
  * Copyright © 2011, Gerolf Reinwardt. All rights reserved.
  * Copyright © 2011, Gerolf Reinwardt. All rights reserved.
Line 156: Line 152:
// —— general includes —————————————————————————
// —— general includes —————————————————————————
#include <windows.h>
#include <windows.h>
#include <QtGui/QMainWindow>
#include <QMainWindow>


// —— local includes —————————————————————————-
// —— local includes —————————————————————————-
Line 163: Line 159:
// —— class definition —————————————————————————
// —— class definition —————————————————————————
/'''*
/'''*
  * <code>short This class implements a main window with the ability to register file types on MS Windows and
  * @short This class implements a main window with the ability to register file types on MS Windows and
  * react on the corresponding DDE events to open / print the files in an Windows MDI typical manner.
  * react on the corresponding DDE events to open / print the files in an Windows MDI typical manner.
  *
  *
Line 170: Line 166:
  * Qt MDI Example (http://doc.qt.nokia.com/4.7/mainwindows-mdi.html)
  * Qt MDI Example (http://doc.qt.nokia.com/4.7/mainwindows-mdi.html)
  *
  *
  * </code>code
  * @code
  MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags flags) :
  MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags flags) :
  DocumentWindow(parent, flags)
  DocumentWindow(parent, flags)
Line 182: Line 178:
  setUnifiedTitleAndToolBarOnMac(true);
  setUnifiedTitleAndToolBarOnMac(true);
  }
  }
  <code>endcode
  @endcode
  *
  *
  * Aditionally, the actions must be performed by overwriting one or more of:
  * Aditionally, the actions must be performed by overwriting one or more of:
  * </code>li ddeOpenFile
  * @li ddeOpenFile
  * <code>li ddeNewFile
  * @li ddeNewFile
  * </code>li ddePrintFile
  * @li ddePrintFile
  * <code>li executeUnknownDdeCommand
  * @li executeUnknownDdeCommand
  *
  *
  * </code>code
  * @code
  void MainWindow::ddeOpenFile(const QString&amp;amp; filePath)
  void MainWindow::ddeOpenFile(const QString& filePath)
  {
  {
  MdiChild '''child = createMdiChild();
  MdiChild '''child = createMdiChild();
Line 204: Line 200:
  }
  }
  }
  }
  <code>endcode
  @endcode
'''
'''
  */
  */
Line 226: Line 222:
  * Constructor.
  * Constructor.
  *
  *
  * Creates a DocumentWindow with a given </code>arg parent and </code>arg flags.
  * Creates a DocumentWindow with a given @arg parent and @arg flags.
  */
  */
  explicit DocumentWindow(QWidget''' parent = 0, Qt::WindowFlags flags = 0);
  explicit DocumentWindow(QWidget''' parent = 0, Qt::WindowFlags flags = 0);
Line 252: Line 248:
  * from Windows.
  * from Windows.
  *
  *
  * <code>param filePath file that was selected in the explorer
  * @param filePath file that was selected in the explorer
  */
  */
  virtual void ddeOpenFile(const QString&amp;amp; filePath);
  virtual void ddeOpenFile(const QString& filePath);


  /'''*
  /'''*
Line 260: Line 256:
  * from Windows.
  * from Windows.
  *
  *
  * </code>param filePath file that was selected in the explorer
  * @param filePath file that was selected in the explorer
  */
  */
  virtual void ddeNewFile(const QString&amp;amp; filePath);
  virtual void ddeNewFile(const QString& filePath);


  /'''*
  /'''*
Line 268: Line 264:
  * from Windows.
  * from Windows.
  *
  *
  * <code>param filePath file that was selected in the explorer
  * @param filePath file that was selected in the explorer
  */
  */
  virtual void ddePrintFile(const QString&amp;amp; filePath);
  virtual void ddePrintFile(const QString& filePath);


  /'''*
  /'''*
Line 277: Line 273:
  * this function is called.
  * this function is called.
  *
  *
  * </code>param command name of the command
  * @param command name of the command
  * <code>param params parameter string, containing the hole stuff, also " and commas.
  * @param params parameter string, containing the hole stuff, also " and commas.
  *
  *
  * </code>note a command like this [compare("%1")] will result in the parameters:
  * @note a command like this [compare("%1")] will result in the parameters:
  command = "compare";
  command = "compare";
  params = "quot;<filepath>quot;";
  params = "quot;<filepath>quot;";
  */
  */
  virtual void executeUnknownDdeCommand(const QString&amp;amp; command, const QString&amp;amp; params);
  virtual void executeUnknownDdeCommand(const QString& command, const QString& params);


  /'''*
  /'''*
  * Call this method to register the file type in Windows. It creates the default command
  * Call this method to register the file type in Windows. It creates the default command
  * which means the app is started with the file to open as parameter. If <code>arg registerForDDE
  * which means the app is started with the file to open as parameter. If @arg registerForDDE
  * is true, the dde events are also created so the opening of a file is done in typical MDI
  * is true, the dde events are also created so the opening of a file is done in typical MDI
  * behavior (all files open in the same app).
  * behavior (all files open in the same app).
  *
  *
  * </code>param documentId id of the document, typically <Application>.Document —> see in registry, e.g. "GiMdi.Document"
  * @param documentId id of the document, typically <Application>.Document —> see in registry, e.g. "GiMdi.Document"
  * <code>param fileTypeName free name of the file type, e.g. "MDI Text Editor Document"
  * @param fileTypeName free name of the file type, e.g. "MDI Text Editor Document"
  * </code>param fileExtension File extension, including the dot (e.g. ".gidoc")
  * @param fileExtension File extension, including the dot (e.g. ".gidoc")
  * <code>param appIconIndex index of the app icon to use for the file in the windows explorer, typically the application icon
  * @param appIconIndex index of the app icon to use for the file in the windows explorer, typically the application icon
  * </code>param registerForDDE true if DDE should be used (typical for MDI apps), typically false for SDI apps.
  * @param registerForDDE true if DDE should be used (typical for MDI apps), typically false for SDI apps.
  * <code>param commands a combination of the commands to install.
  * @param commands a combination of the commands to install.
  *
  *
  * </code>note If more then the default commands are needed, then subsequent calls of registerCommand are needed.
  * @note If more then the default commands are needed, then subsequent calls of registerCommand are needed.
  *
  *
  * <code>note DDEOpen leads to the DDE command: [open("%1)]
  * @note DDEOpen leads to the DDE command: [open("%1)]
  DDENew leads to the DDE command: [new("%1)]
  DDENew leads to the DDE command: [new("%1)]
  DDEPrint leads to the DDE command: [print("%1)]
  DDEPrint leads to the DDE command: [print("%1)]
  */
  */
  void registerFileType(const QString&amp;amp; documentId,
  void registerFileType(const QString& documentId,
  const QString&amp;amp; fileTypeName,
  const QString& fileTypeName,
  const QString&amp;amp; fileExtension,
  const QString& fileExtension,
  qint32 appIconIndex = 0,
  qint32 appIconIndex = 0,
  bool registerForDDE = false,
  bool registerForDDE = false,
Line 317: Line 313:
  * in addition to registerFileType.
  * in addition to registerFileType.
  *
  *
  * </code>code
  * @code
  MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags flags) :
  MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags flags) :
  DocumentWindow(parent, flags)
  DocumentWindow(parent, flags)
Line 329: Line 325:
  …
  …
  }
  }
  <code>endcode
  @endcode
  */
  */
  void registerCommand(const QString&amp;amp; command,
  void registerCommand(const QString& command,
  const QString&amp;amp; documentId,
  const QString& documentId,
  const QString cmdLineArg = QString::null,
  const QString cmdLineArg = QString::null,
  const QString ddeCommand = QString::null);
  const QString ddeCommand = QString::null);
Line 366: Line 362:
  * Sets specified value in the registry under HKCU\Software\Classes, which is mapped to HKCR then.
  * Sets specified value in the registry under HKCU\Software\Classes, which is mapped to HKCR then.
  */
  */
  bool SetHkcrUserRegKey(QString key, const QString&amp;amp; value, const QString&amp;amp; valueName = QString::null);
  bool SetHkcrUserRegKey(QString key, const QString& value, const QString& valueName = QString::null);


  /'''*
  /'''*
Line 372: Line 368:
  * ddeOpenFile, ddeNewFile, ddePrintFile or executeUnknownDdeCommand.
  * ddeOpenFile, ddeNewFile, ddePrintFile or executeUnknownDdeCommand.
  */
  */
  void executeDdeCommand(const QString&amp;amp; command, const QString&amp;amp; params);
  void executeDdeCommand(const QString& command, const QString& params);


  // —— members ——————————————————————————-
  // —— members ——————————————————————————-
Line 390: Line 386:
=== DocumentWindow.cpp ===
=== DocumentWindow.cpp ===


<code>
<code lang="cpp">
// ————————————————————————————————-
// ————————————————————————————————-
/**
/**
  * </code>file
  * @file
  * <code>brief
  * @brief
  * </code>author Gerolf Reinwardt
  * @author Gerolf Reinwardt
  * <code>date 30.01.2011
  * @date 30.01.2011
  *
  *
  * Copyright © 2011, Gerolf Reinwardt. All rights reserved.
  * Copyright © 2011, Gerolf Reinwardt. All rights reserved.
Line 430: Line 426:
// —— general includes —————————————————————————
// —— general includes —————————————————————————
#include <windows.h>
#include <windows.h>
#include <QtGui/QMessageBox>
#include <QMessageBox>
#include <QtGui/QApplication>
#include <QApplication>
#include <QtCore/QDir>
#include <QDir>
#include <QtCore/QFileInfo>
#include <QFileInfo>
#include <QtCore/QRegExp>
#include <QRegExp>


// —— local includes —————————————————————————-
// —— local includes —————————————————————————-
Line 491: Line 487:
}
}


void DocumentWindow::ddeOpenFile(const QString&amp;amp;)
void DocumentWindow::ddeOpenFile(const QString&)
{
{
  // this method will be overwritten, if the application uses the dde open command
  // this method will be overwritten, if the application uses the dde open command
}
}


void DocumentWindow::ddeNewFile(const QString&amp;amp;)
void DocumentWindow::ddeNewFile(const QString&)
{
{
  // this method will be overwritten, if the application uses the dde new command
  // this method will be overwritten, if the application uses the dde new command
}
}


void DocumentWindow::ddePrintFile(const QString&amp;amp;)
void DocumentWindow::ddePrintFile(const QString&)
{
{
  // this method will be overwritten, if the application uses the dde print command
  // this method will be overwritten, if the application uses the dde print command
}
}


void DocumentWindow::executeUnknownDdeCommand(const QString&amp;amp;, const QString&amp;amp;)
void DocumentWindow::executeUnknownDdeCommand(const QString&, const QString&)
{
{
  // this method will be overwritten, if the application uses other commands,
  // this method will be overwritten, if the application uses other commands,
Line 512: Line 508:
}
}


void DocumentWindow::registerFileType(const QString&amp;amp; documentId,
void DocumentWindow::registerFileType(const QString& documentId,
  const QString&amp;amp; fileTypeName,
  const QString& fileTypeName,
  const QString&amp;amp; fileExtension,
  const QString& fileExtension,
  qint32 appIconIndex,
  qint32 appIconIndex,
  bool registerForDDE,
  bool registerForDDE,
Line 529: Line 525:
  m_registerForDDE = registerForDDE;
  m_registerForDDE = registerForDDE;


  if(commands &amp; DDEOpen)
  if(commands & DDEOpen)
  registerCommand("Open", documentId, "quot;%1quot;", "[open(quot;%1quot;)]");
  registerCommand("Open", documentId, "quot;%1quot;", "[open(quot;%1quot;)]");
  if(commands &amp; DDENew)
  if(commands & DDENew)
  registerCommand("New", documentId, "-new quot;%1quot;", "[new(quot;%1quot;)]");
  registerCommand("New", documentId, "-new quot;%1quot;", "[new(quot;%1quot;)]");
  if(commands &amp; DDEPrint)
  if(commands & DDEPrint)
  registerCommand("Print", documentId, "-print quot;%1quot;", "[print(quot;%1quot;)]");
  registerCommand("Print", documentId, "-print quot;%1quot;", "[print(quot;%1quot;)]");


Line 541: Line 537:
  (const wchar_t*)fileExtension.utf16(),
  (const wchar_t*)fileExtension.utf16(),
  szTempBuffer,
  szTempBuffer,
  &amp;lSize);
  &lSize);


  QString temp = QString::fromUtf16((unsigned short*)szTempBuffer);
  QString temp = QString::fromUtf16((unsigned short*)szTempBuffer);
Line 555: Line 551:
}
}


void DocumentWindow::registerCommand(const QString&amp;amp; command,
void DocumentWindow::registerCommand(const QString& command,
  const QString&amp;amp; documentId,
  const QString& documentId,
  const QString cmdLineArg,
  const QString cmdLineArg,
  const QString ddeCommand)
  const QString ddeCommand)
Line 599: Line 595:
bool DocumentWindow::ddeInitiate(MSG* message, long* result)
bool DocumentWindow::ddeInitiate(MSG* message, long* result)
{
{
  if( (0 != LOWORD (message->lParam)) &amp;&amp;
  if( (0 != LOWORD (message->lParam)) &&
  (0 != HIWORD (message->lParam)) &amp;&amp;
  (0 != HIWORD (message->lParam)) &&
  (LOWORD (message->lParam)  m_appAtom) &amp;amp;&amp;amp;
  (LOWORD (message->lParam)  m_appAtom) &&
         (HIWORD(message->lParam)  m_systemTopicAtom))
         (HIWORD(message->lParam)  m_systemTopicAtom))
  {
  {
Line 624: Line 620:
  HGLOBAL hData;
  HGLOBAL hData;
  //IA64: Assume DDE LPARAMs are still 32-bit
  //IA64: Assume DDE LPARAMs are still 32-bit
  Q_ASSERT(::UnpackDDElParam(WM_DDE_EXECUTE, message->lParam, &amp;unused, (UINT_PTR*)&amp;hData));
  Q_ASSERT(::UnpackDDElParam(WM_DDE_EXECUTE, message->lParam, &unused, (UINT_PTR*)&hData));


QString command = QString::fromWCharArray((LPCWSTR)::GlobalLock(hData));
QString command = QString::fromWCharArray((LPCWSTR)::GlobalLock(hData));
Line 658: Line 654:
}
}


bool DocumentWindow::SetHkcrUserRegKey(QString key, const QString&amp;amp; value, const QString&amp;amp; valueName)
bool DocumentWindow::SetHkcrUserRegKey(QString key, const QString& value, const QString& valueName)
{
{
  HKEY hKey;
  HKEY hKey;
Line 666: Line 662:
  LONG lRetVal = RegCreateKey(HKEY_CURRENT_USER,
  LONG lRetVal = RegCreateKey(HKEY_CURRENT_USER,
  (const wchar_t*)key.utf16(),
  (const wchar_t*)key.utf16(),
  &amp;hKey);
  &hKey);


  if(ERROR_SUCCESS == lRetVal)
  if(ERROR_SUCCESS == lRetVal)
Line 677: Line 673:
  (value.length() + 1) * sizeof(wchar_t));
  (value.length() + 1) * sizeof(wchar_t));


  if(::RegCloseKey(hKey)  ERROR_SUCCESS &amp;amp;&amp;amp; lResult  ERROR_SUCCESS)
  if(::RegCloseKey(hKey)  ERROR_SUCCESS && lResult  ERROR_SUCCESS)
  return true;
  return true;


Line 693: Line 689:
}
}


void DocumentWindow::executeDdeCommand(const QString&amp;amp; command, const QString&amp;amp; params)
void DocumentWindow::executeDdeCommand(const QString& command, const QString& params)
{
{
  QRegExp regCommand("</sup>quot;(.''')quot;$");
  QRegExp regCommand("</sup>quot;(.''')quot;$");
  bool singleCommand = regCommand.exactMatch(params);
  bool singleCommand = regCommand.exactMatch(params);
  if((0  command.compare("open", Qt::CaseInsensitive)) &amp;amp;&amp;amp; singleCommand)
  if((0  command.compare("open", Qt::CaseInsensitive)) && singleCommand)
     {
     {
         ddeOpenFile(regCommand.cap(1));
         ddeOpenFile(regCommand.cap(1));
     }
     }
     else if((0  command.compare("new", Qt::CaseInsensitive)) &amp;&amp; singleCommand)
     else if((0  command.compare("new", Qt::CaseInsensitive)) && singleCommand)
  {
  {
  ddeNewFile(regCommand.cap(1));
  ddeNewFile(regCommand.cap(1));
  }
  }
  else if((0 == command.compare("print", Qt::CaseInsensitive)) &amp;&amp; singleCommand)
  else if((0 == command.compare("print", Qt::CaseInsensitive)) && singleCommand)
  {
  {
  ddePrintFile(regCommand.cap(1));
  ddePrintFile(regCommand.cap(1));
Line 721: Line 717:
== Zukünftige Erweiterung ==
== Zukünftige Erweiterung ==


The class might be extended so it also works on Linux or Mac. The code of the class and a demo project are located on gitorious in the following repository: "qtdevnet-registereditorfiletype":https://www.gitorious.org/qtdevnet-wiki-mvc/qtdevnet-registereditorfiletype
The class might be extended so it also works on Linux or Mac. The code of the class and a demo project are located on gitorious in the following repository: [https://www.gitorious.org/qtdevnet-wiki-mvc/qtdevnet-registereditorfiletype qtdevnet-registereditorfiletype]
Die Klasse könnte so erweitert werden, dass sie auch unter Linux und Mac OS funktioniert. Die Quellen der Klasse und ein Demonstratorprojekt finden sich in diesem Gitorious-Repository: "qtdevnet-registereditorfiletype":https://www.gitorious.org/qtdevnet-wiki-mvc/qtdevnet-registereditorfiletype
Die Klasse könnte so erweitert werden, dass sie auch unter Linux und Mac OS funktioniert. Die Quellen der Klasse und ein Demonstratorprojekt finden sich in diesem Gitorious-Repository: [https://www.gitorious.org/qtdevnet-wiki-mvc/qtdevnet-registereditorfiletype qtdevnet-registereditorfiletype]


== Versionen ==
== Versionen ==
Line 734: Line 730:
== Rückmeldungen ==
== Rückmeldungen ==


Ich würde mich wirklich sehr über Rückmeldungen zu dieser Klasse freuen. Wenn dir Schwächen auffallen, informiere mich bitte darüber. Für Diskussionen bezüglich dieses Wikis benutze bitte "diesen Forums-Thread":http://developer.qt.nokia.com/forums/viewthread/4810/ .
Ich würde mich wirklich sehr über Rückmeldungen zu dieser Klasse freuen. Wenn dir Schwächen auffallen, informiere mich bitte darüber. Für Diskussionen bezüglich dieses Wikis benutze bitte [http://developer.qt.nokia.com/forums/viewthread/4810/ diesen Forums-Thread] .

Latest revision as of 11:50, 28 November 2016

En Ar Bg De El Es Fa Fi Fr Hi Hu It Ja Kn Ko Ms Nl Pl Pt Ru Sq Th Tr Uk Zh

Einen Dateitypen unter Windows mit einem Programm verknüpfen

Technischer Hintergrund

Dateitypen werden unter Windows in der Registry definiert. Zunächst einmal ist da der Eintrag "<extension>" in HKCR, welcher den Namen des Dateityps enthält. In HKCRamp;lt;file type name> sind die diversen Aktionen definiert.

Dies bedeutet, es gibt eine Dateinamenerweiterung gidoc, deren Dateien "MDI Text Editor Document" heißen. Diese Dokumente sollen mit einem Programm geöffnet weden, welches sich hier befindet: E:.exe. Die Datei selbst soll ein Parameter sein.

Nach diesem Muster startet jeder Doppelklick auf eine Datei einen neuen Prozess, welcher die Datei als Parameter übergeben bekommt. Dies funktioniert gut für SDI (Single Document Interface) -Programme.

Hier dazu ein Beispiel:

HKEY_CLASSES_ROOT
 idoc
 "Default"="GiMdi.Document"
 "NullFile"=""

.Document
 "Default"="MDI Text Editor Document"
 ]
 "Default"="E:.exe,0"
 "Default"="E:.exe %1"

Bei MDI (Multi Document Interfaces) -Programmen ist jedoch anderes Verhalten erwünscht: Wenn bereits ein passender Prozess läuft, soll das Dokument in diesem geöffnet werden. Um dies zu erreichen müssen weitere Einträge vorgenommen werden:

HKEY_CLASSES_ROOT
 .Document
 "Default"="[open(quot;%1quot;)]"
 ]
 "Default"="SimpleCryptIoDevided"
 "Default"="system"

Mit diesen Einstellungen startet Windows den Prozess, welcher auf der Kommandozeile übergeben wird und sendet eine WM_DDE_INITIATE-Broadcast-Nachricht. Das entsprechende MDI-Programm muss auf diese Nachricht reagieren, dann WM_DDE_EXECUTE-Nachrichten und, falls nötig, eine WM_DDE_TERMINATE-Nachricht behandeln. Falls die Reaktionen auf die DDE-Nachrichten nicht korrekt sind, zeigt Windows entsprechende Fehlermeldungen an.

Und so geht es

Normalerweise registriert ein Programm seine Dateitypen während seines Setup-Vorgangs (es ändert die Windows Registry). Möchte man den MDI-Kram benutzen, muss das Programm einige sog. ATOMS (::GlobalAddAtom) erzeugen. Danach startet es und wartet auf Benutzereingaben.

Wenn der Dateityp registriert ist und keine DDE-Einstellungen vorgenommen wurden, startet das Programm mit dem Dateipfad als Parameter.

Wenn ddeexec Schlüssel in der Registry gesetzt wurden, startet das Programm und die DDE-Nachrichten werden gesendet. Während der Behandlung dieser Nachrichten, werden WM_DDE_ACK-Nachrichten an den Aufrufer zurückgesendet und die Nachrichten müssen behandelt werden.

Dieser Vorgang und der entsprechende Code sind immer gleich, nur die Schlüssel in der Registrx und die Behandlung der DDE-Befehle unterscheiden sich von Programm zu Programm. Deswegen habe ich eine Klasse erstellt, die all diese immer gleichen Dinge abhandelt. Man kann sie als Basisklasse anstelle von QMainWindow benutzen. Die neue Klasse heißt DocumentWindow.

Wie man die DocumentWindow-Klasse benutzt

Wenn du ein (MDI-) Editor-Programm erstellen willst, kann du deine Hauptfenster-Klasse von DocumentWindow, anstatt von QMainWindow, ableiten. Wenn ein MDI-Programm werden soll, solltest zusätzlich die virtuelle Methode

ddeOpenFile()

reimplementieren.

Das folgende Beispiel baut auf dem Qt MDI Example auf.

class MainWindow : public DocumentWindow
{

protected:
 virtual void ddeOpenFile(const QString& filePath);
}

Ansonsten muss nur noch der Constructor erweitert werden…

MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags flags) :
 DocumentWindow(parent, flags)
{
 
 registerFileType("GiMdi.Document", // Document type name
 "MDI Text Editor Document",// User readable file type name
 ".gidoc", // file extension
 0, // index of the icon to use for the files.
 true); // register for DDE events
 enableShellOpen();
 
}
@endcode

… und

ddeFileOpen()

reimplementiert werden:

void MainWindow::ddeOpenFile(const QString& filePath)
{
 MdiChild '''child = createMdiChild();
 if (child->loadFile(filePath))
 {
 statusBar()->showMessage(tr("File loaded"), 2000);
 child->show();
 }
 else
 {
 child->close();
 }
}

Das wars auch schon. Jetzt sollte es reichen das Programm zu starten und schon ist der Dateityp ".gidoc" mit deinem Programm verknüpft. Wenn man auf eine solche Datei im Windows-Explorer doppelklickt, sollte das Dokument entweder in einem schon laufenden Prozess geöffnet werden, oder aber, wenn dein Programm noch nicht läuft, sollte es zunächst gestartet werden und dann darin geöffnet werden. Wenn dein Programm ein Fenster-Icon in seiner Resource hat (Keine qrc-Datei! Eine Windows-Resource-Datei.rc), dann sollte dieses Icon von nun an für Dateien des verknüpften Dateityps angezeigt werden.

Benutze die DocumentWindow-Quellen

DocumentWindow.h

// ————————————————————————————————-
/**
 * @file
 * @brief
 * @author Gerolf Reinwardt
 * @date 30. march 2011
 *
 * Copyright © 2011, Gerolf Reinwardt. All rights reserved.
 *
 * Simplified BSD License
 *
 * Redistribution and use in source and binary forms, with or without modification, are
 * permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 * conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 * of conditions and the following disclaimer in the documentation and/or other materials
 * provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * The views and conclusions contained in the software and documentation are those of the
 * authors and should not be interpreted as representing official policies, either expressed
 * or implied, of Gerolf Reinwardt.
 */
// ————————————————————————————————-

#ifndef WIDGET_H
#define WIDGET_H

// —— general includes —————————————————————————
#include <windows.h>
#include <QMainWindow>

// —— local includes —————————————————————————-
// —— pre defines ——————————————————————————-

// —— class definition —————————————————————————
/'''*
 * @short This class implements a main window with the ability to register file types on MS Windows and
 * react on the corresponding DDE events to open / print the files in an Windows MDI typical manner.
 *
 * The usage is fairly easy. Derive your own MainWindow class from DocumentWindow instead of QMainWindow.
 * Inside your constructor, call registerFileType and enableShellOpen. The axample is build on top of the
 * Qt MDI Example (http://doc.qt.nokia.com/4.7/mainwindows-mdi.html)
 *
 * @code
 MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags flags) :
 DocumentWindow(parent, flags)
 {
 

registerFileType("GiMdi.Document", "MDI Text Editor Document", ".gidoc", 0, true);
 enableShellOpen();

setWindowTitle(tr("MDI"));
 setUnifiedTitleAndToolBarOnMac(true);
 }
 @endcode
 *
 * Aditionally, the actions must be performed by overwriting one or more of:
 * @li ddeOpenFile
 * @li ddeNewFile
 * @li ddePrintFile
 * @li executeUnknownDdeCommand
 *
 * @code
 void MainWindow::ddeOpenFile(const QString& filePath)
 {
 MdiChild '''child = createMdiChild();
 if (child->loadFile(filePath))
 {
 statusBar()->showMessage(tr("File loaded"), 2000);
 child->show();
 }
 else
 {
 child->close();
 }
 }
 @endcode
'''
 */
class DocumentWindow : public QMainWindow
{
 Q_OBJECT
public:
 // —— enums ———————————————————————————
 /'''*
 * Known DDE command. These commands are typically used
 */
 enum DdeCommand {
 DDEOpen = 0x0001, /< open a file via explorer*/
 DDENew = 0x0002, /*'''< create a new file via explorer*/
 DDEPrint = 0x0004, /*'''< print a file via explorer*/
 };
 Q_DECLARE_FLAGS(DdeCommands, DdeCommand)

// —— construction —————————————————————————
 /**
 * Constructor.
 *
 * Creates a DocumentWindow with a given @arg parent and @arg flags.
 */
 explicit DocumentWindow(QWidget''' parent = 0, Qt::WindowFlags flags = 0);

/**
 * Destructor
 */
 ~DocumentWindow();

 // —— operators ——————————————————————————
 // —— methods ——————————————————————————-
 // —— accessors ——————————————————————————
 // —— members ——————————————————————————-

protected:
 // —— events ———————————————————————————
 /'''*
 * reimpl as DDE events come as windows events and are not translated by Qt.
 */
 virtual bool winEvent(MSG *message, long '''result);

 // —— helpers for the file registration ——————————————————
 /'''*
 * virtual function that must be implemented by the derived class to react to the open command
 * from Windows.
 *
 * @param filePath file that was selected in the explorer
 */
 virtual void ddeOpenFile(const QString& filePath);

 /'''*
 * virtual function that must be implemented by the derived class to react to the new command
 * from Windows.
 *
 * @param filePath file that was selected in the explorer
 */
 virtual void ddeNewFile(const QString& filePath);

 /'''*
 * virtual function that must be implemented by the derived class to react to the print command
 * from Windows.
 *
 * @param filePath file that was selected in the explorer
 */
 virtual void ddePrintFile(const QString& filePath);

 /'''*
 * virtual function that must be implemented by get custom dde commands from the explorer. If, e.g.
 * a printo or copy command should be available in explorer and they are registered via registerCommand,
 * this function is called.
 *
 * @param command name of the command
 * @param params parameter string, containing the hole stuff, also " and commas.
 *
 * @note a command like this [compare("%1")] will result in the parameters:
 command = "compare";
 params = "quot;<filepath>quot;";
 */
 virtual void executeUnknownDdeCommand(const QString& command, const QString& params);

 /'''*
 * Call this method to register the file type in Windows. It creates the default command
 * which means the app is started with the file to open as parameter. If @arg registerForDDE
 * is true, the dde events are also created so the opening of a file is done in typical MDI
 * behavior (all files open in the same app).
 *
 * @param documentId id of the document, typically <Application>.Document > see in registry, e.g. "GiMdi.Document"
 * @param fileTypeName free name of the file type, e.g. "MDI Text Editor Document"
 * @param fileExtension File extension, including the dot (e.g. ".gidoc")
 * @param appIconIndex index of the app icon to use for the file in the windows explorer, typically the application icon
 * @param registerForDDE true if DDE should be used (typical for MDI apps), typically false for SDI apps.
 * @param commands a combination of the commands to install.
 *
 * @note If more then the default commands are needed, then subsequent calls of registerCommand are needed.
 *
 * @note DDEOpen leads to the DDE command: [open("%1)]
 DDENew leads to the DDE command: [new("%1)]
 DDEPrint leads to the DDE command: [print("%1)]
 */
 void registerFileType(const QString& documentId,
 const QString& fileTypeName,
 const QString& fileExtension,
 qint32 appIconIndex = 0,
 bool registerForDDE = false,
 DdeCommands commands = DDEOpen);

 /'''*
 * registeres one command for a given file type. It is called for the pre defined DDE command
 * types from registerFileType. if more then the normal commands are needed, it can be called
 * in addition to registerFileType.
 *
 * @code
 MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags flags) :
 DocumentWindow(parent, flags)
 {
 

registerFileType("GiMdi.Document", "MDI Text Editor Document", ".gidoc", 0, true);
 registerCommand("fancyCommand", "GiMdi.Document", "-fancy %1", "[fancy(quot;%1quot;)]");
 enableShellOpen();

 
 }
 @endcode
 */
 void registerCommand(const QString& command,
 const QString& documentId,
 const QString cmdLineArg = QString::null,
 const QString ddeCommand = QString::null);

 /'''*
 * Call this method to enable the user to open data files associated with your application
 * by double-clicking the files in the windows file manager.
 *
 * Use it together with registerFileType to register the fspezified file types or provida a
 * registry file ('''.reg) which does this.
*/
 void enableShellOpen();


private:
 // —— privat helpers ————————————————————————
 /**
 * implementation of the WM_DDE_INITIATE windows message
 */
 bool ddeInitiate(MSG''' message, long* result);

 /**
 * implementation of the WM_DDE_EXECUTE windows message
 */
 bool ddeExecute(MSG''' message, long* result);

 /**
 * implementation of the WM_DDE_TERMINATE windows message
 */
 bool ddeTerminate(MSG''' message, long* result);

 /**
 * Sets specified value in the registry under HKCU\Software\Classes, which is mapped to HKCR then.
 */
 bool SetHkcrUserRegKey(QString key, const QString& value, const QString& valueName = QString::null);

 /'''*
 * this method is called to do the DDE command handling. It does argument splitting and then calls
 * ddeOpenFile, ddeNewFile, ddePrintFile or executeUnknownDdeCommand.
 */
 void executeDdeCommand(const QString& command, const QString& params);

 // —— members ——————————————————————————-
 bool m_registerForDDE; /< used to identfy, if the dde commands should be written to the registry*/
 QString m_appAtomName; /*'''< the name of the application, without file extension*/
 QString m_systemTopicAtomName; /*'''< the name of the system topic atom, typically "System"*/
 ATOM m_appAtom; /*'''< The windows atom needed for DDE communication*/
 ATOM m_systemTopicAtom; /*'''< The windows system topic atom needed for DDE communication*/
 // —— not allowed members ——————————————————————-
};

Q_DECLARE_OPERATORS_FOR_FLAGS(DocumentWindow::DdeCommands)

#endif // WIDGET_H

DocumentWindow.cpp

// ————————————————————————————————-
/**
 * @file
 * @brief
 * @author Gerolf Reinwardt
 * @date 30.01.2011
 *
 * Copyright © 2011, Gerolf Reinwardt. All rights reserved.
 *
 * Simplified BSD License
 *
 * Redistribution and use in source and binary forms, with or without modification, are
 * permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 * conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 * of conditions and the following disclaimer in the documentation and/or other materials
 * provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * The views and conclusions contained in the software and documentation are those of the
 * authors and should not be interpreted as representing official policies, either expressed
 * or implied, of Gerolf Reinwardt.
 */
// ————————————————————————————————-

// —— general includes —————————————————————————
#include <windows.h>
#include <QMessageBox>
#include <QApplication>
#include <QDir>
#include <QFileInfo>
#include <QRegExp>

// —— local includes —————————————————————————-
#include "documentwindow.h"


// —— construction ——————————————————————————
DocumentWindow::DocumentWindow(QWidget''' parent, Qt::WindowFlags flags) :
 QMainWindow(parent, flags),
 m_registerForDDE(false),
 m_appAtomName(),
 m_systemTopicAtomName("system"),
 m_appAtom(0),
 m_systemTopicAtom(0)
{
 QFileInfo fi(qApp->applicationFilePath());
 m_appAtomName = fi.baseName();
}

DocumentWindow::~DocumentWindow()
{
 if(0 != m_appAtom)
 {
 ::GlobalDeleteAtom(m_appAtom);
 m_appAtom = 0;
 }
 if(0 != m_systemTopicAtom)
 {
 ::GlobalDeleteAtom(m_systemTopicAtom);
 m_systemTopicAtom = 0;
 }
}

// —— operators ———————————————————————————
// —— methods ————————————————————————————
// —— accessors ———————————————————————————
// —— public slots ——————————————————————————
// —— protected slots —————————————————————————
// —— events ————————————————————————————
bool DocumentWindow::winEvent(MSG *message, long '''result)
{
 switch(message->message)
 {
 case WM_DDE_INITIATE:
 return ddeInitiate(message, result);
 break;
 case WM_DDE_EXECUTE:
 return ddeExecute(message, result);
 break;
 case WM_DDE_TERMINATE:
 return ddeTerminate(message, result);
 break;
 }

 return QMainWindow::winEvent(message, result);
}

void DocumentWindow::ddeOpenFile(const QString&)
{
 // this method will be overwritten, if the application uses the dde open command
}

void DocumentWindow::ddeNewFile(const QString&)
{
 // this method will be overwritten, if the application uses the dde new command
}

void DocumentWindow::ddePrintFile(const QString&)
{
 // this method will be overwritten, if the application uses the dde print command
}

void DocumentWindow::executeUnknownDdeCommand(const QString&, const QString&)
{
 // this method will be overwritten, if the application uses other commands,
 // then open, new and print via DDE and Explorer
}

void DocumentWindow::registerFileType(const QString& documentId,
 const QString& fileTypeName,
 const QString& fileExtension,
 qint32 appIconIndex,
 bool registerForDDE,
 DdeCommands commands)
{
 // first register the type ID of our server
 if (!SetHkcrUserRegKey(documentId, fileTypeName))
 return;

 if (!SetHkcrUserRegKey(QString("%1DefaultIcon").arg(documentId),
 QString("quot;%1quot;,%2").arg(QDir::toNativeSeparators(qApp->applicationFilePath())).arg(appIconIndex)))
 return;

 m_registerForDDE = registerForDDE;

 if(commands & DDEOpen)
 registerCommand("Open", documentId, "quot;%1quot;", "[open(quot;%1quot;)]");
 if(commands & DDENew)
 registerCommand("New", documentId, "-new quot;%1quot;", "[new(quot;%1quot;)]");
 if(commands & DDEPrint)
 registerCommand("Print", documentId, "-print quot;%1quot;", "[print(quot;%1quot;)]");

 LONG lSize = _MAX_PATH * 2;
 wchar_t szTempBuffer[_MAX_PATH * 2];
 LONG lResult = ::RegQueryValue(HKEY_CLASSES_ROOT,
 (const wchar_t*)fileExtension.utf16(),
 szTempBuffer,
 &lSize);

 QString temp = QString::fromUtf16((unsigned short*)szTempBuffer);

 if (lResult != ERROR_SUCCESS || temp.isEmpty() || temp == documentId)
 {
 // no association for that suffix
 if (!SetHkcrUserRegKey(fileExtension, documentId))
 return;

 SetHkcrUserRegKey(QString("%1ShellNew").arg(fileExtension), QLatin1String(""), QLatin1String("NullFile"));
 }
}

void DocumentWindow::registerCommand(const QString& command,
 const QString& documentId,
 const QString cmdLineArg,
 const QString ddeCommand)
{
 QString commandLine = QDir::toNativeSeparators(qApp->applicationFilePath());
 commandLine.prepend(QLatin1String("quot;"));
 commandLine.append(QLatin1String("quot;"));

 if(!cmdLineArg.isEmpty())
 {
 commandLine.append(QChar(' '));
 commandLine.append(cmdLineArg);
 }

 if (!SetHkcrUserRegKey(QString("%1shell%2command").arg(documentId).arg(command), commandLine))
 return; // just skip it

 if(m_registerForDDE)
 {
 if (!SetHkcrUserRegKey(QString("%1shell%2ddeexec").arg(documentId).arg(command), ddeCommand))
 return;

 if (!SetHkcrUserRegKey(QString("%1shell%2ddeexecapplication").arg(documentId).arg(command), m_appAtomName))
 return;

 if (!SetHkcrUserRegKey(QString("%1shell%2ddeexectopic").arg(documentId).arg(command), m_systemTopicAtomName))
 return;
 }
}

void DocumentWindow::enableShellOpen()
{
 if((0 != m_appAtom) || (0 != m_systemTopicAtom))
 return;

 m_appAtom = ::GlobalAddAtomW((const wchar_t''')m_appAtomName.utf16());
 m_systemTopicAtom = ::GlobalAddAtomW((const wchar_t*)m_systemTopicAtomName.utf16());
}

// —— private slots ——————————————————————————
// —— private helpers —————————————————————————
bool DocumentWindow::ddeInitiate(MSG* message, long* result)
{
 if( (0 != LOWORD (message->lParam)) &&
 (0 != HIWORD (message->lParam)) &&
 (LOWORD (message->lParam)  m_appAtom) &&
        (HIWORD(message->lParam)  m_systemTopicAtom))
 {
 // make duplicates of the incoming atoms (really adding a reference)
 wchar_t atomName[_MAX_PATH];
 Q_ASSERT(::GlobalGetAtomNameW(m_appAtom, atomName, _MAX_PATH - 1) != 0);
 Q_ASSERT(::GlobalAddAtomW(atomName)  m_appAtom);
        Q_ASSERT(::GlobalGetAtomNameW(m_systemTopicAtom, atomName, _MAX_PATH - 1) != 0);
        Q_ASSERT(::GlobalAddAtomW(atomName)  m_systemTopicAtom);

// send the WM_DDE_ACK (caller will delete duplicate atoms)
 ::SendMessage((HWND)message->wParam, WM_DDE_ACK, (WPARAM)winId(), MAKELPARAM (m_appAtom, m_systemTopicAtom));
 }
 '''result = 0;
 return true;
}

bool DocumentWindow::ddeExecute(MSG''' message, long* result)
{
 // unpack the DDE message
 UINT_PTR unused;
 HGLOBAL hData;
 //IA64: Assume DDE LPARAMs are still 32-bit
 Q_ASSERT(::UnpackDDElParam(WM_DDE_EXECUTE, message->lParam, &unused, (UINT_PTR*)&hData));

QString command = QString::fromWCharArray((LPCWSTR)::GlobalLock(hData));
 ::GlobalUnlock(hData);

// acknowledge now - before attempting to execute
 ::PostMessage((HWND)message->wParam, WM_DDE_ACK, (WPARAM)winId(),
 //IA64: Assume DDE LPARAMs are still 32-bit
 ReuseDDElParam(message->lParam, WM_DDE_EXECUTE, WM_DDE_ACK, (UINT)0x8000, (UINT_PTR)hData));

// don't execute the command when the window is disabled
 if (!isEnabled())
 {
 '''result = 0;
 return true;
 }

 QRegExp regCommand("<sup>$");
 if(regCommand.exactMatch(command))
 {
 executeDdeCommand(regCommand.cap(1), regCommand.cap(2));
 }

 '''result = 0;
 return true;
}

bool DocumentWindow::ddeTerminate(MSG''' message, long* result)
{
 // The client or server application should respond by posting a WM_DDE_TERMINATE message.
 ::PostMessageW((HWND)message->wParam, WM_DDE_TERMINATE, (WPARAM)winId(), message->lParam);
 return true;
}

bool DocumentWindow::SetHkcrUserRegKey(QString key, const QString& value, const QString& valueName)
{
 HKEY hKey;

 key.prepend("SoftwareClasses");

 LONG lRetVal = RegCreateKey(HKEY_CURRENT_USER,
 (const wchar_t*)key.utf16(),
 &hKey);

 if(ERROR_SUCCESS == lRetVal)
 {
 LONG lResult = ::RegSetValueExW(hKey,
 valueName.isEmpty() ? 0 : (const wchar_t*)valueName.utf16(),
 0,
 REG_SZ,
 (CONST BYTE*)value.utf16(),
 (value.length() + 1) * sizeof(wchar_t));

 if(::RegCloseKey(hKey)  ERROR_SUCCESS && lResult  ERROR_SUCCESS)
 return true;

 QMessageBox::warning(0, QString("Error in setting Registry values"),
 QString("registration database update failed for key '%s'.").arg(key));
 }
 else
 {
 wchar_t buffer[4096];
 ::FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, 0, lRetVal, 0, buffer, 4096, 0);
 QString szText = QString::fromUtf16((const ushort*)buffer);
 QMessageBox::warning(this, QString("Error in setting Registry values"), szText);
 }
 return false;
}

void DocumentWindow::executeDdeCommand(const QString& command, const QString& params)
{
 QRegExp regCommand("</sup>quot;(.''')quot;$");
 bool singleCommand = regCommand.exactMatch(params);
 if((0  command.compare("open", Qt::CaseInsensitive)) && singleCommand)
    {
        ddeOpenFile(regCommand.cap(1));
    }
    else if((0  command.compare("new", Qt::CaseInsensitive)) && singleCommand)
 {
 ddeNewFile(regCommand.cap(1));
 }
 else if((0 == command.compare("print", Qt::CaseInsensitive)) && singleCommand)
 {
 ddePrintFile(regCommand.cap(1));
 }
 else
 {
 executeUnknownDdeCommand(command, params);
 }
}

You may use this code without any warranty.

Zukünftige Erweiterung

The class might be extended so it also works on Linux or Mac. The code of the class and a demo project are located on gitorious in the following repository: qtdevnet-registereditorfiletype Die Klasse könnte so erweitert werden, dass sie auch unter Linux und Mac OS funktioniert. Die Quellen der Klasse und ein Demonstratorprojekt finden sich in diesem Gitorious-Repository: qtdevnet-registereditorfiletype

Versionen

Die aktuelle Versionsnummer des Codes ist 1.

Version 1

Dies ist die erste Veröffentlichung.

Rückmeldungen

Ich würde mich wirklich sehr über Rückmeldungen zu dieser Klasse freuen. Wenn dir Schwächen auffallen, informiere mich bitte darüber. Für Diskussionen bezüglich dieses Wikis benutze bitte diesen Forums-Thread .