blob: 08b9db3c8014affff2afab7bfbf922c6951b53fb [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_fpicker.hxx"
//------------------------------------------------------------------------
// includes
//------------------------------------------------------------------------
#include <stdio.h>
#include <osl/diagnose.h>
#include "getfilenamewrapper.hxx"
#if defined _MSC_VER
#pragma warning(push, 1)
#endif
#include <objbase.h>
#include <process.h>
#if defined _MSC_VER
#pragma warning(pop)
#endif
namespace /* private */
{
//-----------------------------------------------
// This class prevents changing of the working
// directory.
//-----------------------------------------------
class CurDirGuard
{
sal_Bool m_bValid;
wchar_t* m_pBuffer;
DWORD m_nBufLen;
public:
CurDirGuard()
: m_bValid( sal_False )
, m_pBuffer( NULL )
, m_nBufLen( 0 )
{
m_nBufLen = GetCurrentDirectoryW( 0, NULL );
if ( m_nBufLen )
{
m_pBuffer = new wchar_t[m_nBufLen];
m_bValid = ( GetCurrentDirectoryW( m_nBufLen, m_pBuffer ) == ( m_nBufLen - 1 ) );
}
}
~CurDirGuard()
{
bool bDirSet = false;
if ( m_pBuffer )
{
if ( m_bValid )
{
if ( m_nBufLen - 1 > MAX_PATH )
{
if ( (LONG32)GetVersion() < 0 )
{
// this is Win 98/ME branch, such a long path can not be set
// use the system path as fallback later
}
else
{
DWORD nNewLen = m_nBufLen + 8;
wchar_t* pNewBuffer = new wchar_t[nNewLen];
if ( m_nBufLen > 3 && m_pBuffer[0] == (wchar_t)'\\' && m_pBuffer[1] == (wchar_t)'\\' )
{
if ( m_pBuffer[2] == (wchar_t)'?' )
_snwprintf( pNewBuffer, nNewLen, L"%s", m_pBuffer );
else
_snwprintf( pNewBuffer, nNewLen, L"\\\\?\\UNC\\%s", m_pBuffer+2 );
}
else
_snwprintf( pNewBuffer, nNewLen, L"\\\\?\\%s", m_pBuffer );
bDirSet = SetCurrentDirectoryW( pNewBuffer );
delete [] pNewBuffer;
}
}
else
bDirSet = SetCurrentDirectoryW( m_pBuffer );
}
delete [] m_pBuffer;
m_pBuffer = NULL;
}
if ( !bDirSet )
{
// the fallback solution
wchar_t pPath[MAX_PATH+1];
if ( GetWindowsDirectoryW( pPath, MAX_PATH+1 ) <= MAX_PATH )
{
SetCurrentDirectoryW( pPath );
}
else
{
// the system path is also too long?!!
}
}
}
};
//-----------------------------------------------
//
//-----------------------------------------------
struct GetFileNameParam
{
GetFileNameParam(bool bOpen, LPOPENFILENAME lpofn) :
m_bOpen(bOpen),
m_lpofn(lpofn),
m_bRet(false),
m_ExtErr(0)
{}
bool m_bOpen;
LPOPENFILENAME m_lpofn;
bool m_bRet;
int m_ExtErr;
};
//-----------------------------------------------
//
//-----------------------------------------------
unsigned __stdcall ThreadProc(void* pParam)
{
CurDirGuard aGuard;
GetFileNameParam* lpgfnp =
reinterpret_cast<GetFileNameParam*>(pParam);
HRESULT hr = OleInitialize( NULL );
if (lpgfnp->m_bOpen)
lpgfnp->m_bRet = GetOpenFileName(lpgfnp->m_lpofn);
else
lpgfnp->m_bRet = GetSaveFileName(lpgfnp->m_lpofn);
lpgfnp->m_ExtErr = CommDlgExtendedError();
if ( SUCCEEDED( hr ) )
OleUninitialize();
return 0;
}
//-----------------------------------------------
// exceutes GetOpenFileName/GetSaveFileName in
// a separat thread
//-----------------------------------------------
bool ThreadExecGetFileName(LPOPENFILENAME lpofn, bool bOpen, /*out*/ int& ExtErr)
{
GetFileNameParam gfnp(bOpen,lpofn);
unsigned id;
HANDLE hThread = reinterpret_cast<HANDLE>(
_beginthreadex(0, 0, ThreadProc, &gfnp, 0, &id));
OSL_POSTCOND(hThread, "could not create STA thread");
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
ExtErr = gfnp.m_ExtErr;
return gfnp.m_bRet;
}
//-----------------------------------------------
// This function returns true if the calling
// thread belongs to a Multithreaded Appartment
// (MTA)
//-----------------------------------------------
bool IsMTA()
{
HRESULT hr = CoInitialize(NULL);
if (RPC_E_CHANGED_MODE == hr)
return true;
if(SUCCEEDED(hr))
CoUninitialize();
return false;
}
} // namespace private
//-----------------------------------------------
//
//-----------------------------------------------
CGetFileNameWrapper::CGetFileNameWrapper() :
m_ExtendedDialogError(0)
{
}
//-----------------------------------------------
//
//-----------------------------------------------
bool CGetFileNameWrapper::getOpenFileName(LPOPENFILENAME lpofn)
{
OSL_PRECOND(lpofn,"invalid parameter");
bool bRet = false;
if (IsMTA())
{
bRet = ThreadExecGetFileName(
lpofn, true, m_ExtendedDialogError);
}
else
{
CurDirGuard aGuard;
HRESULT hr = OleInitialize( NULL );
bRet = GetOpenFileName(lpofn);
m_ExtendedDialogError = CommDlgExtendedError();
if ( SUCCEEDED( hr ) )
OleUninitialize();
}
return bRet;
}
//-----------------------------------------------
//
//-----------------------------------------------
bool CGetFileNameWrapper::getSaveFileName(LPOPENFILENAME lpofn)
{
OSL_PRECOND(lpofn,"invalid parameter");
bool bRet = false;
if (IsMTA())
{
bRet = ThreadExecGetFileName(
lpofn, false, m_ExtendedDialogError);
}
else
{
CurDirGuard aGuard;
bRet = GetSaveFileName(lpofn);
m_ExtendedDialogError = CommDlgExtendedError();
}
return bRet;
}
//-----------------------------------------------
//
//-----------------------------------------------
int CGetFileNameWrapper::commDlgExtendedError( )
{
return m_ExtendedDialogError;
}