Montag, 16. August 2010

Acrobat PDF Viewer einbetten

Für die Anzeige von PDF-Dateien innerhalb unseres KiS verwenden wir den Acrobat Reader als ActiveX Modul. Ein (anscheinend schon lange bekannter) Fehler bis zur Acrobat Reader Version 9.3.3 bringt bei betätigen der Tab-Taste innerhalb des Acrobat Reader Fensters das Programm zum Absturz.

Die einzige Möglichkeit den Fehler zu verhindern ist die TAB-Taste innerhalb der Windows-Nachrichtenschleife des Programms abzufangen. Unsere Lösung für die Qt-Klassenbibliothek:
//Erstellen des Controlsviewer()->setControl("AcroPDF.PDF");
WId wid = viewer()->winId();
if (m_AdobeWindows.isEmpty())
{  //Installieren des Event-Filters im eventDispatcher
prevFilter = QAbstractEventDispatcher::instance()->setEventFilter( ::eventFilter );
}
//Eintragen des Windows-Handle in die Liste der zu überwachenden Fenster
m_AdobeWindows.append(wid);

Beim Beenden des Controls wird der Viewer aus der Liste ausgetragen:
if (!viewer()->isNull())
{
m_AdobeWindows.removeAll( viewer()->winId() );
//Wenn keine Controls mehr überwacht werden wird der EventFilter wieder zurückgesetzt.
if (m_AdobeWindows.isEmpty())
{
QAbstractEventDispatcher::instance()->setEventFilter( prevFilter );
}
}

Der Event-Dispatcher sieht folgendermassen aus:
//Liste der zu überwachenden Fenster
QList m_AdobeWindows;
//Nimmt einen ggf. bereits gesetzten EventFilter auf
static QAbstractEventDispatcher::EventFilter prevFilter = 0;

static bool eventFilter(void *message)
{  LPMSG msg = (LPMSG)message;
//Diese Message ist der Auslöser für die Schutzverletzung
if (msg->message == 0x1450)
{
//Hier prüfen wir ob der Adressat der Nachricht ein Kindfenster des Controls ist 
HWND wnd = msg->hwnd;
while (wnd != NULL)
{
if (m_AdobeWindows.contains(wnd))
{
//Falls der Empfänger also ein Kindfenster unseres Controls ist, dann schlucken wir die Nachricht -> Keine Schutzverletzung im Reader mehr.
return true;
}
wnd = GetParent( wnd );
}
}
if (prevFilter) return prevFilter(message);
return false;
}

Besser wäre natürlich das Fenster-Handle des Readers direkt bei der Initialisierung des Controls zu holen, den Aufwand über die entsprechenden OLE-Interfaces zu gehen wollten wir uns hier sparen.

Hier ist der Adobe-Thread in dem ich die Anregung für die obige Lösung gefunden habe

Keine Kommentare:

Kommentar veröffentlichen