diff --git a/CMakeLists.txt b/CMakeLists.txt index e174b40..406a4f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,78 @@ -cmake_minimum_required(VERSION 2.6) -project(NTop C) +cmake_minimum_required(VERSION 3.8) + +project(NTop + LANGUAGES + C + CXX +) option(ENABLE_UNICODE "Compile with Unicode support" OFF) -if(ENABLE_UNICODE) - add_definitions(-DUNICODE -D_UNICODE) -endif() +add_executable(${PROJECT_NAME} + ntop.c + util.c + vi.c +) + +target_compile_definitions(${PROJECT_NAME} + PRIVATE + $<$: + UNICODE + _UNICODE + > +) + +target_link_libraries(${PROJECT_NAME} + PRIVATE + WindowsApp + wbemuuid +) + +target_compile_features(${PROJECT_NAME} + PRIVATE cxx_std_17 +) + +# Temporary fix for C++/WinRT bug +target_compile_options(${PROJECT_NAME} + PRIVATE /permissive +) + +find_package(WIL CONFIG REQUIRED) + +add_executable(wmi + main.c + wmi.cpp +) + +target_link_libraries(wmi + PRIVATE + WindowsApp + wbemuuid + WIL::WIL +) + +target_compile_features(wmi + PRIVATE + cxx_std_17 +) + +# Temporary fix for C++/WinRT bug +target_compile_options(wmi + PRIVATE /permissive +) + +add_executable(test + main.cpp +) + +target_link_libraries(test + PRIVATE + WindowsApp + wbemuuid + WIL::WIL +) -add_executable(NTop ntop.c util.c vi.c) +target_compile_features(test + PRIVATE + cxx_std_17 +) diff --git a/main.c b/main.c new file mode 100644 index 0000000..3b92774 --- /dev/null +++ b/main.c @@ -0,0 +1,23 @@ +#include "wmi.h" + +#include + +#include +#include + +int main() +{ + struct WMI* wmi = NewWMIService(); + + int* loads = NULL; + size_t count = 0; + for(int i = 0; i < 1000 ; ++i) + { + WMIQueryProcessorTime(wmi, &loads, &count); + for(size_t c = 0 ; c < count; ++c) printf("%d\n", loads[c]); + printf("\n"); fflush(NULL); + Sleep(500); + } + + CloseWMIService(wmi); +} \ No newline at end of file diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..9092f00 --- /dev/null +++ b/main.cpp @@ -0,0 +1,148 @@ +// Configuration defines +#define _WIN32_DCOM +#define WIL_ENABLE_EXCEPTIONS + +#include + +#include + +// C++/WinRT includes +#include + +#include + +#include +#include + +int main() +{ + try + { + winrt::init_apartment(); + + auto locator = winrt::create_instance(CLSID_WbemLocator); + winrt::com_ptr services; + winrt::check_hresult(locator->ConnectServer( + wil::make_bstr(LR"(ROOT\CIMV2)").get(), + nullptr, nullptr, + 0, 0, 0, 0, + services.put())); + + winrt::check_hresult(CoSetProxyBlanket( + services.get(), + RPC_C_AUTHN_WINNT, + RPC_C_AUTHZ_NONE, + nullptr, + RPC_C_AUTHN_LEVEL_CALL, + RPC_C_IMP_LEVEL_IMPERSONATE, + nullptr, + EOAC_NONE)); + + auto refresher = winrt::create_instance(CLSID_WbemRefresher); + winrt::com_ptr config; + winrt::check_hresult(refresher->QueryInterface(config.put())); + + winrt::com_ptr enumerator; + long id; + winrt::check_hresult(config->AddEnum( + services.get(), + L"Win32_PerfFormattedData_PerfOS_Processor", + 0, + nullptr, + enumerator.put(), + &id)); + + // Obtain queried object count (using empty buffer for result storage) + winrt::check_hresult(refresher->Refresh(0L)); + ULONG processor_enum_count = [&]() // IILE + { + ULONG count; + auto hresult = enumerator->GetObjects( + 0L, + 0, + nullptr, + &count + ); + if (hresult != WBEM_E_BUFFER_TOO_SMALL) + throw std::runtime_error{"Expecting WBEM_E_BUFFER_TOO_SMALL obtaining object count, got something else."}; + + return count; + }(); + + // Obtain and remember property handles + auto obtain_property_handle = [&](const wchar_t* property_name) + { + std::vector> enum_accessors(processor_enum_count); + ULONG count; + winrt::check_hresult(enumerator->GetObjects( + 0L, + processor_enum_count, + reinterpret_cast(enum_accessors.data()), + &count)); + + CIMTYPE type; + long handle; + winrt::check_hresult(enum_accessors[0]->GetPropertyHandle( + property_name, + &type, + &handle)); + + return handle; + }; + long percent_user_time_handle = obtain_property_handle(L"PercentUserTime"), + percent_privileged_time_handle = obtain_property_handle(L"PercentPrivilegedTime"), + percent_processor_time_handle = obtain_property_handle(L"PercentProcessorTime"); + + std::vector> enum_accessors(processor_enum_count); + for(int I = 0 ; I < 10 ; ++I) + { + winrt::check_hresult(refresher->Refresh(0L)); + + ULONG count; + // Assumes that the layout of winrt::com_ptr is the same as the stored winrt::impl::abi_t + winrt::check_hresult(enumerator->GetObjects( + 0L, + static_cast(enum_accessors.size()), + reinterpret_cast(enum_accessors.data()), + &count)); + + // Loop over core loads. (Last entry seems to be an avarage of all cores.) + for (size_t i = 0 ; i < std::thread::hardware_concurrency() ; ++i) + { + auto read_uint64_t_property = [&](long handle) + { + long bytes_read; + std::uint64_t result; + winrt::check_hresult(enum_accessors[i]->ReadPropertyValue( + handle, + sizeof(std::uint64_t), + &bytes_read, + reinterpret_cast(&result))); + + return result; + }; + + std::cout << + read_uint64_t_property(percent_user_time_handle) << "\t" << + read_uint64_t_property(percent_privileged_time_handle) << "\t" << + read_uint64_t_property(percent_processor_time_handle) << "\t" << + std::endl; + } + + std::cout << std::endl; + std::this_thread::sleep_for(std::chrono::seconds{1}); + } + } + catch(winrt::hresult_error& err) + { + std::wcerr << err.message().c_str() << " (" << err.code() << ")" << std::endl; + std::exit(err.code()); + } + catch(std::exception& err) + { + std::cerr << err.what() << std::endl; + std::exit(-1); + } + + return 0; +} \ No newline at end of file diff --git a/ntop.c b/ntop.c index 9b0798c..d249fb9 100644 --- a/ntop.c +++ b/ntop.c @@ -44,8 +44,6 @@ static int Width; static int Height; static int OldWidth; static int OldHeight; -static int SizeX; -static int SizeY; static const int ProcessWindowPosY = 6; static DWORD ProcessWindowHeight; static DWORD VisibleProcessCount; @@ -811,9 +809,6 @@ static BOOL PollConsoleInfo(void) return TRUE; } - SizeX = (int)Csbi.dwSize.X; - SizeY = (int)Csbi.dwSize.Y; - if(SavedAttributes == 0) SavedAttributes = Csbi.wAttributes; @@ -994,6 +989,49 @@ static int DrawPercentageBar(TCHAR *Name, double Percentage, WORD Color) return CharsWritten; } +static int LogicalCoreBardWidth; + +// Used to calculate the number of bars that should be drawn. +// NOTE: This may not be the maximum of numbers to be drawn, as +// the percentage indicator overlays on top of the bars. +static int CalculateLogicalCoreBarWidth(const int ConsoleWidth) +{ + // ConsoleWidth - Left&Right Margin - BarCount * (CoreNumLabel + []) + return ConsoleWidth - 4 - 4*(3 + 2); +} + +static int LogicalCoreCount; +static int* LogicalCoreLoads; + +static int DrawLogicalCoresPercentageBars() +{/* + int CharsWritten = 0; + + SetColor(Config.FGHighlightColor); + CharsWritten += ConPrintf(_T(" %s"), Name); + SetColor(Config.FGColor); + ConPutc('['); + CharsWritten++; + + int Bars = (int)((double)BAR_WIDTH * Percentage); + SetColor(Color); + for(int i = 0; i < Bars; i++) { + ConPutc('|'); + } + CharsWritten+= Bars; + SetColor(Config.FGColor); + for(int i = 0; i < BAR_WIDTH - Bars; i++) { + ConPutc(' '); + } + CharsWritten += BAR_WIDTH - Bars; + SetColor(Config.BGColor); + CharsWritten += ConPrintf(_T("%04.1f%%"), 100.0 * Percentage); + SetColor(Config.FGColor); + ConPutc(']'); + CharsWritten++; + return CharsWritten; +*/} + static void RestoreConsole(void) { SetConsoleActiveScreenBuffer(OldConsoleHandle); diff --git a/wmi.cpp b/wmi.cpp new file mode 100644 index 0000000..ea336c8 --- /dev/null +++ b/wmi.cpp @@ -0,0 +1,97 @@ +// Configuration defines +#define _WIN32_DCOM +#define WIL_ENABLE_EXCEPTIONS + +#include + +#include + +// C++/WinRT includes +#include + +#include + +#include +#include + +struct WMI +{ + winrt::impl::com_ref locator; + winrt::com_ptr services; + + std::vector loads; +}; + +extern "C" +{ + WMI* NewWMIService() + { + winrt::init_apartment(); + + WMI* wmi = new WMI{}; + + wmi->locator = winrt::create_instance(CLSID_WbemLocator); + winrt::check_hresult(wmi->locator->ConnectServer( + wil::make_bstr(LR"(ROOT\CIMV2)").get(), + nullptr, nullptr, + 0, 0, 0, 0, + wmi->services.put()) + ); + + winrt::check_hresult(CoSetProxyBlanket( + wmi->services.get(), + RPC_C_AUTHN_WINNT, + RPC_C_AUTHZ_NONE, + nullptr, + RPC_C_AUTHN_LEVEL_CALL, + RPC_C_IMP_LEVEL_IMPERSONATE, + nullptr, + EOAC_NONE) + ); + + wmi->loads.resize(std::thread::hardware_concurrency()); + + return wmi; + } + + int WMIQueryProcessorTime(WMI* wmi, int** loads, size_t* count) + { + winrt::com_ptr enumerator; + winrt::check_hresult(wmi->services->ExecQuery( + L"WQL", + L"SELECT PercentProcessorTime FROM Win32_PerfFormattedData_PerfOS_Processor WHERE Name <> '_Total'", + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, + nullptr, + enumerator.put()) + ); + + for (size_t i = 0 ; i < wmi->loads.size() ; ++i) + { + winrt::com_ptr class_object; + ULONG ret; + winrt::check_hresult(enumerator->Next( + WBEM_INFINITE, + 1, + class_object.put(), + &ret) + ); + + if (ret == 0) { break; } + + wil::unique_variant percent; + winrt::check_hresult(class_object->Get( L"PercentProcessorTime", 0, percent.addressof(), nullptr, nullptr)); + + wmi->loads.at(i) = std::stoi(percent.bstrVal); + + *loads = wmi->loads.data(); + *count = wmi->loads.size(); + } + + return 0; + } + + void CloseWMIService(WMI* wmi) + { + delete wmi; + } +} diff --git a/wmi.h b/wmi.h new file mode 100644 index 0000000..2b5f778 --- /dev/null +++ b/wmi.h @@ -0,0 +1,17 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct WMI WMI; + +WMI* NewWMIService(); + +int WMIQueryProcessorTime(WMI* wmi, int** loads, size_t* count); + +void CloseWMIService(WMI* wmi); + +#ifdef __cplusplus +} +#endif