/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
DECL_LINK(ImpNotifyHdl, void*, void);
DECL_LINK(ImpNotifyXferHdl, void*, void); void Notify(WPARAM nEvent); // called by shim communication thread to notify me void NotifyXFer(LPARAM nHandle); // called by shim communication thread to notify me
Twain::ShimListenerThread::ShimListenerThread(const VclPtr<vcl::Window>& xTopWindow)
: salhelper::Thread("TWAINShimListenerThread")
, mxTopWindow(xTopWindow)
{ if (mxTopWindow)
{
mxTopWindow->IncModalCount(); // the operation is modal to the frame
}
}
Twain::ShimListenerThread::~ShimListenerThread()
{ if (mxTopWindow)
{
mxTopWindow->DecModalCount(); // unblock the frame
}
}
void Twain::ShimListenerThread::NotifyOwner(WPARAM nEvent)
{ if (!mbDontNotify)
aTwain.Notify(nEvent);
}
void Twain::ShimListenerThread::NotifyXFerOwner(LPARAM nHandle)
{ if (!mbDontNotify)
aTwain.NotifyXFer(nHandle);
}
// May only be called from the own thread, so no threading issues modifying self void Twain::ShimListenerThread::NotificationHdl(WPARAM nEvent, LPARAM lParam)
{ switch (nEvent)
{ case TWAIN_EVENT_NOTIFYHWND: // shim reported its main HWND for communications if (!mcInitCompleted.check()) // only if not yet initialized!
{ // Owner is still waiting mcInitCompleted in its Twain::InitializeNewShim, // holding its access mutex
mhWndShim = reinterpret_cast<HWND>(lParam);
mbInitSucceeded = lParam != 0;
mcInitCompleted.set();
} break; case TWAIN_EVENT_SCANNING:
NotifyOwner(nEvent); break; case TWAIN_EVENT_XFER:
NotifyXFerOwner(lParam); break; case TWAIN_EVENT_REQUESTRESULT:
mbRequestResult = lParam;
mcGotRequestResult.set(); break; // We don't handle TWAIN_EVENT_QUIT notification from shim, because we send it ourselves // in the end of execute()
}
}
// Spawn a separate 32-bit process to use TWAIN on Windows, and listen for its notifications void Twain::ShimListenerThread::execute()
{
MSG msg; // Initialize thread message queue before launching shim process
PeekMessageW(&msg, nullptr, 0, 0, PM_NOREMOVE);
OUString sCmdLine; if (osl::FileBase::getSystemPathFromFileURL(shimURL, sCmdLine) != osl::FileBase::E_None) throw std::exception("getSystemPathFromFileURL failed!");
HANDLE hDup; if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(),
&hDup, SYNCHRONIZE | THREAD_QUERY_LIMITED_INFORMATION, TRUE, 0))
ThrowLastError("DuplicateHandle"); // we will not need our copy as soon as shim has its own inherited one
ScopedHANDLE hScopedDup(hDup);
sal_uIntPtr nDup = reinterpret_cast<sal_uIntPtr>(hDup); if constexpr (sizeof(sal_uIntPtr) > 4) if (nDup > 0xFFFFFFFF) throw std::exception("HANDLE does not fit to 32 bit - cannot pass to shim!");
// Send this thread handle as the first parameter
sCmdLine = "\"" + sCmdLine + "\" " + OUString::number(nDup);
// We need a WinAPI HANDLE of the process to be able to wait on it and detect the process // termination; so use WinAPI to start the process, not osl_executeProcess.
CloseHandle(pi.hThread);
hShimProcess.reset(pi.hProcess);
}
HANDLE h = hShimProcess.get(); while (true)
{
DWORD nWaitResult = MsgWaitForMultipleObjects(1, &h, FALSE, INFINITE, QS_POSTMESSAGE); // Process any messages in queue before checking if we need to break, to not loose // possible pending notifications while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE))
{ // process it here if (msg.message == WM_TWAIN_EVENT)
{
NotificationHdl(msg.wParam, msg.lParam);
}
} if (nWaitResult == WAIT_OBJECT_0)
{ // shim process exited - return break;
} if (nWaitResult == WAIT_FAILED)
{ // Some Win32 error - report and return
ThrowLastError("MsgWaitForMultipleObjects");
}
}
} catch (const std::exception& e)
{
msErrorReported = OUString(e.what(), strlen(e.what()), RTL_TEXTENCODING_UTF8); // allow owner to resume (in case the condition isn't set yet)
mcInitCompleted.set(); // let mbInitSucceeded keep its (maybe false) value!
} // allow owner to resume (in case the conditions isn't set yet)
mcGotRequestResult.set();
NotifyOwner(TWAIN_EVENT_QUIT);
}
bool Twain::InitializeNewShim(ScannerManager& rMgr, const VclPtr<vcl::Window>& xTopWindow)
{
osl::MutexGuard aGuard(maMutex); if (mpThread) returnfalse; // Have a shim for another task already!
// hold reference to ScannerManager, to prevent premature death
mxMgr = mpCurMgr = &rMgr;
mpThread.set(new ShimListenerThread(xTopWindow));
mpThread->launch(); constbool bSuccess = mpThread->WaitInitialization(); if (!bSuccess)
Reset();
if (rContext.InternalData != 0 || rContext.ScannerName != "TWAIN") throw ScannerException("Scanner does not exist", xThis, ScanError_InvalidContext);
ReleaseData();
VclPtr<vcl::Window> xTopWindow = ImplGetActiveFrameWindow(); if (xTopWindow)
xTopWindow
->IncModalCount(); // to avoid changes between the two operations that each block the window
comphelper::ScopeGuard aModalGuard([xTopWindow]() { if (xTopWindow)
xTopWindow->DecModalCount();
});
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.