Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 63 additions & 3 deletions ProcMonX/CSVEventDataSerializer.cpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,76 @@
#include "pch.h"
#include "CSVEventDataSerializer.h"
#include "FormatHelper.h"
#include <fstream>
#include <format>

// Needed for processes like msedge which contain commas in their command line, messing up the csv formatting
void CSVEventDataSerializer::EscapeCsvString(std::wstring& str)
{
if (str.empty()) {
return;
}

std::wstring escapedStr = L"";
for (wchar_t c : str) {
if (c == '\"') {
escapedStr += c;
}
escapedStr += c;
}

str = std::format(L"\"{}\"", escapedStr);
}

std::wstring CSVEventDataSerializer::SerializeEvent(std::shared_ptr<EventData>& event)
{
uint32_t index = event->GetIndex();
DWORD tPid = event->GetProcessId();
DWORD tTid = event->GetThreadId();

std::wstring ts = (std::wstring)FormatHelper::FormatTime(event->GetTimeStamp());
std::wstring name = event->GetEventName();
std::wstring pName = event->GetProcessName();
std::wstring pid = (tPid == (DWORD) - 1) ? L"" : std::to_wstring(tPid);
std::wstring tid = (tTid == (DWORD) - 1) ? L"" : std::to_wstring(tTid);
std::wstring details = L"";

std::vector<EventProperty> props = event->GetProperties();

if (props.size() > 0) {
bool needsEscaping = false;
for (EventProperty& p : props) {
std::wstring pValue = event->FormatProperty(p);
if (!pValue.empty()) {
details += p.Name + L": " + pValue + L"; ";
if (p.Name == L"CommandLine") {
needsEscaping = true;
}
}
}

if (needsEscaping) {
EscapeCsvString(details);
}
}

return std::format(L"{},{},{},{},{},{},{}", index, ts, name, pName, pid, tid, details);
}

bool CSVEventDataSerializer::Save(const std::vector<std::shared_ptr<EventData>>& events, const EventDataSerializerOptions& options, PCWSTR path) {
std::ofstream out;
std::wofstream out;
out.open(path);
if(out.fail())
return false;

for (auto& evt : events) {
out << L"Id,Time Stamp,Event Name,Process Name,PID,TID,Details" << std::endl;

for (std::shared_ptr<EventData> evt : events) {
out << SerializeEvent(evt) << std::endl;
}
return false;

out.close();
return true;
}

std::vector<std::shared_ptr<EventData>> CSVEventDataSerializer::Load(PCWSTR path) {
Expand Down
3 changes: 3 additions & 0 deletions ProcMonX/CSVEventDataSerializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
#include "IEventDataSerializer.h"

class CSVEventDataSerializer : public IEventDataSerializer {
private:
void EscapeCsvString(std::wstring& str);
std::wstring SerializeEvent(std::shared_ptr<EventData>& event);
public:
virtual bool Save(const std::vector<std::shared_ptr<EventData>>& events, const EventDataSerializerOptions& options, PCWSTR path) override;
virtual std::vector<std::shared_ptr<EventData>> Load(PCWSTR path) override;
Expand Down
2 changes: 2 additions & 0 deletions ProcMonX/View.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,8 @@ LRESULT CView::OnSave(WORD, WORD, HWND, BOOL&) {
auto eventsCopy = m_OrgEvents;
if (!serializer->Save(eventsCopy, options, dlg.m_szFileName))
AtlMessageBox(*this, L"Failed to save data", IDS_TITLE, MB_ICONERROR);
else
AtlMessageBox(*this, L"CSV Data saved successfully", IDS_TITLE, MB_ICONINFORMATION);
return 0;
}
}
Expand Down