diff --git a/base/applications/mscutils/CMakeLists.txt b/base/applications/mscutils/CMakeLists.txt index cd3e5511e7c..f6928976b23 100644 --- a/base/applications/mscutils/CMakeLists.txt +++ b/base/applications/mscutils/CMakeLists.txt @@ -1,4 +1,5 @@ +add_subdirectory(certmgr) add_subdirectory(devmgmt) add_subdirectory(eventvwr) add_subdirectory(servman) \ No newline at end of file diff --git a/base/applications/mscutils/certmgr/CCert.hpp b/base/applications/mscutils/certmgr/CCert.hpp new file mode 100644 index 00000000000..97f60912a9e --- /dev/null +++ b/base/applications/mscutils/certmgr/CCert.hpp @@ -0,0 +1,85 @@ +/* + * PROJECT: ReactOS Certificate Manager + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: CCert definition + * COPYRIGHT: Copyright 2025 Mark Jansen + */ + +class CCert +{ + private: + PCCERT_CONTEXT m_CertContext = NULL; + CAtlStringW m_SubjectName; + CAtlStringW m_IssuerName; + CAtlStringW m_FriendlyName; + + void + GetNameString(DWORD dwFlags, CAtlStringW &out) + { + DWORD length = CertGetNameStringW(m_CertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, dwFlags, NULL, NULL, 0); + if (length > 1) + { + WCHAR *buffer = out.GetBuffer(length); + CertGetNameStringW(m_CertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, dwFlags, NULL, buffer, length); + out.ReleaseBuffer(); + } + } + + public: + explicit CCert(_In_ PCCERT_CONTEXT certContext) + { + m_CertContext = CertDuplicateCertificateContext(certContext); + Init(); + } + ~CCert() + { + if (m_CertContext) + { + CertFreeCertificateContext(m_CertContext); + } + } + + const CAtlStringW & + GetSubjectName() const + { + return m_SubjectName; + } + + const CAtlStringW & + GetIssuerName() const + { + return m_IssuerName; + } + + FILETIME + GetNotAfter() const + { + return (m_CertContext && m_CertContext->pCertInfo) ? m_CertContext->pCertInfo->NotAfter : FILETIME{}; + } + + const CAtlStringW & + GetFriendlyName() const + { + return m_FriendlyName; + } + + const PCCERT_CONTEXT + GetCertContext() const + { + return m_CertContext; + } + + void + Init() + { + GetNameString(0, m_SubjectName); + GetNameString(CERT_NAME_ISSUER_FLAG, m_IssuerName); + DWORD length = 0; + if (CertGetCertificateContextProperty(m_CertContext, CERT_FRIENDLY_NAME_PROP_ID, NULL, &length) && length > 0) + { + WCHAR *buffer = m_FriendlyName.GetBuffer(length / sizeof(WCHAR)); + CertGetCertificateContextProperty(m_CertContext, CERT_FRIENDLY_NAME_PROP_ID, buffer, &length); + m_FriendlyName.ReleaseBuffer(); + } + } +}; diff --git a/base/applications/mscutils/certmgr/CMakeLists.txt b/base/applications/mscutils/certmgr/CMakeLists.txt new file mode 100644 index 00000000000..0ce160db56b --- /dev/null +++ b/base/applications/mscutils/certmgr/CMakeLists.txt @@ -0,0 +1,19 @@ + +add_executable(certmgr + certmgr.cpp + certmgr.h + certmgr.rc + resource.h + + CCert.hpp + CStore.hpp + CStoreList.cpp + CStoreList.hpp + CSplitter.hpp + CSortableHeader.hpp +) +set_module_type(certmgr win32gui UNICODE) +target_link_libraries(certmgr uuid cpprt atl_classes) +add_importlibs(certmgr cryptui crypt32 ole32 user32 msvcrt kernel32 ntdll) +add_dependencies(certmgr psdk) +add_cd_file(TARGET certmgr DESTINATION reactos/system32 FOR all) diff --git a/base/applications/mscutils/certmgr/CSortableHeader.hpp b/base/applications/mscutils/certmgr/CSortableHeader.hpp new file mode 100644 index 00000000000..6145c58d7d8 --- /dev/null +++ b/base/applications/mscutils/certmgr/CSortableHeader.hpp @@ -0,0 +1,105 @@ +/* + * PROJECT: ReactOS Certificate Manager + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: CSortableHeader definition + * COPYRIGHT: Copyright 2025 Mark Jansen + */ + +struct CSortableHeader +{ + private: + int m_LastHeaderID = 0; + bool m_Ascending = true; + + public: + struct SortContext + { + CSortableHeader *hdr; + CListView *lvw; + INT iSubItem; + }; + + static INT CALLBACK + s_CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) + { + SortContext *ctx = ((SortContext *)lParamSort); + return ctx->hdr->CompareFunc(lParam1, lParam2, ctx); + } + + INT + CompareFunc(LPARAM lParam1, LPARAM lParam2, SortContext *ctx) + { + const INT iSubItem = ctx->iSubItem; +#define MAX_STR_LEN 256 + + CStringW Item1, Item2; + LVFINDINFOW IndexInfo; + INT Index; + + IndexInfo.flags = LVFI_PARAM; + + IndexInfo.lParam = lParam1; + Index = ctx->lvw->FindItem(-1, &IndexInfo); + ctx->lvw->GetItemText(Index, iSubItem, Item1.GetBuffer(MAX_STR_LEN), MAX_STR_LEN); + Item1.ReleaseBuffer(); + + IndexInfo.lParam = lParam2; + Index = ctx->lvw->FindItem(-1, &IndexInfo); + ctx->lvw->GetItemText(Index, iSubItem, Item2.GetBuffer(MAX_STR_LEN), MAX_STR_LEN); + Item2.ReleaseBuffer(); + + return m_Ascending ? Item1.Compare(Item2) : Item2.Compare(Item1); + } + + void + ColumnClick(CListView &listView, LPNMLISTVIEW pnmv) + { + if ((listView.GetWindowLongPtr(GWL_STYLE) & ~LVS_NOSORTHEADER) == 0) + return; + + ApplySorting(listView, pnmv->iSubItem); + + /* Save new values */ + m_LastHeaderID = pnmv->iSubItem; + m_Ascending = !m_Ascending; + } + + void + ReapplySorting(CListView &listView) + { + if (m_LastHeaderID != -1) + { + ApplySorting(listView, m_LastHeaderID); + } + } + + void + ApplySorting(CListView &listView, INT nHeaderID) + { + HWND hHeader = (HWND)listView.SendMessage(LVM_GETHEADER, 0, 0); + HDITEMW hColumn; + ZeroMemory(&hColumn, sizeof(hColumn)); + + /* If the sorting column changed, remove the sorting style from the old column */ + if ((m_LastHeaderID != -1) && (m_LastHeaderID != nHeaderID)) + { + m_Ascending = TRUE; // also reset sorting method to ascending + hColumn.mask = HDI_FORMAT; + Header_GetItem(hHeader, m_LastHeaderID, &hColumn); + hColumn.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN); + Header_SetItem(hHeader, m_LastHeaderID, &hColumn); + } + + /* Set the sorting style to the new column */ + hColumn.mask = HDI_FORMAT; + Header_GetItem(hHeader, nHeaderID, &hColumn); + + hColumn.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP); + hColumn.fmt |= (m_Ascending ? HDF_SORTUP : HDF_SORTDOWN); + Header_SetItem(hHeader, nHeaderID, &hColumn); + + /* Sort the list, using the current values of nHeaderID and bIsAscending */ + SortContext ctx = {this, &listView, nHeaderID}; + listView.SortItems(s_CompareFunc, &ctx); + } +}; diff --git a/base/applications/mscutils/certmgr/CSplitter.hpp b/base/applications/mscutils/certmgr/CSplitter.hpp new file mode 100644 index 00000000000..6e2aa05edb5 --- /dev/null +++ b/base/applications/mscutils/certmgr/CSplitter.hpp @@ -0,0 +1,117 @@ +/* + * PROJECT: ReactOS Certificate Manager + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: CSortableHeader definition + * COPYRIGHT: Copyright 2025 Mark Jansen + */ + +struct CSplitter +{ + private: + CWindow m_Parent; + CWindow m_Left; + CWindow m_Right; + + int m_splitterPos = 280; + const int m_splitterSize = 4; + + public: + void + Init(CWindow parent, CWindow left, CWindow right) + { + m_Parent = parent; + m_Left = left; + m_Right = right; + } + + void + ResizeWnd(int width, int height) + { + RECT rc; + m_Parent.GetClientRect(&rc); + + HDWP hdwp = BeginDeferWindowPos(2); + + if (hdwp) + hdwp = m_Left.DeferWindowPos( + hdwp, NULL, 0, 0, m_splitterPos - m_splitterSize / 2, height, SWP_NOZORDER | SWP_NOACTIVATE); + if (hdwp) + hdwp = m_Right.DeferWindowPos( + hdwp, NULL, m_splitterPos + m_splitterSize / 2, 0, width - (m_splitterPos + m_splitterSize / 2), height, + SWP_NOZORDER | SWP_NOACTIVATE); + if (hdwp) + EndDeferWindowPos(hdwp); + } + + void + DragSplitter(INT x) + { + m_splitterPos = max(x, 120); + RECT rc; + m_Parent.GetClientRect(&rc); + ResizeWnd(rc.right - rc.left, rc.bottom - rc.top); + } + + LRESULT + OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) + { + ResizeWnd(LOWORD(lParam), HIWORD(lParam)); + return TRUE; + } + + LRESULT + OnSetCursor(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) + { + if (LOWORD(lParam) == HTCLIENT) + { + POINT pt; + GetCursorPos(&pt); + m_Parent.ScreenToClient(&pt); + if (pt.x >= m_splitterPos - m_splitterSize / 2 && pt.x <= m_splitterPos + m_splitterSize / 2) + { + SetCursor(LoadCursor(NULL, IDC_SIZEWE)); + bHandled = TRUE; + return TRUE; + } + } + bHandled = FALSE; + return FALSE; + } + + LRESULT + OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) + { + INT x = GET_X_LPARAM(lParam); + + if (x >= m_splitterPos - m_splitterSize / 2 && x <= m_splitterPos + m_splitterSize / 2) + { + m_Parent.SetCapture(); + + bHandled = TRUE; + return TRUE; + } + + return TRUE; + } + + LRESULT + OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) + { + if (GetCapture() == m_Parent.m_hWnd) + { + DragSplitter(GET_X_LPARAM(lParam)); + } + return TRUE; + } + + LRESULT + OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) + { + if (GetCapture() == m_Parent.m_hWnd) + { + DragSplitter(GET_X_LPARAM(lParam)); + ReleaseCapture(); + } + return TRUE; + } +}; diff --git a/base/applications/mscutils/certmgr/CStore.hpp b/base/applications/mscutils/certmgr/CStore.hpp new file mode 100644 index 00000000000..452021943aa --- /dev/null +++ b/base/applications/mscutils/certmgr/CStore.hpp @@ -0,0 +1,93 @@ +/* + * PROJECT: ReactOS Certificate Manager + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: CStore definition + * COPYRIGHT: Copyright 2025 Mark Jansen + */ + +class CStore +{ + private: + CAtlStringW m_CryptName; + DWORD m_dwFlags; + CAtlStringW m_StoreName; + HCERTSTORE m_hStore = NULL; + CAtlList m_Certificates; + bool m_Expanded = false; + + HCERTSTORE + StoreHandle() + { + if (!m_hStore) + { + m_hStore = CertOpenStore( + CERT_STORE_PROV_SYSTEM_W, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, NULL, + CERT_STORE_SET_LOCALIZED_NAME_FLAG | m_dwFlags | CERT_STORE_MAXIMUM_ALLOWED_FLAG, m_CryptName); + } + return m_hStore; + } + + public: + CStore(_In_ LPCWSTR cryptName, DWORD dwFlags) : m_CryptName(cryptName), m_dwFlags(dwFlags) + { + if (auto localized = CryptFindLocalizedName(cryptName)) + { + m_StoreName = localized; + } + else + { + m_StoreName = cryptName; + } + } + ~CStore() + { + if (m_hStore) + { + CertCloseStore(m_hStore, 0); + } + } + + LPCWSTR + GetStoreName() const + { + return m_StoreName; + } + + void + Expand() + { + if (m_Expanded) + return; + m_Expanded = true; + // EnumCertificateRevocationLists() + // EnumCertificateTrustLists() + EnumCertificates(); + } + + void + EnumCertificates() + { + auto handle = StoreHandle(); + if (!handle) + return; + PCCERT_CONTEXT pContext = NULL; + while ((pContext = CertEnumCertificatesInStore(handle, pContext))) + { + CCert *newCert = new CCert(pContext); + m_Certificates.AddTail(newCert); + } + } + + template + void + ForEach(Fn callback) + { + Expand(); + + for (POSITION it = m_Certificates.GetHeadPosition(); it; m_Certificates.GetNext(it)) + { + auto current = m_Certificates.GetAt(it); + callback(current); + } + } +}; diff --git a/base/applications/mscutils/certmgr/CStoreList.cpp b/base/applications/mscutils/certmgr/CStoreList.cpp new file mode 100644 index 00000000000..4ff9e7d8b97 --- /dev/null +++ b/base/applications/mscutils/certmgr/CStoreList.cpp @@ -0,0 +1,49 @@ +/* + * PROJECT: ReactOS Certificate Manager + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: CStoreList implementation + * COPYRIGHT: Copyright 2025 Mark Jansen + */ + +#include "certmgr.h" + +CStoreList::CStoreList(StoreType type) : m_Type(type) +{ +} + +DWORD +CStoreList::StoreTypeFlags() const +{ + switch (m_Type) + { + case StoreType::User: + return CERT_SYSTEM_STORE_CURRENT_USER; + case StoreType::Service: + return CERT_SYSTEM_STORE_SERVICES; + case StoreType::Computer: + return CERT_SYSTEM_STORE_LOCAL_MACHINE; + default: + return 0; + } +} + +BOOL CALLBACK +CStoreList::s_StoreCallback( + const void *pvSystemStore, + DWORD dwFlags, + PCERT_SYSTEM_STORE_INFO pStoreInfo, + void *pvReserved, + void *pvArg) +{ + CStoreList *storeList = static_cast(pvArg); + const wchar_t *storeName = static_cast(pvSystemStore); + CStore *newStore = new CStore(storeName, storeList->StoreTypeFlags()); + storeList->m_Stores.AddTail(newStore); + return TRUE; // Continue enumeration +} + +void +CStoreList::LoadStores() +{ + CertEnumSystemStore(StoreTypeFlags(), NULL, this, s_StoreCallback); +} diff --git a/base/applications/mscutils/certmgr/CStoreList.hpp b/base/applications/mscutils/certmgr/CStoreList.hpp new file mode 100644 index 00000000000..da371f47a4c --- /dev/null +++ b/base/applications/mscutils/certmgr/CStoreList.hpp @@ -0,0 +1,51 @@ +/* + * PROJECT: ReactOS Certificate Manager + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: CStoreList definition + * COPYRIGHT: Copyright 2025 Mark Jansen + */ + +enum class StoreType +{ + User, + Service, + Computer, +}; + +class CStoreList +{ + private: + CAtlList m_Stores; + StoreType m_Type; + + static BOOL CALLBACK + s_StoreCallback( + const void *pvSystemStore, + DWORD dwFlags, + PCERT_SYSTEM_STORE_INFO pStoreInfo, + void *pvReserved, + void *pvArg); + + public: + explicit CStoreList(StoreType type); + + void + LoadStores(); + DWORD + StoreTypeFlags() const; + + template + void + ForEach(Fn callback) + { + if (m_Stores.IsEmpty()) + LoadStores(); + + for (POSITION it = m_Stores.GetHeadPosition(); it; m_Stores.GetNext(it)) + { + CStore *current = m_Stores.GetAt(it); + + callback(current); + } + } +}; diff --git a/base/applications/mscutils/certmgr/certmgr.cpp b/base/applications/mscutils/certmgr/certmgr.cpp new file mode 100644 index 00000000000..a84c6d4481d --- /dev/null +++ b/base/applications/mscutils/certmgr/certmgr.cpp @@ -0,0 +1,166 @@ +/* + * PROJECT: ReactOS Certificate Manager + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: + * COPYRIGHT: Copyright 2025 Mark Jansen + */ + +#include "certmgr.h" + +struct CCertMgrProperties : public CDialogImpl +{ + enum + { + IDD = IDD_CERTMGR_MAIN + }; + CTreeView m_StoreTree; + CListView m_CertList; + CSplitter m_Splitter; + CSortableHeader m_SortableHeader; + + CStoreList m_UserStoreList; + CStoreList m_ComputerStoreList; + + CCertMgrProperties() : m_UserStoreList(StoreType::User), m_ComputerStoreList(StoreType::Computer) + { + + } + + LRESULT + OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) + { + HICON hIcon = (HICON)::LoadImageW(_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCEW(IDI_CERTMGR), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED); + SetIcon(hIcon, TRUE); + SetIcon(hIcon, FALSE); + + m_StoreTree.Attach(GetDlgItem(IDC_STORE_TREE)); + m_CertList.Attach(GetDlgItem(IDC_CERT_LIST)); + m_Splitter.Init(m_hWnd, m_StoreTree.m_hWnd, m_CertList.m_hWnd); + + ListView_SetExtendedListViewStyleEx(m_CertList, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT); + + auto certRoot = m_StoreTree.AddItem(NULL, (LPWSTR)L"Certificates", 0, 0, 0); + auto userRoot = m_StoreTree.AddItem(certRoot, (LPWSTR)L"User Store", 0, 0, 0); + m_UserStoreList.ForEach( + [&](const CStore *current) + {m_StoreTree.AddItem(userRoot, (LPWSTR)current->GetStoreName(), 0, 0, (LPARAM)current); }); + auto computerRoot = m_StoreTree.AddItem(certRoot, (LPWSTR)L"Computer Store", 0, 0, 0); + m_ComputerStoreList.ForEach( + [&](const CStore *current) + { m_StoreTree.AddItem(computerRoot, (LPWSTR)current->GetStoreName(), 0, 0, (LPARAM)current); }); + + m_StoreTree.Expand(certRoot, TVE_EXPAND); + + m_CertList.InsertColumn(0, (LPWSTR)L"Issued To", LVCFMT_LEFT, 200); + m_CertList.InsertColumn(1, (LPWSTR)L"Issued By", LVCFMT_LEFT, 200); + m_CertList.InsertColumn(2, (LPWSTR)L"Expiration Date", LVCFMT_LEFT, 100); + m_CertList.InsertColumn(3, (LPWSTR)L"Friendly Name", LVCFMT_LEFT, 200); + + return TRUE; + } + + LRESULT + OnEndDialog(WORD, WORD wID, HWND, BOOL &) + { + EndDialog(wID); + return 0L; + } + + LRESULT + OnStoreChanged(int idCtrl, LPNMHDR pnmh, BOOL &bHandled) + { + if (idCtrl == IDC_STORE_TREE) + { + LPNMTREEVIEW pntv = (LPNMTREEVIEW)pnmh; + CStore *store = (CStore *)pntv->itemNew.lParam; + if (store) + { + m_CertList.DeleteAllItems(); + store->Expand(); + store->ForEach( + [&](const CCert *current) + { + LV_ITEM item = {}; + item.mask = LVIF_TEXT | LVIF_PARAM; + item.lParam = (LPARAM)current; + item.pszText = (LPWSTR)(LPCWSTR)current->GetSubjectName(); + item.iItem = m_CertList.GetItemCount(); + item.iItem = m_CertList.InsertItem(&item); + m_CertList.SetItemText(item.iItem, 1, (LPCWSTR)current->GetIssuerName()); + FILETIME notAfter = current->GetNotAfter(); + SYSTEMTIME st; + FileTimeToSystemTime(¬After, &st); + WCHAR dateStr[100]; + GetDateFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, dateStr, _countof(dateStr)); + m_CertList.SetItemText(item.iItem, 2, dateStr); + m_CertList.SetItemText(item.iItem, 3, (LPCWSTR)current->GetFriendlyName()); + }); + m_SortableHeader.ReapplySorting(m_CertList); + } + } + return 0L; + } + + LRESULT + OnCertDoubleClicked(int idCtrl, LPNMHDR pnmh, BOOL &bHandled) + { + if (idCtrl == IDC_CERT_LIST) + { + auto lpnmitem = (LPNMITEMACTIVATE)pnmh; + if (lpnmitem->iItem < 0) + return 0L; + + const CCert *current = (const CCert *)m_CertList.GetItemData(lpnmitem->iItem); + + CRYPTUI_VIEWCERTIFICATE_STRUCTW CertViewInfo = {0}; + CertViewInfo.dwSize = sizeof(CertViewInfo); + CertViewInfo.pCertContext = current->GetCertContext(); + CertViewInfo.hwndParent = m_hWnd; + CryptUIDlgViewCertificateW(&CertViewInfo, NULL); + } + return 0L; + } + + LRESULT + OnHeaderClicked(int idCtrl, LPNMHDR pnmh, BOOL &bHandled) + { + auto pnmv = (LPNMLISTVIEW)pnmh; + m_SortableHeader.ColumnClick(m_CertList, pnmv); + return 0L; + } + + BEGIN_MSG_MAP(CCertMgrProperties) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + COMMAND_ID_HANDLER(IDCANCEL, OnEndDialog) + NOTIFY_HANDLER(IDC_STORE_TREE, TVN_SELCHANGED, OnStoreChanged) + NOTIFY_HANDLER(IDC_CERT_LIST, NM_DBLCLK, OnCertDoubleClicked) + NOTIFY_HANDLER(IDC_CERT_LIST, LVN_COLUMNCLICK, OnHeaderClicked) + + MESSAGE_HANDLER(WM_SIZE, m_Splitter.OnSize) + MESSAGE_HANDLER(WM_SETCURSOR, m_Splitter.OnSetCursor) + MESSAGE_HANDLER(WM_LBUTTONDOWN, m_Splitter.OnLButtonDown) + MESSAGE_HANDLER(WM_MOUSEMOVE, m_Splitter.OnMouseMove) + MESSAGE_HANDLER(WM_LBUTTONUP, m_Splitter.OnLButtonUp) + END_MSG_MAP() +}; + +class CCertMgrModule : public ATL::CAtlExeModuleT +{ + public: + HRESULT + Run(_In_ int nShowCmd) throw() + { + CStringW Title(MAKEINTRESOURCEW(IDS_PROPERTIES_MAIN_TITLE)); + CCertMgrProperties certMgr; + certMgr.DoModal(); + return S_OK; + } +}; + +CCertMgrModule _AtlModule; + +extern "C" int WINAPI +wWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPWSTR /*lpCmdLine*/, int nShowCmd) +{ + return _AtlModule.WinMain(nShowCmd); +} diff --git a/base/applications/mscutils/certmgr/certmgr.h b/base/applications/mscutils/certmgr/certmgr.h new file mode 100644 index 00000000000..2a553560437 --- /dev/null +++ b/base/applications/mscutils/certmgr/certmgr.h @@ -0,0 +1,62 @@ +/* + * PROJECT: ReactOS Certificate Manager + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: Main header file + * COPYRIGHT: Copyright 2025 Mark Jansen + */ + +#pragma once + +#ifndef STRICT +#define STRICT +#endif + +#define _ATL_APARTMENT_THREADED +#define _ATL_NO_AUTOMATIC_NAMESPACE +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define ATL_NO_ASSERT_ON_DESTROY_NONEXISTENT_WINDOW + +#define _FORCENAMELESSUNION + +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include + +using namespace ATL; + +#define NDEBUG +#include +#include +#include + +template class CLocalPtr + : public CHeapPtr +{ +public: + CLocalPtr() throw() + { + } + + explicit CLocalPtr(_In_ T* pData) throw() : + CHeapPtr(pData) + { + } +}; + +#include "resource.h" +#include "CCert.hpp" +#include "CStore.hpp" +#include "CStoreList.hpp" +#include "CSplitter.hpp" +#include "CSortableHeader.hpp" diff --git a/base/applications/mscutils/certmgr/certmgr.rc b/base/applications/mscutils/certmgr/certmgr.rc new file mode 100644 index 00000000000..619060732ae --- /dev/null +++ b/base/applications/mscutils/certmgr/certmgr.rc @@ -0,0 +1,40 @@ +/* + * PROJECT: ReactOS Certificate Manager + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: Resources + * COPYRIGHT: Copyright 2025 Mark Jansen + */ + +#include +#include +#include +#include "resource.h" + +#define REACTOS_STR_FILE_DESCRIPTION "ReactOS Certificate Manager" +#define REACTOS_STR_INTERNAL_NAME "certmgr" +#define REACTOS_STR_ORIGINAL_FILENAME "certmgr.exe" +#include + +#include + +IDI_CERTMGR ICON "resources/certmgr.ico" + +#pragma code_page(65001) + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +STRINGTABLE +BEGIN + IDS_PROPERTIES_MAIN_TITLE "Certificate manager" +END + +IDD_CERTMGR_MAIN DIALOGEX 0, 0, 522, 273 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_CLIENTEDGE | WS_EX_LEFTSCROLLBAR | WS_EX_APPWINDOW +CAPTION "Certificate manager" +FONT 8, "MS Shell Dlg", 400, 0, 0x0 +BEGIN + CONTROL "",IDC_STORE_TREE,"SysTreeView32",TVS_HASBUTTONS | LVS_SORTASCENDING | TVS_HASLINES | TVS_SHOWSELALWAYS | WS_BORDER | WS_HSCROLL | WS_TABSTOP,7,7,158,259 + CONTROL "",IDC_CERT_LIST,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,170,7,345,259 +END + diff --git a/base/applications/mscutils/certmgr/resource.h b/base/applications/mscutils/certmgr/resource.h new file mode 100644 index 00000000000..7d7ae4ca62e --- /dev/null +++ b/base/applications/mscutils/certmgr/resource.h @@ -0,0 +1,16 @@ +/* + * PROJECT: ReactOS Certificate Manager + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: Resource definitions + * COPYRIGHT: Copyright 2025 Mark Jansen + */ + +#define IDC_STATIC -1 + +#define IDI_CERTMGR 100 + +#define IDD_CERTMGR_MAIN 200 +#define IDC_STORE_TREE 201 +#define IDC_CERT_LIST 202 + +#define IDS_PROPERTIES_MAIN_TITLE 1000 diff --git a/base/applications/mscutils/certmgr/resources/certmgr.ico b/base/applications/mscutils/certmgr/resources/certmgr.ico new file mode 100644 index 00000000000..0582af55bb5 Binary files /dev/null and b/base/applications/mscutils/certmgr/resources/certmgr.ico differ