Skip to content

Commit

Permalink
add logs to the files explorer integration DLL
Browse files Browse the repository at this point in the history
Signed-off-by: Matthieu Gallien <[email protected]>
  • Loading branch information
mgallien committed Mar 19, 2024
1 parent 747efd4 commit d017e1d
Show file tree
Hide file tree
Showing 11 changed files with 72 additions and 27 deletions.
27 changes: 20 additions & 7 deletions shell_integration/windows/NCContextMenu/NCClientInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,58 +26,71 @@
#include <sstream>
#include <iterator>
#include <unordered_set>
#include <locale>
#include <codecvt>

using namespace std;

#define PIPE_TIMEOUT 5*1000 //ms

NCClientInterface::ContextMenuInfo NCClientInterface::FetchInfo(const std::wstring &files)
NCClientInterface::ContextMenuInfo NCClientInterface::FetchInfo(const std::wstring &files, std::ofstream &logger)

Check warning on line 36 in shell_integration/windows/NCContextMenu/NCClientInterface.cpp

View workflow job for this annotation

GitHub Actions / build

shell_integration/windows/NCContextMenu/NCClientInterface.cpp:36:55 [modernize-use-trailing-return-type]

use a trailing return type for this function
{
auto pipename = CommunicationSocket::DefaultPipePath();

CommunicationSocket socket;
if (!WaitNamedPipe(pipename.data(), PIPE_TIMEOUT)) {
logger << "error with WaitNamedPipe" << std::endl;
return {};
}
if (!socket.Connect(pipename)) {
logger << "error with Connect" << std::endl;
return {};
}
socket.SendMsg(L"GET_STRINGS:CONTEXT_MENU_TITLE\n");
socket.SendMsg((L"GET_MENU_ITEMS:" + files + L"\n").data());
socket.SendMsg(L"GET_STRINGS:CONTEXT_MENU_TITLE\n", logger);
socket.SendMsg((L"GET_MENU_ITEMS:" + files + L"\n").data(), logger);

ContextMenuInfo info;
std::wstring response;
int sleptCount = 0;
while (sleptCount < 20) {
logger << "trying to read a line" << std::endl;
if (socket.ReadLine(&response)) {
logger << "received: " << converter.to_bytes(response) << std::endl;
if (StringUtil::begins_with(response, wstring(L"REGISTER_PATH:"))) {
logger << "received: REGISTER_PATH" << std::endl;
wstring responsePath = response.substr(14); // length of REGISTER_PATH
info.watchedDirectories.push_back(responsePath);
}
else if (StringUtil::begins_with(response, wstring(L"STRING:"))) {
logger << "received: STRING" << std::endl;
wstring stringName, stringValue;

Check warning on line 66 in shell_integration/windows/NCContextMenu/NCClientInterface.cpp

View workflow job for this annotation

GitHub Actions / build

shell_integration/windows/NCContextMenu/NCClientInterface.cpp:66:17 [readability-isolate-declaration]

multiple declarations in a single statement reduces readability
if (!StringUtil::extractChunks(response, stringName, stringValue))
continue;
if (stringName == L"CONTEXT_MENU_TITLE")
info.contextMenuTitle = move(stringValue);
} else if (StringUtil::begins_with(response, wstring(L"MENU_ITEM:"))) {
logger << "received: MENU_ITEM" << std::endl;
wstring commandName, flags, title;

Check warning on line 73 in shell_integration/windows/NCContextMenu/NCClientInterface.cpp

View workflow job for this annotation

GitHub Actions / build

shell_integration/windows/NCContextMenu/NCClientInterface.cpp:73:17 [readability-isolate-declaration]

multiple declarations in a single statement reduces readability
if (!StringUtil::extractChunks(response, commandName, flags, title))
continue;
info.menuItems.push_back({ commandName, flags, title });
} else if (StringUtil::begins_with(response, wstring(L"GET_MENU_ITEMS:END"))) {
logger << "received: GET_MENU_ITEMS:END" << std::endl;
break; // Stop once we completely received the last sent request
} else {
logger << "received: another reply" << std::endl;
}
}
else {
} else {
logger << "received nothing" << std::endl;
Sleep(50);
++sleptCount;
}
}

return info;
}

void NCClientInterface::SendRequest(const wchar_t *verb, const std::wstring &path)
void NCClientInterface::SendRequest(const wchar_t *verb, const std::wstring &path, std::ofstream &logger)
{
auto pipename = CommunicationSocket::DefaultPipePath();

Expand All @@ -89,5 +102,5 @@ void NCClientInterface::SendRequest(const wchar_t *verb, const std::wstring &pat
return;
}

socket.SendMsg((verb + (L":" + path + L"\n")).data());
socket.SendMsg((verb + (L":" + path + L"\n")).data(), logger);
}
5 changes: 3 additions & 2 deletions shell_integration/windows/NCContextMenu/NCClientInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <mutex>
#include <atomic>
#include <condition_variable>
#include <fstream>

class CommunicationSocket;

Expand All @@ -52,8 +53,8 @@ class NCClientInterface
};
std::vector<MenuItem> menuItems;
};
static ContextMenuInfo FetchInfo(const std::wstring &files);
static void SendRequest(const wchar_t *verb, const std::wstring &path);
static ContextMenuInfo FetchInfo(const std::wstring &files, std::ofstream &logger);
static void SendRequest(const wchar_t *verb, const std::wstring &path, std::ofstream &logger);
};

#endif //ABSTRACTSOCKETHANDLER_H
20 changes: 18 additions & 2 deletions shell_integration/windows/NCContextMenu/NCContextMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,22 @@
#include <StringUtil.h>
#include <strsafe.h>

#include <iostream>
#include <fstream>

extern long g_cDllRef;

Check warning on line 27 in shell_integration/windows/NCContextMenu/NCContextMenu.cpp

View workflow job for this annotation

GitHub Actions / build

shell_integration/windows/NCContextMenu/NCContextMenu.cpp:27:13 [cppcoreguidelines-avoid-non-const-global-variables]

variable 'g_cDllRef' is non-const and globally accessible, consider making it const

NCContextMenu::NCContextMenu(void)
: m_cRef(1)
{
InterlockedIncrement(&g_cDllRef);
m_logger.open("c:\\test.log");
m_logger << "hello world" << std::endl;
}

NCContextMenu::~NCContextMenu(void)
{
m_logger << "NCContextMenu::~NCContextMenu" << std::endl;
InterlockedDecrement(&g_cDllRef);
}

Expand All @@ -39,6 +45,7 @@ NCContextMenu::~NCContextMenu(void)
// Query to the interface the component supported.
IFACEMETHODIMP NCContextMenu::QueryInterface(REFIID riid, void **ppv)
{
m_logger << "NCContextMenu::QueryInterface" << std::endl;
static const QITAB qit[] =
{
QITABENT(NCContextMenu, IContextMenu),
Expand All @@ -51,12 +58,14 @@ IFACEMETHODIMP NCContextMenu::QueryInterface(REFIID riid, void **ppv)
// Increase the reference count for an interface on an object.
IFACEMETHODIMP_(ULONG) NCContextMenu::AddRef()
{
m_logger << "NCContextMenu::AddRef" << std::endl;
return InterlockedIncrement(&m_cRef);
}

// Decrease the reference count for an interface on an object.
IFACEMETHODIMP_(ULONG) NCContextMenu::Release()
{
m_logger << "NCContextMenu::Release" << std::endl;
ULONG cRef = InterlockedDecrement(&m_cRef);
if (0 == cRef) {
delete this;
Expand All @@ -74,6 +83,7 @@ IFACEMETHODIMP_(ULONG) NCContextMenu::Release()
IFACEMETHODIMP NCContextMenu::Initialize(
LPCITEMIDLIST, LPDATAOBJECT pDataObj, HKEY)
{
m_logger << "NCContextMenu::Initialize" << std::endl;
m_selectedFiles.clear();

if (!pDataObj) {
Expand Down Expand Up @@ -129,17 +139,20 @@ void InsertSeperator(HMENU hMenu, UINT indexMenu)

IFACEMETHODIMP NCContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
{
m_logger << "NCContextMenu::QueryContextMenu" << std::endl;
// If uFlags include CMF_DEFAULTONLY then we should not do anything.
if (CMF_DEFAULTONLY & uFlags)
{
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));
}

m_info = NCClientInterface::FetchInfo(m_selectedFiles);
m_info = NCClientInterface::FetchInfo(m_selectedFiles, m_logger);
if (m_info.menuItems.empty()) {
m_logger << "NCContextMenu::QueryContextMenu " << "empty info" << std::endl;
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));
}

m_logger << "NCContextMenu::QueryContextMenu" << "insert separator" << std::endl;
InsertSeperator(hMenu, indexMenu++);

HMENU hSubmenu = CreateMenu();
Expand All @@ -153,6 +166,7 @@ IFACEMETHODIMP NCContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT
if (!InsertMenuItem(hMenu, indexMenu++, TRUE, &mii))
return HRESULT_FROM_WIN32(GetLastError());
}
m_logger << "NCContextMenu::QueryContextMenu" << "insert separator" << std::endl;
InsertSeperator(hMenu, indexMenu++);

UINT indexSubMenu = 0;
Expand All @@ -179,6 +193,7 @@ IFACEMETHODIMP NCContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT

IFACEMETHODIMP NCContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
{
m_logger << "NCContextMenu::InvokeCommand" << std::endl;
std::wstring command;

CMINVOKECOMMANDINFOEX *piciEx = nullptr;
Expand Down Expand Up @@ -215,13 +230,14 @@ IFACEMETHODIMP NCContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
return E_FAIL;
}

NCClientInterface::SendRequest(command.data(), m_selectedFiles);
NCClientInterface::SendRequest(command.data(), m_selectedFiles, m_logger);
return S_OK;
}

IFACEMETHODIMP NCContextMenu::GetCommandString(UINT_PTR idCommand,
UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax)
{
m_logger << "NCContextMenu::GetCommandString" << std::endl;
if (idCommand < m_info.menuItems.size() && uFlags == GCS_VERBW) {
return StringCchCopyW(reinterpret_cast<PWSTR>(pszName), cchMax,
m_info.menuItems[idCommand].command.data());
Expand Down
8 changes: 7 additions & 1 deletion shell_integration/windows/NCContextMenu/NCContextMenu.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@
#define NCCONTEXTMENU_H

#pragma once
#include "NCClientInterface.h"

#include <shlobj.h> // For IShellExtInit and IContextMenu

#include <string>
#include "NCClientInterface.h"
#include <fstream>
#include <iostream>

class NCContextMenu : public IShellExtInit, public IContextMenu
{
Expand Down Expand Up @@ -48,6 +52,8 @@ class NCContextMenu : public IShellExtInit, public IContextMenu
// The name of the selected files (separated by '\x1e')
std::wstring m_selectedFiles;
NCClientInterface::ContextMenuInfo m_info;

std::ofstream m_logger;
};

#endif //NCCONTEXTMENU_H
10 changes: 6 additions & 4 deletions shell_integration/windows/NCOverlays/NCOverlay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,22 +35,24 @@ namespace {

unique_ptr<RemotePathChecker> s_instance;

RemotePathChecker *getGlobalChecker()
RemotePathChecker *getGlobalChecker(ofstream &logger)

Check warning on line 38 in shell_integration/windows/NCOverlays/NCOverlay.cpp

View workflow job for this annotation

GitHub Actions / build

shell_integration/windows/NCOverlays/NCOverlay.cpp:38:20 [modernize-use-trailing-return-type]

use a trailing return type for this function
{
// On Vista we'll run into issue #2680 if we try to create the thread+pipe connection
// on any DllGetClassObject of our registered classes.
// Work around the issue by creating the static RemotePathChecker only once actually needed.
static once_flag s_onceFlag;
call_once(s_onceFlag, [] { s_instance.reset(new RemotePathChecker); });
call_once(s_onceFlag, [&logger] { s_instance.reset(new RemotePathChecker{logger}); });

return s_instance.get();
}

}
NCOverlay::NCOverlay(int state)
NCOverlay::NCOverlay(int state)

Check warning on line 50 in shell_integration/windows/NCOverlays/NCOverlay.cpp

View workflow job for this annotation

GitHub Actions / build

shell_integration/windows/NCOverlays/NCOverlay.cpp:50:1 [cppcoreguidelines-pro-type-member-init]

constructor does not initialize these fields: ULONG, m_logger
: _referenceCount(1)
, _state(state)
{
m_logger.open("c:\\testOverlay.log");
m_logger << "hello world" << std::endl;
}

NCOverlay::~NCOverlay(void)
Expand Down Expand Up @@ -120,7 +122,7 @@ IFACEMETHODIMP NCOverlay::GetPriority(int *pPriority)

IFACEMETHODIMP NCOverlay::IsMemberOf(PCWSTR pwszPath, DWORD dwAttrib)
{
RemotePathChecker* checker = getGlobalChecker();
RemotePathChecker* checker = getGlobalChecker(m_logger);
std::shared_ptr<const std::vector<std::wstring>> watchedDirectories = checker->WatchedDirectories();

if (watchedDirectories->empty()) {
Expand Down
6 changes: 4 additions & 2 deletions shell_integration/windows/NCOverlays/NCOverlay.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@
#pragma once

#include <shlobj.h>

Check failure on line 20 in shell_integration/windows/NCOverlays/NCOverlay.h

View workflow job for this annotation

GitHub Actions / build

shell_integration/windows/NCOverlays/NCOverlay.h:20:10 [clang-diagnostic-error]

'shlobj.h' file not found
#include <fstream>

class NCOverlay : public IShellIconOverlayIdentifier

{
public:
NCOverlay(int state);
explicit NCOverlay(int state);

IFACEMETHODIMP_(ULONG) AddRef();
IFACEMETHODIMP GetOverlayInfo(PWSTR pwszIconFile, int cchMax, int *pIndex, DWORD *pdwFlags);
Expand All @@ -38,6 +39,7 @@ class NCOverlay : public IShellIconOverlayIdentifier
private:
long _referenceCount;
int _state;
std::ofstream m_logger;
};

#endif
#endif
4 changes: 3 additions & 1 deletion shell_integration/windows/NCUtil/CommunicationSocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,10 @@ bool CommunicationSocket::Connect(const std::wstring &pipename)
return true;
}

bool CommunicationSocket::SendMsg(const wchar_t* message) const
bool CommunicationSocket::SendMsg(const wchar_t* message, std::ofstream &logger) const
{
logger << "CommunicationSocket::SendMsg: " << (*message) << std::endl;

auto utf8_msg = StringUtil::toUtf8(message);

DWORD numBytesWritten = 0;
Expand Down
3 changes: 2 additions & 1 deletion shell_integration/windows/NCUtil/CommunicationSocket.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include <string>

Check failure on line 22 in shell_integration/windows/NCUtil/CommunicationSocket.h

View workflow job for this annotation

GitHub Actions / build

shell_integration/windows/NCUtil/CommunicationSocket.h:22:10 [clang-diagnostic-error]

'string' file not found
#include <vector>
#include <fstream>
#include <WinSock2.h>

class __declspec(dllexport) CommunicationSocket
Expand All @@ -34,7 +35,7 @@ class __declspec(dllexport) CommunicationSocket
bool Connect(const std::wstring& pipename);
bool Close();

bool SendMsg(const wchar_t*) const;
bool SendMsg(const wchar_t*, std::ofstream &logger) const;
bool ReadLine(std::wstring*);

HANDLE Event() { return _pipe; }
Expand Down
8 changes: 4 additions & 4 deletions shell_integration/windows/NCUtil/RemotePathChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
using namespace std;

// This code is run in a thread
void RemotePathChecker::workerThreadLoop()
void RemotePathChecker::workerThreadLoop(ofstream &logger)

Check warning on line 33 in shell_integration/windows/NCUtil/RemotePathChecker.cpp

View workflow job for this annotation

GitHub Actions / build

shell_integration/windows/NCUtil/RemotePathChecker.cpp:33:25 [readability-function-cognitive-complexity]

function 'workerThreadLoop' has cognitive complexity of 42 (threshold 25)
{
auto pipename = CommunicationSocket::DefaultPipePath();
bool connected = false;
Expand Down Expand Up @@ -62,7 +62,7 @@ void RemotePathChecker::workerThreadLoop()
lock.unlock();
if (!asked.count(filePath)) {
asked.insert(filePath);
socket.SendMsg(wstring(L"RETRIEVE_FILE_STATUS:" + filePath + L'\n').data());
socket.SendMsg(wstring(L"RETRIEVE_FILE_STATUS:" + filePath + L'\n').data(), logger);
}
lock.lock();
}
Expand Down Expand Up @@ -162,12 +162,12 @@ void RemotePathChecker::workerThreadLoop()



RemotePathChecker::RemotePathChecker()
RemotePathChecker::RemotePathChecker(ofstream &logger)

Check warning on line 165 in shell_integration/windows/NCUtil/RemotePathChecker.cpp

View workflow job for this annotation

GitHub Actions / build

shell_integration/windows/NCUtil/RemotePathChecker.cpp:165:1 [cppcoreguidelines-pro-type-member-init]

constructor does not initialize these fields: _pending, _cache, _watchedDirectories, _newQueries
: _stop(false)
, _watchedDirectories(make_shared<const vector<wstring>>())
, _connected(false)
, _newQueries(CreateEvent(nullptr, FALSE, FALSE, nullptr))
, _thread([this]{ this->workerThreadLoop(); })
, _thread([this, &logger]{ this->workerThreadLoop(logger); })
{
}

Expand Down
7 changes: 4 additions & 3 deletions shell_integration/windows/NCUtil/RemotePathChecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <memory>
#include <mutex>
#include <atomic>
#include <fstream>
#include <condition_variable>

#pragma once
Expand All @@ -36,7 +37,7 @@ class RemotePathChecker {
StateWarning,
StateNone
};
RemotePathChecker();
explicit RemotePathChecker(std::ofstream &logger);
~RemotePathChecker();
std::shared_ptr<const std::vector<std::wstring>> WatchedDirectories() const;
bool IsMonitoredPath(const wchar_t* filePath, int* state);
Expand Down Expand Up @@ -64,7 +65,7 @@ class RemotePathChecker {
HANDLE _newQueries;

std::thread _thread;
void workerThreadLoop();
void workerThreadLoop(std::ofstream &logger);
};

#endif
#endif
1 change: 1 addition & 0 deletions src/gui/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,7 @@ void Application::setupLogging()
logger->setLogExpire(_logExpire > 0 ? _logExpire : ConfigFile().logExpire());
logger->setLogFlush(_logFlush || ConfigFile().logFlush());
logger->setLogDebug(_logDebug || ConfigFile().logDebug());

if (!logger->isLoggingToFile() && ConfigFile().automaticLogDir()) {
logger->setupTemporaryFolderLogDir();
}
Expand Down

0 comments on commit d017e1d

Please sign in to comment.