Cannot convert from 'WCHAR [256]' to 'WCHAR'

164 Views Asked by At

I have this function which uses the winscard.h function SCardGetReaderDeviceInstanceId.

    WCHAR SCardInstanceId(SCARDCONTEXT phContext, LPTSTR szReaderName) {
    WCHAR    szDeviceInstanceId[256];
    DWORD    cchDeviceInstanceId = 256;

    long lReturn = SCardGetReaderDeviceInstanceId(phContext, szReaderName, szDeviceInstanceId, &cchDeviceInstanceId);

    if (lReturn != SCARD_S_SUCCESS) {
        cout << "Failed SCardGetReaderDeviceInstanceId, errorcode: " << std::hex << std::setfill('0') << std::setw(8) << lReturn << endl;
        exit(1);
    }
    
    return szDeviceInstanceId;
}

But it gives me a wierd error message on the return line.

E0120   return value type does not match the function type

and

Error   C2440   'return': cannot convert from 'WCHAR [256]' to 'WCHAR'

What can be the issue here? and how do I solve it?

I can't change the function type to WCHAR [256], it that even a type?

1

There are 1 best solutions below

0
michuu On

The function return type is WCHAR. You are trying to return a C-style array of WCHARs. This isn't possible. You can instead return an std::wstring object, so your code would look like this:

#include <string>
std::wstring SCardInstanceId(SCARDCONTEXT phContext, LPTSTR szReaderName) {
    std::wstring szDeviceInstanceId;
    DWORD cchDeviceInstanceId = 255;
    szDeviceInstanceId.resize(cchDeviceInstanceId);
    // I think it is safer to resize to 255 chars as it is implementation defined if the internal array has the null-terminator.
    // If it does and you resize to 256, you will end up with a 257-element array...

    long lReturn = SCardGetReaderDeviceInstanceId(phContext, szReaderName, szDeviceInstanceId.data(), &cchDeviceInstanceId); // from c++17
    // long lReturn = SCardGetReaderDeviceInstanceId(phContext, szReaderName, &szDeviceInstanceId[0], &cchDeviceInstanceId); 
    // before c++17 'data' returns const reference, so SCardGetReaderDeviceInstanceId couldn't modify the buffer (compilation error)

    szDeviceInstanceId.resize(cchDeviceInstanceId-1); // shrink the string length to the length actually occupied by characters
    // -1 because cchDeviceInstanceId is length including null-terminator (according to docs), and resize expects length excluding null
    

    if (lReturn != SCARD_S_SUCCESS) {
        cout << "Failed SCardGetReaderDeviceInstanceId, errorcode: " << std::hex << std::setfill('0') << std::setw(8) << lReturn << endl;
        exit(1);
    }
    
    return szDeviceInstanceId;
}

If the 4th parameter of SCardGetReaderDeviceInstanceId didn't output any data, you could just pass szDeviceInstanceId.size()+1 (+1 for null). Also note, that the buffer will be allocated on the heap, unless SSO occurs (which is implementation defined, yet I don't think it would occur in any implementation in case of this long string).
As you can see the code is somewhat complex because of the differences in the management of the null-terminator. To make it simpler (but less beautiful in the C++ context) you can use std::wstring only to return the string:

std::wstring SCardInstanceId(SCARDCONTEXT phContext, LPTSTR szReaderName) {
    WCHAR    szDeviceInstanceId[255];
    DWORD    cchDeviceInstanceId = 255;

    long lReturn = SCardGetReaderDeviceInstanceId(phContext, szReaderName, szDeviceInstanceId, &cchDeviceInstanceId);

    if (lReturn != SCARD_S_SUCCESS) {
        cout << "Failed SCardGetReaderDeviceInstanceId, errorcode: " << std::hex << std::setfill('0') << std::setw(8) << lReturn << endl;
        exit(1);
    }
    
    return std::wstring(szDeviceInstanceId);
}

Please note, that doing it like this might be a bit less performant as you have to allocate both WCHAR[255] array and std::wstring array. It isn't going to matter most of the time, but it might be worth using the first method in a very performance-sensitive context.

You can return the array in the C manner as well, however it isn't recommended to do that in C++.