Skip to content

Commit

Permalink
Improve compatibility with MinGW
Browse files Browse the repository at this point in the history
Removes Windows APIs that MinGW doesn't support, namely ATL.
  • Loading branch information
oblivioncth committed Oct 10, 2024
1 parent 3329206 commit bb1833d
Show file tree
Hide file tree
Showing 9 changed files with 194 additions and 81 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ project(Qx

# Get helper scripts
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/FetchOBCMake.cmake)
fetch_ob_cmake("v0.3.7")
fetch_ob_cmake("e7e1e091fd3b95dcd33e168f7faffa9d33d3b2a7")

# Initialize project according to standard rules
include(OB/Project)
Expand Down
6 changes: 3 additions & 3 deletions lib/core/src/qx-system_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ quint32 processId(QString processName)
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);

HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

if(Process32First(snapshot, &entry))
{
Expand Down Expand Up @@ -100,7 +100,7 @@ QString processName(quint32 processId)
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);

HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);


if(Process32First(snapshot, &entry))
Expand Down Expand Up @@ -138,7 +138,7 @@ QList<quint32> processChildren(quint32 processId, bool recursive)
QList<quint32> cPids = {processId};

// Initialize snapshot
if(HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL))
if(HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0))
{
// Initialize entry data holder
PROCESSENTRY32 procEntry;
Expand Down
5 changes: 5 additions & 0 deletions lib/windows-gui/src/qx-taskbarbutton.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@

// Windows Includes
#include "qx_windows.h"
#ifdef Q_CC_MINGW // MinGW headers for this are less fine-grained
#include "Shlobj.h"
#else
#include "ShlObj_core.h"
#endif

// Intra-component Includes
#include "qx/windows-gui/qx-winguievent.h"
Expand Down
2 changes: 2 additions & 0 deletions lib/windows/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ qx_add_component("Windows"
qx-windefs.h
IMPLEMENTATION
qx-common-windows.cpp
qx-common-windows_p.h
qx-common-windows_p.cpp
qx-filedetails.cpp
DOC_ONLY
qx-windefs.dox
Expand Down
28 changes: 25 additions & 3 deletions lib/windows/include/qx_windows.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,26 @@
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
// ifdefs are to avoid macro redefinition warnings
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOATOM
#define NOATOM
#endif
#ifndef NOGDI
#define NOGDI
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
#ifndef NOSOUND
#define NOSOUND
#endif
#ifndef NOHELP
#define NOHELP
#endif
#ifndef NOMCX
#define NOMCX
#endif

#include "windows.h"
#include "ShObjIdl_core.h"

// See windows.h for more "NOXXX" options
126 changes: 53 additions & 73 deletions lib/windows/src/qx-common-windows.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Unit Includes
#include "qx/windows/qx-common-windows.h"
#include "qx-common-windows_p.h"

// Qt Includes
#include <QFile>
Expand All @@ -9,12 +10,14 @@
// Windows Includes
#include "qx_windows.h"
#include "TlHelp32.h"
#include "comdef.h"
#include "ShlGuid.h"
#include "atlbase.h"
#ifdef Q_CC_MINGW // MinGW headers for this are less fine-grained
#include "Shlobj.h"
#else
#include "ShlObj_core.h"
#endif
#include <wrl/client.h>

// Extra-component Includes
#include "qx/core/qx-bitarray.h"
#include "qx/core/qx-system.h"

/*!
Expand Down Expand Up @@ -380,6 +383,7 @@ SystemError getLastError()
return SystemError::fromHresult(HRESULT_FROM_WIN32(error));
}


/*!
* Creates a shortcut on the user's filesystem at the path @a shortcutPath, with the given
* shortcut properties @a sp.
Expand All @@ -390,83 +394,59 @@ SystemError createShortcut(QString shortcutPath, ShortcutProperties sp)
if(sp.target.isEmpty() || shortcutPath.isEmpty() || sp.iconIndex < 0)
return SystemError::fromHresult(E_INVALIDARG);

// Working vars
HRESULT hRes;
CComPtr<IShellLink> ipShellLink;

// Get full path of target
QFileInfo targetInfo(sp.target);
QString fullTargetPath = targetInfo.absoluteFilePath();


// Get a pointer to the IShellLink interface
auto getIShellLinkPtr = [](CComPtr<IShellLink>& ptrShellLnk){
return CoCreateInstance(CLSID_ShellLink,
NULL,
CLSCTX_INPROC_SERVER,
IID_IShellLink,
(void**)&ptrShellLnk);
};

hRes = getIShellLinkPtr(ipShellLink);

// Handle the case for if the COM server wasn't already initialized in this thread
QScopeGuard COMGuard([]{ CoUninitialize(); });
if(hRes == CO_E_NOTINITIALIZED)
// Ensure COM is ready
ScopedCom com;
if(!com)
return com.error();

// Access IShelLink interface
using namespace Microsoft::WRL;
ComPtr<IShellLink> ipShellLink;
HRESULT hRes = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&ipShellLink));
if(FAILED(hRes))
return SystemError::fromHresult(hRes);

// Get a pointer to the IPersistFile interface
ComPtr<IPersistFile> ipPersistFile;
hRes = ipShellLink.As(&ipPersistFile);
if(FAILED(hRes))
return SystemError::fromHresult(hRes);

// Set shortcut properties
// NOTE: The string casts here are only valid on Windows where wchat_t is 2-bytes in size
QString tgtPath = QFileInfo(sp.target).absoluteFilePath();
hRes = ipShellLink->SetPath((const wchar_t*)tgtPath.utf16());
if(FAILED(hRes)) return SystemError::fromHresult(hRes);

if(!sp.targetArgs.isEmpty())
{
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
hRes = getIShellLinkPtr(ipShellLink);
hRes = ipShellLink->SetArguments((const wchar_t*)sp.targetArgs.utf16());
if (FAILED(hRes)) return SystemError::fromHresult(hRes);
}
else
COMGuard.dismiss();

// Commence shortcut creation if COM server was properly connected to
if(SUCCEEDED(hRes))
if(!sp.startIn.isEmpty())
{
// Get a pointer to the IPersistFile interface
CComQIPtr<IPersistFile> ipPersistFile(ipShellLink);

// Set shortcut properties
hRes = ipShellLink->SetPath((const wchar_t*)fullTargetPath.utf16());
if(FAILED(hRes))
return SystemError::fromHresult(hRes);

if(!sp.targetArgs.isEmpty())
{
hRes = ipShellLink->SetArguments((const wchar_t*)sp.targetArgs.utf16());
if (FAILED(hRes))
return SystemError::fromHresult(hRes);
}

if(!sp.startIn.isEmpty())
{
hRes = ipShellLink->SetWorkingDirectory((const wchar_t*)sp.startIn.utf16());
if (FAILED(hRes))
return SystemError::fromHresult(hRes);
}

if(!sp.comment.isEmpty())
{
hRes = ipShellLink->SetDescription((const wchar_t*)sp.comment.utf16());
if (FAILED(hRes))
return SystemError::fromHresult(hRes);
}

if(!sp.iconFilePath.isEmpty())
{
hRes = ipShellLink->SetIconLocation((const wchar_t*)sp.iconFilePath.utf16(), sp.iconIndex);
if (FAILED(hRes))
return SystemError::fromHresult(hRes);
}
hRes = ipShellLink->SetWorkingDirectory((const wchar_t*)sp.startIn.utf16());
if (FAILED(hRes)) return SystemError::fromHresult(hRes);
}

hRes = ipShellLink->SetShowCmd(nativeShowMode(sp.showMode));
if(FAILED(hRes))
return SystemError::fromHresult(hRes);
if(!sp.comment.isEmpty())
{
hRes = ipShellLink->SetDescription((const wchar_t*)sp.comment.utf16());
if (FAILED(hRes)) return SystemError::fromHresult(hRes);
}

// Write the shortcut to disk
hRes = ipPersistFile->Save((const wchar_t*)shortcutPath.utf16(), TRUE);
if(!sp.iconFilePath.isEmpty())
{
hRes = ipShellLink->SetIconLocation((const wchar_t*)sp.iconFilePath.utf16(), sp.iconIndex);
if (FAILED(hRes)) return SystemError::fromHresult(hRes);
}

hRes = ipShellLink->SetShowCmd(nativeShowMode(sp.showMode));
if(FAILED(hRes)) return SystemError::fromHresult(hRes);

// Write the shortcut to disk
hRes = ipPersistFile->Save((const wchar_t*)shortcutPath.utf16(), TRUE);
return SystemError::fromHresult(hRes);
}

Expand Down
67 changes: 67 additions & 0 deletions lib/windows/src/qx-common-windows_p.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Unit Includes
#include "qx-common-windows_p.h"

// Qt Includes
#include <QCoreApplication>
#include <QThread>

// Windows Includes
#include "combaseapi.h"

namespace Qx
{
//===============================================================================================================
// ScopedCom
//===============================================================================================================

//-Constructor--------------------------------------------------------------------------------------------------
//Public:
ScopedCom::ScopedCom() :
mThreadId(GetCurrentThreadId()),
mCleanup(false)
{
// Check if COM is initialized (parameter return values are ignored)
APTTYPE aptType;
APTTYPEQUALIFIER aptTypeQualifier;
HRESULT hRes = CoGetApartmentType(&aptType, &aptTypeQualifier);
if(SUCCEEDED(hRes))
return; // COM is ready, do nothing
else if(hRes != CO_E_NOTINITIALIZED)
{
// True error
mError = SystemError::fromHresult(hRes);
return;
}

// Init COM (shouldn't ever be needed in the main thread, but we check just in-case)
auto app = QCoreApplication::instance();
bool inMainThread = app && app->thread() == QThread::currentThread(); // TODO: Use Qt 6.8 isMainThread()
int tm = (inMainThread ? COINIT_APARTMENTTHREADED : COINIT_MULTITHREADED) | COINIT_DISABLE_OLE1DDE;
hRes = CoInitializeEx(NULL, tm);
if(!SUCCEEDED(hRes)) // Should never fail, but hey...
{
mError = SystemError::fromHresult(hRes);
return;
}

mCleanup = true;
}

//-Destructor--------------------------------------------------------------------------------------------------
//Public:
ScopedCom::~ScopedCom()
{
Q_ASSERT(mThreadId == GetCurrentThreadId());
if(mCleanup)
CoUninitialize();
}

//-Instance Functions--------------------------------------------------------------------------------------------
//Public:
bool ScopedCom::hasError() const { return mError.isValid(); }
SystemError ScopedCom::error() const { return mError; }

//-Operators--------------------------------------------------------------------------------------------
//Public:
ScopedCom::operator bool() const { return !hasError(); }
}
37 changes: 37 additions & 0 deletions lib/windows/src/qx-common-windows_p.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#ifndef QX_WINDOWS_COMMON_P_H
#define QX_WINDOWS_COMMON_P_H

// Qt Includes
#include <QtClassHelperMacros>

// Inter-component Includes
#include "qx/windows/qx-windefs.h"

// Extra-component Includes
#include "qx/core/qx-systemerror.h"

namespace Qx
{

// Makes sure COM is initialized, and cleans up on deletion.
// Based on QComHelper, but slightly more flexible in that it just cares COM is initialized one way or another.
class ScopedCom
{
Q_DISABLE_COPY_MOVE(ScopedCom);
private:
SystemError mError;
DWORD mThreadId; // For safety check
bool mCleanup;

public:
ScopedCom();
~ScopedCom();

bool hasError() const;
SystemError error() const;
explicit operator bool() const;
};


}
#endif // QX_WINDOWS_COMMON_P_H
2 changes: 1 addition & 1 deletion lib/windows/src/qx-filedetails.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ FileDetails FileDetails::readFileDetails(QString filePath)
{
DWORD verInfoHandle, verInfoSize = GetFileVersionInfoSize((const wchar_t*)filePath.utf16(), &verInfoHandle);

if (verInfoSize != NULL)
if (verInfoSize != 0)
{
LPSTR verInfo = new char[verInfoSize];

Expand Down

0 comments on commit bb1833d

Please sign in to comment.