Converting Variables to Unicode

I'm a Javascript developer so it's easy on me! I am trying to write just a C ++ printable patch on a framework. I am compiling with Unicode and based on my research this is what scares me.

I think this is a relatively simple thing that I complicate. The application has std::string

one that contains the current printer name. The script first checks to see if it is disabled (if it uses GetDefaultPrinter

that output LPTSTR

). Finally, the script takes the value std::string

or LPTSTR

and converts it to LPCTSTR

for CreateDC

.

Here is my code:

std::string PrinterName = window->getPrinter();
LPDWORD lPrinterNameLength;
LPWSTR szPrinterName;
LPCTSTR PrinterHandle;

if (PrinterName == "unset") {
    GetDefaultPrinter( szPrinterName, &lPrinterNameLength );
    PrinterHandle = szPrinterName; //Note sure the best way to convert here
} else {
    PrinterHandle = PrinterName.c_str();
}
HDC hdc = CreateDC( L"WINSPOOL\0", PrinterHandle, NULL, NULL);

      

I am getting conversion errors when compiling. For example,

Cannot convert parameter 2 from LPDWORD * to LPDWORD (GetDefaultPrinter)

and

Cannot convert from 'const char *' to 'LPCTSTR' (on line PrinterHandle = PrinterName.c_str ())

I've done quite a bit of research but haven't found a specific solution.

Any help is greatly appreciated!

+3


source to share


2 answers


Even if you are compiled for "Unicode" (wide character strings), you can call versions of ANSI (narrow letter) API functions. Windows will do the conversions for you and bring up the widescreen version under the covers.

For example, for most Windows APIs like CreateDC

there is actually no function with this name. Instead, there is a macro with a name CreateDC

that expands to CreateDCA

or CreateDCW

, which are the actual function names. When you are compiled for "Unicode" macros are expanded to versions -W

(which are native to all modern OS versions. There is nothing stopping you from explicitly naming any version, whether compiled for Unicode. In most cases, the version -A

just converts narrow strings to broad for you and then calls the appropriate version -W

(there are some caveats here related to window creation, but I don't think they refer to DCs.)



std::string PrinterName = window->getPrinter();
if (PrinterName == "unset") {
  char szPrinterName[MAX_PATH];  // simplified for illustration
  DWORD cchPrinterNameLength = ARRAYSIZE(szPrinterName);
  GetDefaultPrinterA(szPrinterName, &cchPrinterNameLength);
  PrinterName = szPrinterName;
}

HDC hdc = CreateDCA("WINSPOOL", PrinterName.c_str(), NULL, NULL);

      

+2


source


First of all, as mentioned in the comments, the correct way is to do DWORD

and pass the address:

DWORD lpPrinterNameLength;
...
GetDefaultPrinter(..., &lpPrinterNameLength);

      

Why is it so that it can use and change the number:

The input is the size in characters of the pszBuffer buffer. The output takes the size, in characters, of the printer name string, including the terminating null character.



It will just take DWORD

, but the function will change the number in the passed variable, so the function needs to change the address of the variable so that these changes are reflected on the caller.


Second, since it window->getPrinter()

returns a narrow string, and you are using UNICODE

that causes the functions to accept wide strings, you must convert from a narrow string to wide. There are several ways to do this (for example the very simple one mentioned in ildjarn's comment) and even this is slightly better with C ++ 11, although the above note applies even better with this, but I'll use MultiByteToWideChar

C ++ 03 as well:

std::wstring narrowToWide(const std::string &narrow) {
    std::vector<wchar_t> wide;

    int length = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, narrow.c_str(), -1, NULL, 0);
    if (!length) {
        //error
    }

    wide.resize(length);
    if (!MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, narrow.c_str(), -1, &wide[0], length)) {
        //error, should probably check that the number of characters written is consistent as well
    }

    return std::wstring(wide.begin(), wide.end());
}

...

std::wstring PrinterName = narrowToWide(window->getPrinter());
//rest is same, but should be L"unset"
CreateDC( L"WINSPOOL\0", PrinterHandle, NULL, NULL);

      

+2


source







All Articles