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?
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++.
Related
I have the below code.
main()
{
test::RouteMessage *Rtmesg = new test::RouteMessage;
test::RouteV4Prefix *prefix = new test::RouteV4Prefix;
test::RouteMessage testRtmesg;
prefix->set_family(test::RouteV4Prefix::RT_AFI_V4);
prefix->set_prefix_len(24);
prefix->set_prefix(1000);
Rtmesg->set_routetype(test::RouteMessage::RT_TYPE_BGP);
Rtmesg->set_allocated_v4prefix(prefix);
Rtmesg->set_flags(test::RouteMessage::RT_FLGS_NONE);
Rtmesg->set_routeevnt(test::RouteMessage::BGP_EVNT_V4_RT_ADD);
Rtmesg->set_nexthop(100);
Rtmesg->set_ifindex(200); Rtmesg->set_metric(99);
Rtmesg->set_pref(1);
int size = Rtmesg->ByteSize();
char const *rt_msg = (char *)malloc(size);
google::protobuf::io::ArrayOutputStream oarr(rt_msg, size);
google::protobuf::io::CodedOutputStream output (&oarr)
Rtmesg->SerializeToCodedStream(&output);
// Below code is just to see if everything is fine.
google::protobuf::io::ArrayInputtStream iarr(rt_msg, size);
google::protobuf::io::CodedInputStream Input (&iarr)
testRtmesg.ParseFromCodedStream(&Input);
Vpe::RouteV4Prefix test_v4Prefix = testRtmesg.v4prefix();
cout << std::endl;
std::cout << "Family " << test_v4Prefix.family() << std::endl;
std::cout << "Prefix " << test_v4Prefix.prefix()<< std::endl;
std::cout << "PrefixLen " << test_v4Prefix.prefix_len() << std::endl;
// All the above outputs are fine.
cout << std::endl;
cout << rt_msg; <<------------ This prints absolutely junk.
cout << std::endl;
amqp_bytes_t str2;
str2 = amqp_cstring_bytes(rt_msg); <<----- This just crashes.
printf("\n str2=%s %d", str2.bytes, str2.len);
}
Any operation on the above rt_msg just crashes. I want to use the above buffer to send to socket and another rabbitmq publish APIs.
Anybody out there who had similar issue...or worked out similar code ?
Protocol Buffers is a binary serialization format, not text. This means:
Yes, if you write the binary data to cout, it will look like junk (or crash).
The data is not NUL-terminated like C strings. Therefore, you cannot pass it into a function like amqp_cstring_bytes which expects a NUL-terminated char* -- it may cut the data short at the first 0 byte, or it may search for a 0 byte past the end of the buffer and crash. In general, any function that takes a char* but does not also take a length won't work.
I'm not familiar with amqp, but it looks like the function you are trying to call, amqp_cstring_bytes, just builds a amqp_bytes_t, which is defined as follows:
typedef struct amqp_bytes_t_ {
size_t len;
void *bytes;
} amqp_bytes_t;
So, all you have to do is something like:
amqp_bytes_t str2;
str2.bytes = rt_msg;
str2.len = size;
So, I converted the string to byte in C++, but when it goes to add it into registry, it's stripping off the exe part but keeping the ., I have no idea what's wrong with it.
If you're wondering what NXS is, the value of it is "noerrorsplease.exe", type is char.
char szFinal[] = "";
strcat(szFinal, (const char *)ExtractDirectory(filepath).c_str());
//Not needed: strcat(szFinal, "");
strcat(szFinal, nxs);
strcat(szFinal, ".exe");
CString str;
str = szFinal;
str += ".exe";
cout << str.GetString() << endl;
const BYTE* pb = reinterpret_cast<const BYTE*>(str.GetString());
cout << pb << endl;
DWORD pathLenInBytes = *szFinal * sizeof(*szFinal);
if(RegSetValueEx(newValue, TEXT("Printing Device"), 0, REG_SZ, (LPBYTE)pb, pathLenInBytes) != ERROR_SUCCESS)
{
RegCloseKey(newValue);
cout << "error" << endl;
}
cout << "Possibly worked." << endl;
RegCloseKey(newValue);
This code
char szFinal[] = "";
strcat(szFinal, (const char *)ExtractDirectory(filepath).c_str());
is already invalid. You defined array szFina having only one character that is the terminating zero. You may not use it for copying in it any string. In these situations you should use an object of type std::string.
I'm trying to access the friendly name attribute of the PRINTER_INFO_2 structure. But I simply don't know how to do it in C++.
So the following code returns the names in Hexadecimals...
int _tmain(int argc, _TCHAR* argv[])
{
DWORD dwNeeded = 0, dwPrintersR = 0, Level = 2;
PRINTER_INFO_2* prninfo=NULL;
int retValue = 0;
//Find required buffer size
EnumPrinters( PRINTER_ENUM_NAME, NULL, Level, NULL, 0, &dwNeeded, &dwPrintersR );
prninfo = (PRINTER_INFO_2*) GlobalAlloc(GPTR,dwNeeded);
EnumPrinters( PRINTER_ENUM_NAME, NULL, Level, (LPBYTE) prninfo, dwNeeded, &dwNeeded, &dwPrintersR );
cout << "# of printers:" << dwPrintersR << "\n";
for(int i = 0; i<dwPrintersR; i++){
cout << "Printer Name: " << prninfo[i].pPrinterName << "\n";
}
_getch();
return 0;
}
I would like to use PRINTER_ATTRIBUTE_FRIENDLY_NAME, but I don't know how to do it.
I'm new to C++ and compiled languages.
Thanks you very much.
The code is working except for where it actually tries to print the name to the console window.
It appears you're compiling for Unicode, so the printer name is a wide character string (whcar_t *). There's no overload for std::ostream::operator<<(wchar_t*), so you just end up getting the value of the pointer rather than the string.
You need to convert the wide character string to an "ANSI" string, compiler for ANSI instead of Unicode, or output the name using a function that handles wide character strings. For example, you could replace the cout line with:
MessageBox(NULL, prninfo[i].pPrinterName, TEXT("Printer Name"), MB_OK);
Or simply replace this
cout << "# of printers:" << dwPrintersR << "\n";
with this
wcout << L"Printer Name: " << prninfo[i].pPrinterName << L"\n";
Tested. It worked.
Hi i have the following code:
char msg[10000];
string mystr = "hello";
I want to put mystr into msg. Is there a way to do that? I tried all sorts of methods, but keep getting:
incompatible types in assignment of 'const char*' to char [10000]'
I tried:
msg = mystr.c_str();
and
msg = (char[10000])mystr;
to no avail.
You can try std::copy for this. Something like:
std::copy(mystr.begin(), mystr.end(), msg);
I would avoid C string functions like mempcy and strcpy in C++.
Take a look at string::copy - it takes a string an puts it into an array.
In your case it would be:
std::size_t length = mystr.copy(msg,10000);
msg[length]='\0';
char msg[10000];
string mystr = "hello";
strcpy(msg, mystr.c_str());
cout<<msg;
Use copy member function of std::string:
size_t len = mystr.copy(msg, (sizeof msg)-1);
msg[len] = 0;
String assignment in C is different. You have to copy the bytes into your destination string.
memcpy_s(msg, 1000, mystr.c_str(), mystr.length()) // safe windows version
memcpy(msg, mystr.c_str(), mystr.length()) // unix version
Use strcpy function :
http://www.cplusplus.com/reference/clibrary/cstring/strncpy/
strncpy(msg, mystr.c_str(), sizeof msg / sizeof msg[0]);
msg[sizeof msg / sizeof msg[0] - 1] = 0; // null-terminate in case of truncation
Compilers sometimes produce wonky error messages for array types.
Here's an accumulation of previous answers into a paste-and-compile program.
#include <string>
#include <iostream>
#if 1
int main(int argc, char **argv)
{
using std::cout;
using std::endl;
char msg[1000] = {0}; // initialize to 0 here since we're printing below
// the <type> <array-name>[<size>] = {0} just fills a POD struct or an array with 0s
std::string mystr = "hello";
// if, at some point, you have things changing "mystr"
// you'll need to make sure that it will fit in msg[]
cout << "Before strcpy: \"" << msg << "\"" << endl;
// I'll just finish the statement in mystr...
mystr += " world!";
if(mystr.length() < sizeof(msg)){
strcpy(
msg, // <- put in here until we find a '\0'
mystr.c_str() // <- take from here (which could be a temporary buffer)
);
}
//MSC will complain about strcpy being unsafe
//
// you can use the below instead (if you really feel the need to), which is
// the MS-specific equivalent to the above.
/*
strcpy_s(
msg, // <- put in here until we find a '\0' or the size limit is reached
sizeof(msg), // <- don't put any more than this many chars in msg
mystr.c_str() // <- take from here
);
*/
cout << "After strcpy: \"" << msg << "\"" << endl;
return 0;
}
#else
// Similarly, using wchar_t (a usually non-byte-sized character type)
//
// note where the divisions occurr
int main(int argc, char **argv)
{
using std::wcout;
using std::endl;
wchar_t msg[1000] = {0};
std::wstring mystr = L"hello";
wcout << "Before strcpy: \"" << msg << "\"" << endl;
mystr += L" world";
if(mystr.length() < (sizeof(msg)/sizeof(wchar_t))){
// mystr wil fit!
wcscpy(
msg, // <- put in here until we find a '\0'
mystr.c_str() // <- take from here (which could be a temporary buffer)
);
}
// Similar to the char case in the first preprocessor block
/*
wcscpy_s(
msg, // <- put in here until we find a '\0' or the size limit is reached
sizeof(msg)/sizeof(wchar_t), // <- don't put any more than this many wchar_ts in msg
mystr.c_str() // <- take from here
);
*/
wcout << "After strcpy: \"" << msg << "\"" << endl;
return 0;
}
#endif
I shall leave it to you to read the documentation on all related functions.
in a function, that gets unsigned char && unsigned char length,
void pcap_callback(u_char *args, const struct pcap_pkthdr* pkthdr, const u_char* packet)
{
std::vector<unsigned char> vec(packet, packet+pkthdr->len); // optimized from foo.
std::stringstream scp;
for (int i=0;i<pkthdr->len;i++) {
scp<<vec[i];
}
std::string mystr = std::string(scp.rdbuf()->str());
std::cout << "WAS: " << packet << std::endl;
std::cout << "GOOD: " << scp.str() << std::endl;
std::cout << "BAD: " << scp.str().c_str() << std::endl;
std::cout << "TEST: " << mystr.size() << std::endl;
assert(mystr.size() == pkthdr->len);
}
Results:
WAS: prints nothing (guess there is a pointer to const.. case)
GOOD: prints data
BAD: prints nothing
TEST, assert: prints that mystr.size() is equal to passed unsigned char size.
I tried:
string.assign(scp.rdbuf());
memcpy(char, scp.str(), 10);
different methods of creating/allocating temporary chars, strings
No help.. it is wanted to get a std::cout'able std::string that contains data, (which was picked from foo, which was unsigned char, which was packet data).
Guessing either the original foo may not be null-terminated, or the problem is something like this - simple, but can't get in.. what are the things to look for here?
(this code is another attempt to use libpcap, just to print packets in C++ way, without using known C++ magic wrappers like libpcapp).
For a quick test, throw in a check for scp.str().size() == strlen(scp.str().c_str()) to see if there are embedded '\0' characters in the string, which is what I suspect is happening.
I think you're going about this the wrong way. It looks like you're dealing with binary data here, in which case you can't expect to meaningfully output it to the screen as text. What you really need is a hex dump.
const unsigned char* ucopy = packet;
std::ios_base::fmtflags old_flags = std::cout.flags();
std::cout.setf(std::ios::hex, std::ios::basefield);
for (const unsigned char* p = ucopy, *e = p + pkthdr->len; p != e; ++p) {
std::cout << std::setw(2) << std::setfill('0') << static_cast<unsigned>(*p) << " ";
}
std::cout.flags(old_flags);
This will output the data byte-by-byte, and let you examine the individual hex values of the binary data. A null byte will simply be output as 00.
Check std::cout.good() after the failed output attempt. My guess is that there's some failure on output (i.e. trying to write a nonprintable character to the console), which is setting failbit on cout.
Also check to ensure the string does not start with a NULL, which would cause empty output to be the expected behavior :)
(Side note, please use reinterpret_cast for unsigned char *ucopy = (unsigned char*)packet; if you're in C++ ;) )