?
Solved

Reading an INI file from the kernel driver (?)

Posted on 2006-11-26
8
Medium Priority
?
689 Views
Last Modified: 2011-09-20
Hi, I've read the question/answers located here:
http://www.experts-exchange.com/Programming/Programming_Languages/Cplusplus/Q_20598910.html
and in general I'm aware that in the kernel mode driver you are not allowed to use CreateFile.

But, I need to read the ini file (or registry if possible) at the system startup (when the driver loads for the first time). How is this possible, if it is :)

Thanx a lot.
P.S. I've placed the 500 points for this because I think it's worth that amount.
0
Comment
Question by:nepostojeci_email
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
8 Comments
 
LVL 48

Accepted Solution

by:
AlexFM earned 672 total points
ID: 18014190
To read file in kernel mode see the following functions:
ZwCreateFile
ZwClose
ZwReadFile
ZwWriteFile

I don't think that there are functions for handling ini files in kernel mode.

Usually driver-related data is kept in the Registry. The following functions can be used to access Registry:
IoOpenDeviceRegistryKey
IoOpenDeviceInterfaceRegistryKey
RtlDeleteRegistryValue
RtlQueryRegistryValues
RtlWriteRegistryValue
ZwClose
ZwCreateKey
... other functions

Do you have Walter Oney's book "Programming the Microsoft Windows Driver Model"? It contains working samples for these topics. This is possibly the only drivers book which contains really working sample code, I suggest you to buy it.
If you don't have this book, make search for these functions in www.osronline.com.
0
 
LVL 48

Expert Comment

by:AlexFM
ID: 18014305
0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 664 total points
ID: 18014664
Accessing registry keys without Win32 APIs is way different. Sysinternals had some code that demonstrated how to do this, however, that is no longer available online. The scoop is to

    NTSTATUS ntStatus;

    WCHAR awcBaseKey [] = L"\\Registry\\Machine\\SOFTWARE\\MyProduct";
    WCHAR awcDataKey [] = L"MySettingsSubKey";
    UNICODE_STRING KeyName;
    UNICODE_STRING DataKeyName;
    HANDLE hBaseKey = NULL;
    HANDLE hDataKey = NULL;

    OBJECT_ATTRIBUTES oa;
    ULONG ulDisposition;

    // Open the base key

    KeyName.Buffer = awcBaseKey;
    KeyName.Length = (USHORT) wcslen (awcBaseKey) * sizeof (WCHAR);

    InitializeObjectAttributes(&oa, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);

    ntStatus = ZwCreateKey(&hBaseKey, KEY_ALL_ACCESS, &oa, 0,  NULL, REG_OPTION_NON_VOLATILE, &ulDisposition);

    if(!NT_SUCCESS (ntStatus)) {

        // error
    }

    __try {

        // Open the storage key

        DataKeyName.Buffer = awcDataKey;
        DataKeyName.Length = (USHORT) (wcslen (awcDataKey)) * sizeof (WCHAR);

        InitializeObjectAttributes (&oa, &DataKeyName, OBJ_CASE_INSENSITIVE, hBaseKey, NULL);

        ntStatus = ZwCreateKey (&hDataKey, KEY_ALL_ACCESS, &oa, 0, NULL, REG_OPTION_NON_VOLATILE, &ulDisposition);

        if(!NT_SUCCESS (ntStatus)) {

            // error

            __leave;
        }

    } __finally {

        ZwClose (hBaseKey);
    }

    WCHAR awcDataValue[]    = L"MySettings";
    UNICODE_STRING ValueName;

    KEY_VALUE_PARTIAL_INFORMATION* pkvi = NULL;

    __try {

        // Read the stored value

        ValueName.Buffer = awcDataValue;
        ValueName.Length = (USHORT) (wcslen (awcDataValue)) * sizeof (WCHAR);
        ULONG ulNeeded;

        size_t szkvi = sizeof (KEY_VALUE_PARTIAL_INFORMATION);
        pkvi = (KEY_VALUE_PARTIAL_INFORMATION*) new BYTE [szkvi];

        ZeroMemory (pkvi, sizeof (KEY_VALUE_PARTIAL_INFORMATION));
        pkvi->Type = REG_BINARY;

        // Query necessary size first
        ntStatus = ZwQueryValueKey (hDataKey, &ValueName, KeyValuePartialInformation, pkvi, (ULONG) szkvi, &ulNeeded);

        //  Not present
        if (STATUS_OBJECT_NAME_NOT_FOUND == ntStatus) {

            // error

            __leave;
        }

        if (ntStatus != STATUS_BUFFER_TOO_SMALL && ntStatus != STATUS_BUFFER_OVERFLOW) {

            // error

            __leave;
        }

        delete [] pkvi;
        szkvi = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + ulNeeded;
        pkvi = (KEY_VALUE_PARTIAL_INFORMATION*) new BYTE [szkvi];
        ZeroMemory (pkvi, szkvi);
        pkvi->Type = REG_BINARY;

        // Finally, read value
        ntStatus = ZwQueryValueKey (hDataKey, &ValueName, KeyValuePartialInformation, pkvi, (ULONG) szkvi, &ulNeeded);

        if(!NT_SUCCESS (ntStatus)) {

            // error

            __leave;
        }


    } __finally {

        delete [] pkvi;

        ZwClose (hDataKey);
    }
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 30

Assisted Solution

by:Axter
Axter earned 664 total points
ID: 18014829
>>WCHAR awcBaseKey [] = L"\\Registry\\Machine\\SOFTWARE\\MyProduct";

Instead of using a string literal, you could use the path that is passed in to the DriverEntry function.
NTSTATUS
DriverEntry(IN PDRIVER_OBJECT DriverObject,
                  IN PUNICODE_STRING RegistryPath) // ***** use this value ******
{
   
    GetRegistrySettings(RegistryPath);
}

This value will change according to your driver, so it makes it a little more portable.
Example reg path:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\MY_DRIVER_NAME\DEBUG_LOGGING_ON


In my GetRegistrySettings function, I have a static variable that stores the RegistryPath value, so that the function can be called again from outside of DriverEntry without knowning the path value.
Example:

VOID GetRegistrySettings (IN PUNICODE_STRING RegistryPath_Input)
{
      OBJECT_ATTRIBUTES attributes;
      HANDLE driverRegKey;
      NTSTATUS status;
      ULONG resultLength;
      UNICODE_STRING valueName;
      UCHAR bufferPath[MAX_PATH * sizeof(WCHAR)] = {0};
      WCHAR *buffer = (WCHAR *)bufferPath;

      static UNICODE_STRING RegistryPath = {0, 0, 0}; // ****** Make sure this is STATIC *****

      if (RegistryPath_Input == NULL && RegistryPath.Buffer == NULL)
            return; //Should never reach this point unless NULL value passed first time called

      if (RegistryPath.Buffer == NULL)
      {
            RegistryPath.Buffer = ExAllocatePoolWithTag(NonPagedPool,  (RegistryPath_Input->MaximumLength + 2) * sizeof(WCHAR), '6_H');
            if (RegistryPath.Buffer == NULL)
                  return;
            RegistryPath.Length                        = RegistryPath_Input->Length;
            RegistryPath.MaximumLength            = RegistryPath_Input->MaximumLength;
            wcsncpy(RegistryPath.Buffer,RegistryPath_Input->Buffer, RegistryPath.Length      / 2 );
            RegistryPath.Buffer[RegistryPath_Input->Length / 2] = 0;
      }

      InitializeObjectAttributes( &attributes,
            &RegistryPath,
            OBJ_CASE_INSENSITIVE,
            NULL,
            NULL );

      status = ZwOpenKey( &driverRegKey,
            KEY_READ,
            &attributes );

      if (!NT_SUCCESS( status )) {
            return;
      }

      // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\MY_DRIVER_NAME\DEBUG_LOGGING_ON
      RtlInitUnicodeString( &valueName, L"DEBUG_LOGGING_ON" );
      status = ZwQueryValueKey( driverRegKey,
            &valueName,
            KeyValuePartialInformation,
            bufferPath,
            sizeof(bufferPath),
            &resultLength );


      if (NT_SUCCESS( status ))
      {
            if (((PKEY_VALUE_PARTIAL_INFORMATION) bufferPath)->Data[0] == 'Y')
            {
                  GXHSM_DIAG_MODE_ON = TRUE;
                  RelLoggingInfo("Turning on DiagMode\n");
            }
            else
            {
                  GXHSM_DIAG_MODE_ON = FALSE;
                  DbgPrintInfo("DiagMode is OFF\n");
            }
      }

You could easily change the above function so as to take a second argument that would specify the specific registry field to retrieve.
0
 
LVL 30

Expert Comment

by:Axter
ID: 18014860
FYI:
I have macros that use the global GXHSM_DIAG_MODE_ON for determining if logging occurs.
Example:
#if DBG //Dbg macros only log when debug version is compiled

#define DbgPrintInfo                        DbgPrint( "%p: (%5.5i) [%s] [Info]", KeGetCurrentThread(), __LINE__, __FUNCTION__);DbgPrint

//The Release log macros always log on debug version, and only log on release when switch is turned on
#define RelLoggingErrCond                  DbgPrint( "(%5.5i) [%s] [Error Condition ~~~] ", __LINE__, __FUNCTION__);if (GXHSM_DIAG_MODE_ON) DbgPrint
#define RelLoggingWarn                        DbgPrint( "(%5.5i) [%s] [Warning ~~] ", __LINE__, __FUNCTION__);if (GXHSM_DIAG_MODE_ON) DbgPrint
#define RelLoggingInfo                        DbgPrint( "(%5.5i) [%s] [Info ~] ", __LINE__, __FUNCTION__);if (GXHSM_DIAG_MODE_ON) DbgPrint

#else //Release macros log only when GXHSM_DIAG_MODE_ON is set to true

#define RelLoggingErrCond                  if (GXHSM_DIAG_MODE_ON) DbgPrint( "(%5.5i) [%s] [Error Condition ~~~] ", __LINE__, __FUNCTION__);if (GXHSM_DIAG_MODE_ON) DbgPrint
#define RelLoggingWarn                        if (GXHSM_DIAG_MODE_ON) DbgPrint( "(%5.5i) [%s] [Warning ~~] ", __LINE__, __FUNCTION__);if (GXHSM_DIAG_MODE_ON) DbgPrint
#define RelLoggingInfo                        if (GXHSM_DIAG_MODE_ON) DbgPrint( "(%5.5i) [%s] [Info ~] ", __LINE__, __FUNCTION__);if (GXHSM_DIAG_MODE_ON) DbgPrint

//This macro does nothing in release mode
#define DbgPrintInfo if (1);else DbgPrint

#endif // end DBG

If you use DebugView from Sysinternals, you can easily view above logging without having to boot the machine in special mode.
With my dirver, I'm able to turn the logging on and off without having to reboot the machine.
0
 
LVL 8

Author Comment

by:nepostojeci_email
ID: 18014995
Thanks a lot guys, these answers were very helpful for me.
Let me just try out these and I'll close this question.
Thanks for your help.
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article shows you how to optimize memory allocations in C++ using placement new. Applicable especially to usecases dealing with creation of large number of objects. A brief on problem: Lets take example problem for simplicity: - I have a G…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question