Click here to Skip to main content
15,888,521 members
Articles / Desktop Programming / MFC
Article

Registry Manipulation Using NT Native APIs

Rate me:
Please Sign up or sign in to vote.
4.85/5 (51 votes)
5 Sep 2006CPOL9 min read 276.2K   5.3K   97   71
An article on manipulating the registry using NT Native APIs.

This is the Native Registry Editor (NtRegEdit) article I wrote that uses the CNtRegistry class.

Important notice: Any registry manipulation can cause harm to your system and make it so it doesn't start or run properly. Back-up your registry before using this class. I am not responsible for any damage it causes.

Introduction

There are many registry classes out there, but none (that I know of) that use NT Native API calls to manipulate the registry. Normally, we use the Microsoft APIs to do the work, but they are a bit uncomfortable to use (to say the least), especially when it comes to copying, searching, and deleting keys and values. I also liked the simple example for RegHide by SysInternals that hides registry keys (in a matter of speaking).

Now, I use Robert Pittenger's CRegistry class (found here at CodeProject) whenever I write something that accesses the registry, because of its simplicity. I also liked the idea of hiding registry keys/values from the Registry Editor (RegEdit) by Microsoft, so I decided to combine the two and write a class that does both but only uses the NT Native Registry APIs to do it. This led to the creation of the CNtRegistry class.

Hidden Registry Keys, you say?

SysInternals says it the best (see below - verbatim from their website):

A subtle but significant difference between the Win32 API and the Native API (see Inside the Native API for more information on this largely undocumented interface) is the way that names are described. In the Win32 API, strings are interpreted as NULL-terminated ANSI (8-bit) or wide character (16-bit) strings. In the Native API, names are counted as Unicode (16-bit) strings. While this distinction is usually not important, it leaves open an interesting situation: there is a class of names that can be referenced using the Native API, but that cannot be described using the Win32 API.

How is this possible? The answer is that a name which is a counted as a Unicode string can explicitly include NULL characters (0) as part of the name. For example, "Key\0". To include the NULL at the end, the length of the Unicode string is specified as 4. There is absolutely no way to specify this name using the Win32 API since if "Key\0" is passed as a name, the API will determine that the name is "Key" (3 characters in length) because the "\0" indicates the end of the name.

When a key (or any other object with a name such as a named Event, Semaphore, or Mutex) is created with such a name, any application using the Win32 API will be unable to open the name, even though they might seem to see it.

This is where you can get a copy of RegHide from SysInternals.

What can it do?

The CNtRegistry class has some useful features ... You can:

  • Copy Keys and Values (including hidden ones) with in the same RootKey or across RootKeys.
    • BOOL CopyKeys(CString csSource, CString csTarget, BOOL bRecursively);
    • BOOL CopyValues(CString csSource, CString csTarget, CString csValueName, CString csNewValueName);
  • Delete Keys and Values (including hidden ones and recursively).
    • BOOL DeleteKey (CString csKey);
    • BOOL DeleteKeysRecursive (CString csKey);
    • BOOL DeleteValue (CString csName);
  • Rename Keys and Values.
    • BOOL RenameKey(CString csFullKey, CString csNewKeyName);
    • BOOL RenameValue(CString csOldName, CString csNewName);
  • Search for Keys, Value names, and Values. This allows you to do searches for certain "String" occurrences. It can also Find hidden Keys. Both functions (Search/Find) can perform them recursively, but only with in the current RootKey.
    • BOOL Search (CString csString, CString csStartKey, CStringArray& csaResults, int nRegSearchType=3, BOOL bCaseSensitive = TRUE);
    • BOOL FindHiddenKeys (CString csKey, BOOL bRecursive, CStringArray& csaResults);
  • Read and Write Values. Possible values/types are:
    • Binary (REG_BINARY, REG_RESOURCE_LIST, REG_FULL_RESOURCE_DECRIPTOR, REG_RESOURCE_REQUIREMENTS_LIST, REG_NONE)
      • UCHAR* ReadBinary(CString csKey, CString csName, UINT& uiLength);
      • BOOL WriteBinary(CString csKey, CString csName, UCHAR* pValue, UINT uiLength);
    • DWORD (REG_DWORD)
      • DWORD ReadDword(CString csKey, CString csName, DWORD dwDefault);
      • BOOL WriteDword(CString csKey, CString csName, DWORD dwValue);
    • String (REG_SZ, REG_EXPAND_SZ, REG_MULTI_SZ)
      • CString ReadString(CString csKey, CString csName, CString csDefault);
      • BOOL ReadMultiString(CString csKey, CString csName, CStringArray& csaReturn);
      • BOOL WriteString(CString csKey, CString csName, CString csValue);
      • BOOL WriteExpandString(CString csKey, CString csName, CString csValue);
      • BOOL WriteMultiString(CString csKey, CString csName, CStringArray& csaValue);
    • int (REG_DWORD)
      • int ReadInt(CString csKey, CString csName, int nDefault);
      • BOOL WriteInt(CString csKey, CString csName, int nValue);
    • float (REG_BINARY)
      • double ReadFloat(CString csKey, CString csName, double fDefault);
      • BOOL WriteFloat(CString csKey, CString csName, double fValue);
    • BOOL (REG_DWORD)
      • BOOL ReadBool(CString csKey, CString csName, BOOL bDefault);
      • BOOL WriteBool(CString csKey, CString csName, BOOL bValue);
    • COleDateTime (REG_BINARY)
      • COleDateTime ReadDateTime(CString csKey, CString csName, COleDateTime dtDefault);
      • BOOL WriteDateTime(CString csKey, CString csName, COleDateTime dtValue);
    • COLORREF (REG_BINARY)
      • COLORREF ReadColor(CString csKey, CString csName, COLORREF rgbDefault);
      • BOOL WriteColor(CString csKey, CString csName, COLORREF rgbValue);
    • Objects (REG_BINARY)
      • BOOL ReadFont(CString csKey, CString csName, CFont* pFont);
      • BOOL WriteFont(CString csKey, CString csName, CFont* pFont);
      • BOOL ReadPoint(CString csKey, CString csName, CPoint* pPoint);
      • BOOL WritePoint(CString csKey, CString csName, CPoint* pPoint);
      • BOOL ReadSize(CString csKey, CString csName, CSize* pSize);
      • BOOL WriteSize(CString csKey, CString csName, CSize* pSize);
      • BOOL ReadRect(CString csKey, CString csName, CRect* pRect);
      • BOOL WriteRect(CString csKey, CString csName, CRect* pRect);
  • Display errors that come from the calls to Native APIs in nt.dll.
  • Provide a default Value in case the operation fails.
  • Enable privileges for the current user which gives them the ability (if it doesn't exist already) to backup/restore Hives/Keys.

Using the code

Using the CNtRegistry class is actually very simple. Once you have declared CNtRegistry, initialize the class by calling InitNtRegistry(), call SetRootKey, then SetKey to set "SOFTWARE\MyApp". You can also use SetKey(HKEY hRoot, CString strKey, BOOL bCanCreate, BOOL bCanSaveCurrentKey) which simply combines the two functions (SetRootKey and SetKey). Now call almost any function ... like CreateHiddenKey to create a hidden key (or try a number of other functions).

Here is an example that creates a hidden key, then puts some values in it (which are also hidden).

#define "NtRegistry.h"

void CMyApp::ReadRegistry()
{
    CNtRegistry ntReg;
    ntReg.InitNtRegistry(); 
    //
    if (ntReg.SetKey(HKEY_LOCAL_MACHINE, 
        _T("Software\\MyApp\\Settings"), FALSE, TRUE))
    {
        if (ntReg.CreateHiddenKey(_T("Software\\MyApp\\Settings\\Hidden")))
        {
            // Write some stuff
            ntReg.WriteInt(_T("Data1"), 777);
            ntReg.WriteFloat(_T("Pi"), 3.14159);
            ntReg.WriteString(_T("UserName"), _T("DMadden61"));

            // Read some stuff
            int nData = ntReg.ReadInt(_T("Data1"), 0);
            pi = ntReg.ReadFloat(_T("Pi"), 0.0);
            CString csUserName = ntReg.ReadString(_T("UserName"), _T("ERR"));
        }
    }
    else
    {
        TRACE("Failed to open/set key\n");
    }
}

Simple enough? Well, it is, but how it is all put together was another thing.

Differences between Nt...() calls and Reg...() calls

I am going to show you some of the NT Native Registry APIs that CNtRegistry uses (or at least, is ready for use), talk about what makes these different, and how I modified a popular function called "EnablePrivileges" to use the NT Native APIs.

Some Native APIs
Related Win32 APIs
Required Privileges
NtCreateKey
RegCreateKey, RegCreateKeyEx
N/A
NtOpenKey
RegOpenKey, RegOpenKeyEx
N/A
NtDeleteKey
RegDeleteKey
N/A
NtFlushKey
RegFlushKey
N/A
NtSetInformationKey
None
N/A
NtQueryKey
RegQueryInfoKey
N/A
NtEnumerateKey
RegEnumerateKey, RegEnumerateKeyEx
N/A
NtNotifyChangeKey
RegNotifyChangeKeyValue
N/A
NtDeleteValueKey
RegDeleteValue
N/A
NtSetValueKey
RegSetValue, RegSetValueEx
N/A
NtQueryValueKey
RegQueryValue, RegQueryValueEx
N/A
NtEnumerateValueKey
RegEnumValue
N/A
NtQueryMultipleValueKey
RegQueryMultipleValues
N/A
NtEnumerateKey
RegEnumKey, RegEnumKeyEx
N/A
*NtSaveKey
RegSaveKey
SeBackupPrivilege
*NtRestoreKey
RegRestoreKey
SeRestorePrivilege
*NtLoadKey
RegLoadKey
SeRestorePrivilege
*NtLoadKey2
None
SeRestorePrivilege
*NtReplaceKey
RegReplaceKey
SeRestorePrivilege
*NtUnloadKey
RegUnloadKey
SeRestorePrivilege
NtClose
CloseHandle
N/A
NtCreateFile
CreateFile
N/A
NtOpenThread
OpenThread
N/A
NtOpenProcessToken
None
SeCreateTokenPrivilege
NtAdjustPrivilegesToken
AdjustTokenPrivileges
N/A
NtQueryInformationToken
GetTokenInformation
N/A

Sample NtRegistryAPI Image

The parameters used for NT Native Registry APIs are not the same ones you are familiar with. Did you know that there is actually only two (2) Root (main) Keys in the registry? The rest are simply symbolic links. The two Root Keys are "\Registry\Machine (HKEY_LOCAL_MACHINE)" and "\Registry\User (HKEY_USERS)". Look below to see the HKEY and the TEXT equivalent. Where you would normally write a path for a subkey (RegCreateKey) like this "SOFTWARE\MyApp" and also include the HKEY (HKEY_LOCAL_MACHINE), these Native APIs (NtCreateKey) need the entire "full" path to the subkey, like this: "\Registry\Machine\SOFTWARE\MyApp". The CNtRegistry class lets you make the call the way you are used to, but puts it all together for you (internally), simply by calling the two functions (see below) or one that does it both.

  • SetRootKey(HKEY_LOCAL_MACHINE);
  • SetKey(_T("SOFTWARE\\MyApp"),TRUE,TRUE);
  • or just the one below which combines the two
  • SetKey(HKEY_LOCAL_MACHINE,_T("SOFTWARE\\MyApp"),TRUE,TRUE);
HKEY_USERS           \Registry\User
HKEY_CURRENT_USER    \Registry\User\<Users_SID>
HKEY_LOCAL_MACHINE   \Registry\Machine
HKEY_CLASSES_ROOT    \Registry\Machine\SOFTWARE\Classes
HKEY_CURRENT_CONFIG  \Registry\Machine\SYSTEM\CurrentControlSet\
                                       Hardware Profiles\Current

Others are the UNICODE_STRING (U_S) and OBJECT_ATTRIBUTES (O_A) structures. The U_S structure holds the "full" Key path (Unicode string) and length. The O_A struct contains the properties. InitializeObjectAttributes(...) initializes the O_A structure that specifies the properties of an object handle to be opened. A pointer to this structure is then passed to the routine that actually opens the handle (e.g., NtOpenKey(...)).

// Used to define Unicode strings.
typedef struct _UNICODE_STRING 
{
    // The length in bytes of the string stored in Buffer.
    USHORT Length;
    // The maximum length in bytes of Buffer.
    USHORT MaximumLength;
    // Points to a buffer used to contain
    // a string of wide characters.
    PWSTR  Buffer;
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;

// Specifies the properties of an object handle.
typedef struct _OBJECT_ATTRIBUTES {
    ULONG Length;
    // Handle to the root object directory             
    HANDLE RootDirectory;
    // Name of the object to open a handle for.
    PUNICODE_STRING ObjectName;
    // Specifies flags (e.g. OBJ_CASE_INSENSITIVE)
    ULONG Attributes;
    // Points to type SECURITY_DESCRIPTOR
    PVOID SecurityDescriptor;
    // Points to type SECURITY_QUALITY_OF_SERVICE
    PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES;
typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;

#define InitializeObjectAttributes( p, n, a, r, s ) { \
    (p)->Length = sizeof( OBJECT_ATTRIBUTES );        \
    (p)->RootDirectory = r;                           \
    (p)->Attributes = a;                              \
    (p)->ObjectName = n;                              \
    (p)->SecurityDescriptor = s;                      \
    (p)->SecurityQualityOfService = NULL;             \
    }

Code example using the above structures to create a registry key (the native way):

...
//
// Initialize the Unicode String from an ANSI String
//
ANSI_STRING asName;
RtlZeroMemory(&asName,sizeof(asName));
RtlInitAnsiString(&asName,csName);

RtlZeroMemory(&usName,sizeof(usName));

RtlAnsiStringToUnicodeString(&usName,&asName,TRUE);


//
// Initialize the data/properties for the actual call
//
OBJECT_ATTRIBUTES ObjectAttributes;
InitializeObjectAttributes(&ObjectAttributes,
                           &usName, 
                           OBJ_CASE_INSENSITIVE, 
                           NULL,NULL);

//
// We are ready to create the key...
//
HANDLE hKey = NULL;
m_NtStatus = NtCreateKey(&hKey, 
                         KEY_ALL_ACCESS, 
                         &ObjectAttributes,
                         0, 
                         NULL, 
                         REG_OPTION_NON_VOLATILE, 
                         &m_dwDisposition);

if (!NT_SUCCESS(m_NtStatus)) {
    return FALSE;
}
else {
    NtClose(hKey);
}

...

Because I wanted to use some of the NT Registry Hive APIs (NtSaveKey, etc...), I had to re-write the function EnablePrivileges below to use NT Native APIs (except one function that I couldn't find a native call for, LookupPrivilegeValue).

// The following code can be used to enable or disable the
// privilege. You can use this code to enable or disable privilege 
//
// Use the following to enable the privilege:
//   EnablePrivilege(SE_BACKUP_NAME, TRUE);
//
// Use the following to disable the privilege:
//   EnablePrivilege(SE_BACKUP_NAME, FALSE);
//
NTSTATUS CNtRegistry::EnablePrivilege(CString csPrivilege, BOOL bEnable)
{
    TOKEN_PRIVILEGES NewState;
    HANDLE           hToken   = NULL;
    NTSTATUS         NtStatus = STATUS_SUCCESS;

    // Open the process token for this process.
    NtStatus = NtOpenProcessToken(GetCurrentProcess(),
                                  TOKEN_ADJUST_PRIVILEGES|
                                  TOKEN_QUERY|TOKEN_QUERY_SOURCE,
                                  &hToken);
    if (!NT_SUCCESS(NtStatus)) {
        return NtStatus;
    }

    // Get the local unique id for the privilege. This
    // is a Win32 API :-\ I couldn't find a Native one.
    LUID luid;
    if ( !LookupPrivilegeValue(NULL,
                               (LPCTSTR)csPrivilege,
                               &luid))
    {
        NtClose( hToken );
        return (NTSTATUS) ERROR_FUNCTION_FAILED;
    }

    // Assign values to the TOKEN_PRIVILEGE structure.
    NewState.PrivilegeCount = 1;
    NewState.Privileges[0].Luid = luid;
    NewState.Privileges[0].Attributes = (bEnable ? SE_PRIVILEGE_ENABLED : 0);

    // Adjust the token privilege.
    NtStatus = NtAdjustPrivilegesToken( hToken, 
                                        FALSE, 
                                        &NewState, 
                                        sizeof(NewState), 
                                        (PTOKEN_PRIVILEGES)NULL, 
                                        0);
    // Close the handle.
    NtClose(hToken);

    return NtStatus;
}

In closing...

Being an "Intermediate" programmer, the problems I ran into were simply learning curves in the conversion of different types. I commented out the Hive functions because I was having some problems and I didn't want folks out there to screw up their systems. I also do not use all the Native Registry APIs in the nt.dll.

That is all I have got, I don't expect this to be perfect, so please give me your ideas to make it better. One thing to remember in life itself (and all the challenges that come with it) ... if you make a "mistake" and learn from it, then it never was a mistake to begin with...it was a "lesson"!

Thanks to ...

  • CRegistry by Robert Pittenger. The inspiration behind this class!!

Things To-Do

  • Incorporate the "Hive" functions in the code.
  • Ability to "Rename" Keys/Values (shouldn't be too hard with copying/deleting capabilities already there).
  • Take out "un-needed" code (used when I was writing it).
  • Make sure everything is commented (working).
  • There is a lot more...

History

There is a lot more that can be done to this class, but time is short and I thought that someone out there might like to help :-)

  • August 10, 2006 (0.0.0.37)
    • Added recursive parameter to the CopyKey function.
    • Added "DeleteKeyRecursive()" function.
  • July 16, 2006 (0.0.0.36)
    • Added "ShowPermissionsDlg()" common dialog.
    • Added Key path in the statusbar.
  • July 2, 2006 (0.0.0.35)
    • Changed the parameters of "CopyKeys()/CopyValues()" functions.
      • This makes it easier to copy anything/anywhere.
    • Changed the parameters of the "FindHiddenKeys()" function.
      • This is so the output goes to a CStringArray (instead of a message box) which allowed me to display the output in a ListCtrl for display (thanks to a suggestion from "Tcpip2005" from CodeProject)!!
    • Added the "InitNtRegistry()" function which does all the initialization.
    • Added the CaseSensitive parameter to the "Search()" function.
    • Added "#pragma comment(linker...)" to stdafx.h to show XP themes.
    • Added some "Rtl...()" string functions.
      • RtlInitString()
      • RtlInitAnsiString()
      • RtlInitUnicodeString()
      • RtlAnsiStringToUnicodeString()
      • RtlUnicodeStringToAnsiString()
      • RtlFreeString()
      • RtlFreeAnsiString()
      • RtlFreeUnicodeString()
  • Jun 24, 2006 (0.0.0.34)
    • Added "RenameKey()" that uses the "NtRenameKey()".
    • Added "RenameValue()" that uses home-bread functions.
    • Reformated the header and source so that the order of the functions in the header match the order in the source.
  • Jun 22, 2006 (0.0.0.33)
    • Combined "SetRootKey() and SetKey" and added more explanations in the article.
    • Added "GetCurrentUsersTextualSid()" that returns the private variable "m_csSID".
  • Jun 11, 2006 - Release to public.
  • Jun 03, 2004 - Initial playing.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Product Manager
Germany Germany
I have been programming (as a hobby) for 20+ years (Unix C, Scripting, VB, C/C++, C#). I am getting too old to talk about it and been in the Security line of work (both Military/Civilian) for 25+ years.

Comments and Discussions

 
GeneralRe: * DONE * - Regular Expression for Search in the Class Pin
SebaM22-Sep-06 12:31
SebaM22-Sep-06 12:31 
GeneralRe: * DONE * - Regular Expression for Search in the Class Pin
Dan Madden22-Sep-06 15:22
Dan Madden22-Sep-06 15:22 
GeneralRe: * DONE * - Regular Expression for Search in the Class Pin
SebaM22-Sep-06 20:20
SebaM22-Sep-06 20:20 
GeneralRe: * DONE * - Regular Expression for Search in the Class Pin
Dan Madden23-Sep-06 13:52
Dan Madden23-Sep-06 13:52 
GeneralRe: * DONE * - Regular Expression for Search in the Class Pin
SebaM24-Sep-06 9:40
SebaM24-Sep-06 9:40 
GeneralRe: * DONE * - Regular Expression for Search in the Class Pin
SebaM1-Oct-06 4:52
SebaM1-Oct-06 4:52 
GeneralQuestion about changing registry values Pin
Christopher Stratmann12-Jul-06 10:02
Christopher Stratmann12-Jul-06 10:02 
AnswerRe: Question about changing registry values Pin
Dan Madden12-Jul-06 17:36
Dan Madden12-Jul-06 17:36 
Hi Chris175,

Before I ask the obvious question, below are the possible values and the "User Rights". Now, what is the error you are getting? Normal users may not have access to certain places in the registry, so depending on which Key you are trying to write to and depending on if that user has the Access/Rights to write to them ...

SE_ASSIGNPRIMARYTOKEN_NAME Required to assign the primary token of a process.
User Right: Replace a process level token.

SE_AUDIT_NAME Required to generate audit-log entries. Give this privilege to secure servers.
User Right: Generate security audits.

SE_BACKUP_NAME Required to perform backup operations.
User Right: Back up files and directories.

SE_CHANGE_NOTIFY_NAME Required to receive notifications of changes to files or directories. This privilege also causes the system to skip all traversal access checks. It is enabled by default for all users.
User Right: Bypass traverse checking.

SE_CREATE_PAGEFILE_NAME Required to create a paging file.
User Right: Create a pagefile.

SE_CREATE_PERMANENT_NAME Required to create a permanent object.
User Right: Create permanent shared objects.

SE_CREATE_TOKEN_NAME Required to create a primary token.
User Right: Create a token object.

SE_DEBUG_NAME Required to debug a process.
User Right: Debug programs.

SE_ENABLE_DELEGATION_NAME Required to mark user and computer accounts as trusted for delegation.
SE_INC_BASE_PRIORITY_NAME Required to increase the base priority of a process.
User Right: Increase scheduling priority.

SE_INCREASE_QUOTA_NAME Required to increase the quota assigned to a process.
User Right: Increase quotas.

SE_LOAD_DRIVER_NAME Required to load or unload a device driver.
User Right: Load and unload device drivers.

SE_LOCK_MEMORY_NAME Required to lock physical pages in memory.
User Right: Lock pages in memory.

SE_MACHINE_ACCOUNT_NAME Required to create a computer account.
User Right: Add workstations to domain.

SE_PROF_SINGLE_PROCESS_NAME Required to gather profiling information for a single process.
User Right: Profile single process.

SE_REMOTE_SHUTDOWN_NAME Required to shut down a system using a network request.
User Right: Force shutdown from a remote system.

SE_RESTORE_NAME Required to perform restore operations. This privilege enables you to set any valid user or group SID as the owner of an object.
User Right: Restore files and directories.

SE_SECURITY_NAME Required to perform a number of security-related functions, such as controlling and viewing audit messages. This privilege identifies its holder as a security operator.
User Right: Manage auditing and security log.

SE_SHUTDOWN_NAME Required to shut down a local system.
User Right: Shut down the system.

SE_SYNC_AGENT_NAME Required for a domain controller to use the LDAP directory synchronization services. This privilege enables the holder to read all objects and properties in the directory, regardless of the protection on the objects and properties. By default, it is assigned to the Administrator and LocalSystem accounts on domain controllers.
User Right: Synchronize directory service data.

SE_SYSTEM_ENVIRONMENT_NAME Required to modify the nonvolatile RAM of systems that use this type of memory to store configuration information.
User Right: Modify firmware environment values.

SE_SYSTEM_PROFILE_NAME Required to gather profiling information for the entire system.
User Right: Profile system performance.

SE_SYSTEMTIME_NAME Required to modify the system time.
User Right: Change the system time.

SE_TAKE_OWNERSHIP_NAME Required to take ownership of an object without being granted discretionary access. This privilege allows the owner value to be set only to those values that the holder may legitimately assign as the owner of an object.
User Right: Take ownership of files or other objects.

SE_TCB_NAME This privilege identifies its holder as part of the trusted computer base. Some trusted protected subsystems are granted this privilege. This privilege is required to call the LogonUser function.
User Right: Act as part of the operating system.

SE_UNDOCK_NAME Required to undock a laptop.
SE_UNSOLICITED_INPUT_NAME Required to read unsolicited input from a terminal device.
SE_MANAGE_VOLUME_NAME Required to enable volume management privileges.
User Right: Manage the files on a volume.




Regards,

Dan
GeneralRe: Question about changing registry values Pin
Christopher Stratmann13-Jul-06 0:05
Christopher Stratmann13-Jul-06 0:05 
AnswerRe: Question about changing registry values Pin
Dan Madden15-Jul-06 9:11
Dan Madden15-Jul-06 9:11 
GeneralVery good job Pin
42887-Jul-06 1:54
42887-Jul-06 1:54 
GeneralRe: Very good job Pin
Dan Madden8-Jul-06 13:12
Dan Madden8-Jul-06 13:12 
QuestionAuthor: New "NtRegEdit" Application Help (requested) Pin
Dan Madden29-Jun-06 8:39
Dan Madden29-Jun-06 8:39 
GeneralSearch Interface Pin
Tcpip200527-Jun-06 17:53
Tcpip200527-Jun-06 17:53 
GeneralRe: Search Interface Pin
Dan Madden27-Jun-06 17:59
Dan Madden27-Jun-06 17:59 
GeneralAuthor: Coming, NtRegistry Editor with a new look (Kinda) Pin
Dan Madden27-Jun-06 14:28
Dan Madden27-Jun-06 14:28 
GeneralRe: Author: Coming, NtRegistry Editor with a new look (Kinda) Pin
Defenestration29-Jun-06 7:24
Defenestration29-Jun-06 7:24 
AnswerRe: Author: Coming, NtRegistry Editor with a new look (Kinda) Pin
Dan Madden29-Jun-06 8:23
Dan Madden29-Jun-06 8:23 
GeneralRe: Author: Coming, NtRegistry Editor with a new look (Kinda) Pin
Defenestration29-Jun-06 9:26
Defenestration29-Jun-06 9:26 
GeneralRe: Author: Coming, NtRegistry Editor with a new look (Kinda) Pin
Dan Madden29-Jun-06 10:25
Dan Madden29-Jun-06 10:25 
GeneralRe: Author: Coming, NtRegistry Editor with a new look (Kinda) Pin
Defenestration30-Jun-06 12:13
Defenestration30-Jun-06 12:13 
GeneralRe: Author: Coming, NtRegistry Editor with a new look (Kinda) Pin
Dan Madden30-Jun-06 14:19
Dan Madden30-Jun-06 14:19 
GeneralRe: Author: Coming, NtRegistry Editor with a new look (Kinda) [modified] Pin
Defenestration18-Jul-06 13:18
Defenestration18-Jul-06 13:18 
GeneralRe: Author: Coming, NtRegistry Editor with a new look (Kinda) Pin
Dan Madden18-Jul-06 15:21
Dan Madden18-Jul-06 15:21 
GeneralRe: Author: Coming, NtRegistry Editor with a new look (Kinda) Pin
Defenestration19-Jul-06 4:08
Defenestration19-Jul-06 4:08 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.