mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-08-26 19:33:31 +00:00
[MSCUTILS] Add very basic certmgr
This commit is contained in:
@@ -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(¬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<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 |
Reference in New Issue
Block a user