[MSCUTILS] Add very basic certmgr

This commit is contained in:
Mark Jansen
2026-02-15 20:13:01 +01:00
parent 23c4ed174f
commit 3529151141
13 changed files with 804 additions and 0 deletions
@@ -1,4 +1,5 @@
add_subdirectory(certmgr)
add_subdirectory(devmgmt)
add_subdirectory(eventvwr)
add_subdirectory(servman)
@@ -0,0 +1,85 @@
/*
* PROJECT: ReactOS Certificate Manager
* LICENSE: MIT (https://spdx.org/licenses/MIT)
* PURPOSE: CCert definition
* COPYRIGHT: Copyright 2025 Mark Jansen <[email protected]>
*/
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();
}
}
};
@@ -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)
@@ -0,0 +1,105 @@
/*
* PROJECT: ReactOS Certificate Manager
* LICENSE: MIT (https://spdx.org/licenses/MIT)
* PURPOSE: CSortableHeader definition
* COPYRIGHT: Copyright 2025 Mark Jansen <[email protected]>
*/
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);
}
};
@@ -0,0 +1,117 @@
/*
* PROJECT: ReactOS Certificate Manager
* LICENSE: MIT (https://spdx.org/licenses/MIT)
* PURPOSE: CSortableHeader definition
* COPYRIGHT: Copyright 2025 Mark Jansen <[email protected]>
*/
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;
}
};
@@ -0,0 +1,93 @@
/*
* PROJECT: ReactOS Certificate Manager
* LICENSE: MIT (https://spdx.org/licenses/MIT)
* PURPOSE: CStore definition
* COPYRIGHT: Copyright 2025 Mark Jansen <[email protected]>
*/
class CStore
{
private:
CAtlStringW m_CryptName;
DWORD m_dwFlags;
CAtlStringW m_StoreName;
HCERTSTORE m_hStore = NULL;
CAtlList<CCert *> 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 <typename Fn>
void
ForEach(Fn callback)
{
Expand();
for (POSITION it = m_Certificates.GetHeadPosition(); it; m_Certificates.GetNext(it))
{
auto current = m_Certificates.GetAt(it);
callback(current);
}
}
};
@@ -0,0 +1,49 @@
/*
* PROJECT: ReactOS Certificate Manager
* LICENSE: MIT (https://spdx.org/licenses/MIT)
* PURPOSE: CStoreList implementation
* COPYRIGHT: Copyright 2025 Mark Jansen <[email protected]>
*/
#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<CStoreList *>(pvArg);
const wchar_t *storeName = static_cast<const wchar_t *>(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);
}
@@ -0,0 +1,51 @@
/*
* PROJECT: ReactOS Certificate Manager
* LICENSE: MIT (https://spdx.org/licenses/MIT)
* PURPOSE: CStoreList definition
* COPYRIGHT: Copyright 2025 Mark Jansen <[email protected]>
*/
enum class StoreType
{
User,
Service,
Computer,
};
class CStoreList
{
private:
CAtlList<CStore *> 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 <typename Fn>
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);
}
}
};
@@ -0,0 +1,166 @@
/*
* PROJECT: ReactOS Certificate Manager
* LICENSE: MIT (https://spdx.org/licenses/MIT)
* PURPOSE:
* COPYRIGHT: Copyright 2025 Mark Jansen <[email protected]>
*/
#include "certmgr.h"
struct CCertMgrProperties : public CDialogImpl<CCertMgrProperties>
{
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(&notAfter, &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<CCertMgrModule>
{
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);
}
@@ -0,0 +1,62 @@
/*
* PROJECT: ReactOS Certificate Manager
* LICENSE: MIT (https://spdx.org/licenses/MIT)
* PURPOSE: Main header file
* COPYRIGHT: Copyright 2025 Mark Jansen <[email protected]>
*/
#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 <ndk/rtlfuncs.h>
#include <windef.h>
#include <winbase.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <atlbase.h>
#include <atlcom.h>
#include <atlstr.h>
#include <atlwin.h>
#include <strsafe.h>
#include <atlcoll.h>
#include <cryptuiapi.h>
using namespace ATL;
#define NDEBUG
#include <reactos/debug.h>
#include <reactos/shellutils.h>
#include <ui/rosctrls.h>
template <class T> class CLocalPtr
: public CHeapPtr<T, CLocalAllocator>
{
public:
CLocalPtr() throw()
{
}
explicit CLocalPtr(_In_ T* pData) throw() :
CHeapPtr<T, CLocalAllocator>(pData)
{
}
};
#include "resource.h"
#include "CCert.hpp"
#include "CStore.hpp"
#include "CStoreList.hpp"
#include "CSplitter.hpp"
#include "CSortableHeader.hpp"
@@ -0,0 +1,40 @@
/*
* PROJECT: ReactOS Certificate Manager
* LICENSE: MIT (https://spdx.org/licenses/MIT)
* PURPOSE: Resources
* COPYRIGHT: Copyright 2025 Mark Jansen <[email protected]>
*/
#include <windef.h>
#include <winuser.h>
#include <commctrl.h>
#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 <reactos/version.rc>
#include <reactos/manifest_exe.rc>
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
@@ -0,0 +1,16 @@
/*
* PROJECT: ReactOS Certificate Manager
* LICENSE: MIT (https://spdx.org/licenses/MIT)
* PURPOSE: Resource definitions
* COPYRIGHT: Copyright 2025 Mark Jansen <[email protected]>
*/
#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
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB