1

I have a method that has a mandatory parameter as char* and I want convert to PCSZ before RtlInitiAnsiString() and the result of uName after RtlAnsiStringToUnicodeString() to be the correct value.

How can I do this?

NTSTATUS myMethod(char *myName)
{        
    ANSI_STRING aName;
    UNICODE_STRING uName;
    OBJECT_ATTRIBUTES ObjAttr;

    RtlInitAnsiString(&aName, myName);
    status = RtlAnsiStringToUnicodeString(&uName, &aName, TRUE);
    if(!NT_SUCCESS(status))
    {
       DbgPrint("RtlAnsiStringToUnicodeString Error");
       return status;
    }

    InitializeObjectAttributes(&ObjAttr, &uName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); 
    // some code here
    //...
    RtlFreeUnicodeString(&uName);
    return status;    
}

EDITION 01:

To a better understand here is how MyMethod() is used in my kernel driver:

struct MyData
{
    ULONG Value[3];
    char *Str1;
    char *Str2;
};

NTSTATUS Function_IRP_DEVICE_CONTROL(PDEVICE_OBJECT pDeviceObject, PIRP Irp)
{
    PIO_STACK_LOCATION pIoStackLocation;
    struct MyData *pData = (struct MyData*) Irp->AssociatedIrp.SystemBuffer;
    pIoStackLocation = IoGetCurrentIrpStackLocation(Irp);
    switch (pIoStackLocation->Parameters.DeviceIoControl.IoControlCode)
    {
        case IOCTL_DATA :
            DbgPrint("IOCTL DATA");
            DbgPrint("%lu \n %lu \n %lu \n %s \n %s", pData->Value[0], pData->Value[1], pData->Value[2], pData->Str1, pData->Str2);
            ...
            break;
    }

...

//////////// Calling MyMethod() //////////////

myMethod(pData->Str1);
  • 3
    isn't `PCSZ` alias for `const char *`? – user7860670 Aug 15 '17 at 11:02
  • Possible duplicate of [this](https://stackoverflow.com/questions/20561277/c-converting-a-char-to-a-const-char)? – Griffin Aug 15 '17 at 11:05
  • 2
    Don't worry too much about those MS naming conventions. – Ron Aug 15 '17 at 11:10
  • If the usage of `myName` you show is the only usage inside `myMethod()` I recommend to change the function's defintion to be `myMethod(const char * myName)`. – alk Aug 15 '17 at 11:14
  • Actually it can be changed to `myMethod(char const * const myName)` because the value of pointer itself is not modified either. – user7860670 Aug 15 '17 at 11:17
  • @VTT which makes no sense because any argument is passed *by value*, so modifying the *pointer* would never have an effect on the calling code. –  Aug 15 '17 at 11:21
  • @FelixPalmen However it does have effect on the code being called. As [often suggested](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rconst-const) it is a good (and sometimes mandatory) practice to declare all values that won't be modified as `const`. – user7860670 Aug 15 '17 at 11:24

1 Answers1

5

There's nothing to convert. PCSZ is a Pointer to Constant String Zero-terminated. So, it's just const char *. char * is implicitly convertible to const char *.

I consider such typedefs horrible, but unfortunately, Microsoft APIs make heavy use of them.

  • 5
    It comes from the dark times - people were fascinated in the preprocessor directives & typedefs. – 0___________ Aug 15 '17 at 11:08
  • "I consider such typedefs horrible" Why? Can you offer a better alternative? – user7860670 Aug 15 '17 at 11:09
  • 4
    @VTT Because they hide the real type **and** they hide the fact you're dealing with pointers ... for no gain at all. Alternative: Just don't introduce such typedefs. –  Aug 15 '17 at 11:11
  • @FelixPalmen To be honest I don't get your point at all. The whole purpose of type alias is to hide the real type to prevent client code from explicitly binding to some implementation-defined type. But no, they don't hide the fact you are dealing with pointers and actually verbosely describe with what exact kind of pointer you are dealing with. And no, simply not using typedef is not a comparable alternative. Without a typedef a comparable alternative will involve writing a comment like "Pointer to Constant String Zero-terminated" every time a `const char *` is declared. – user7860670 Aug 15 '17 at 11:32
  • 4
    They come from the days of long and short pointers (and data segments), remember the architecture of Window 3 (ish). MS is still using them for backward compatibility. – Richard Critten Aug 15 '17 at 11:33
  • @VTT, if there's no `*` in the usage, the pointer **is** hidden. There's nothing wrong with a `typedef` for something used by the implementation you don't care about. But a `typedef` for `char` in order to express a string is completely redundant and just confuses people. –  Aug 15 '17 at 11:35
  • I edited my question to show how `myMethod()` is called in my project. –  Aug 15 '17 at 11:38
  • @JonasSilva I don't see how this changes anything? You have a `char *`, this can be passed for a `PCSZ`, which is just a `const char *`. If something doesn't work in your code, the problem is somewhere else. –  Aug 15 '17 at 11:39
  • @FelixPalmen, but content of `char*` parameter not will be changed after `RtlAnsiStringToUnicodeString()`? seems that my trouble is this that i left on question. –  Aug 15 '17 at 11:43
  • @JonasSilva why **should** it be changed? This function places the result in the `UNICODE_STRING` structure you're passing a pointer to. –  Aug 15 '17 at 11:45
  • @FelixPalmen, based in your suggestion of answer, my actual code is right, but no :-(. I understood that you not suggest changes. –  Aug 15 '17 at 11:48
  • @JonasSilva your code **is** right and it doesn't **attempt** to change your `char *myName` anywhere. if you expect `*myName` to be changed by that code, explain why you think so. –  Aug 15 '17 at 11:49
  • @FelixPalmen, then my error is with `RtlAnsiStringToUnicodeString()`? –  Aug 15 '17 at 11:58
  • @JonasSilva I don't know what you're trying to accomplish! `RtlAnsiStringToUnicodeString()` will probably correctly pouplate your `uName`. If this is not what you need, *describe* what you need. You might want to (re-?)read [how to ask](https://stackoverflow.com/help/how-to-ask). –  Aug 15 '17 at 12:00
  • I saw here in _ntdef.h_ that: `PCSZ` is a `typedef _Null_terminated_ CONST char* PCSZ`. –  Aug 15 '17 at 12:02
  • @JonasSilva You wrote "my error is with RtlAnsiStringToUnicodeString()" but you never written what kind of error do you have. If you are getting compilation error you should add compiler output into question. – user7860670 Aug 15 '17 at 12:03
  • @JonasSilva so, search for the other parts. `CONST` is probably just a `#define` for `const` and `_Null_terminated_` maybe for some attribute. All in all, it **is** `const char *`. –  Aug 15 '17 at 12:03
  • @FelixPalmen Sorry, but your "if there's no `*`" part makes no sense since you have an explicitl **P** *ointer* as part of the type alias name. I somewhat agree that quizzing everything into just 4 chars is not the best idea ever, however tend to make identifiers short is still rather common (and probably was justified back then). Actually declarations containing `*` (and especially `&`) are what I consider horrible practice. And I went as far is wrote a [dedicated library](https://github.com/guaranteed-to-be-unique/Straight-Declarations) completely eliminating need for such declarations. – user7860670 Aug 15 '17 at 12:06
  • @VTT then you're in contradiction of the entire C community, and I really don't care. We like our pointers to use exactly the syntax that makes them obvious as pointers. Period. –  Aug 15 '17 at 12:07
  • @FelixPalmen, well, the output: `DbgPrint("result is: %s", myName);` is empty string, already with one `&` before **myName** is a strange character. My `DbgPrint()` is on parte "**// some code here**" . –  Aug 15 '17 at 12:11
  • @FelixPalmen Just how having a type alias named like `PointerToSomething` makes pointers less obvious? Actually writing straight `char *` makes it less obvious because you won't even be able to easily distinguish pointers to null-terminated strings and pointers to not-null-terminated buffers and pointers to single char. – user7860670 Aug 15 '17 at 12:12
  • @JonasSilva But there is no `&` before `myName` in `DbgPrint("result is: %s", myName);` – user7860670 Aug 15 '17 at 12:13
  • @VTT, ok i will test again. –  Aug 15 '17 at 12:14
  • @FelixPalmen, if i do eg: `RtlInitAnsiString(&aName, L"\\SystemRoot\\System32\\foo.txt);` works fine `DbgPrint("result is: %s", uName);`. –  Aug 15 '17 at 13:03
  • @VTT, sorry, must be: `DbgPrint("result is: %s", uName);` and not `DbgPrint("result is: %s", myName);` as i said. –  Aug 15 '17 at 13:04
  • I already solved. Then solution to apper on `DgbPrint()` is: `DbgPrint("result is: %wZ", &uName);` @FelixPalmen, your answer also is right! thank you. –  Aug 15 '17 at 13:23
  • @FelixPalmen, apparently no :-). –  Aug 15 '17 at 13:26