I'm a C/Java/VBA guy who's new to C++... I need to take a vector of chars and populate the chars in a listbox (Visual Studio 2015) after pressing a button on the form.
When I try to do what seems natural (code below) the list box gets populated with the base-10 ASCII values instead of the characters. I've looked for ways to "force" listbox.Items.Add() to take it in as a character, but I've not had any luck. Can someone tell me what I'm doing wrong?
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
std::vector<char> CDROMDrives{ 'A', 'B', 'C'};
int i = 0;
for (auto &c : CDROMDrives) {
listBox1->Items->Add(c);
i++;
}
}
Here's what the list box looks like currently
Standard note about the language: C++/CLI is intended as a bridge to allow C# or other .Net code to call C++ code. It is not intended as a primary development language. If you want to learn C++, I would use C++ with MFC as your GUI toolkit. If you want to learn managed code, I'd learn C# with either WinForms or WPF. If you've got Java/VBA experience, I'd go with C#.
That said:
You didn't say what GUI toolkit you're using, or what the type of listBox1 is, but it's certainly a managed type of some sort. As such, you need to make a .Net System::String to insert into the list box. A C++ char will be interpreted as an 8-bit integer, and a C++ std::string will not be interpreted as you'd like.
To convert to a string, cast it to the proper managed type, and then call the ToString method.
listBox1->Items->Add(((System::Char)c).ToString());
65, 66, and 67 are the numeric values for 'A', 'B', and 'C' in ASCII. You need to make sure that your program is interpreting those values as chars and not ints. Try changing your loop condition to for (char &c : CDROMDrives) or casting to char before insertion to the list.
Related
I have a problem to translate the following C++ code to Delphi.
This is the code:
char dbcc_name[1]
And this is what I think what it should be:
dbcc_name : array [0..0] of Char;
However, I know this field should return a name, and not just one character.
So, it maybe something like this:
dbcc_name: array of Char;
Now, this looks nice, but there's no way of predicting how long the name will be, and it will probably return something with a load of rubish and somewhere a #0 terminator in it, but that is -I think- not the proper way.
Would it not be wise to use a pointer to this array?
Like:
dbcc_name: PChar;
Thank you in advance.
You were right the first time, only with the wrong data type. Use AnsiChar instead, which is char in C/C++:
dbcc_name: array[0..0] of AnsiChar;
In Delphi 2009+, Char is an alias for WideChar, which in C/C++ is wchar_t on Windows and char16_t on other platforms.
That being said, in C/C++, it makes sense for a 1-element array to exist in a struct when it represents variable-length data, and is the last field in the struct. In this case, the struct usually exists inside of a larger block of allocated memory. There is no array bounds checking in C/C++, the contents of an array can exceed the bounds of the array as long as it doesn't exceed the bounds of the memory that the array is allocated in. Referring to an array by name decays into a pointer to the first element. It is very common in C to exploit this to define a struct that has variable-length data embedded directly inside of it, that can be referred to by name, without having to allocate the data elsewhere in memory. This is especially useful in embedded systems with limited memory.
There are several structs in the Win32 API that use this approach for variable-length data. Raymond Chen discusses this in more detail on his blog:
Why do some structures end with an array of size 1?
You will most likely use either array[0..0] of char or just char, with some caveats. The code below assumes you are using a Windows API and I make assumptions based on one specific Windows Message record that matches your description.
If you are using char dbcc_name[1] as defined in DEV_BROADCAST_DEVICEINTERFACE in C its a char in the DEV_BROADCAST_DEVICEINTERFACE_A structure, but a wchar_t in the DEV_BROADCAST_DEVICEINTERFACE_W structure. NOTE: char in C maps to AnsiChar in Delphi and wchar_t maps to char in Delphi.
With the W strucutre I declare this in Delphi as dbcc_name: char; to read, I simply use PChar(#ARecordPtr^.dbcc_name). Your C++ sample seemingly uses the A struct, a straight translation to Delphi would mean a using the A structure with AnsiChar and using PAnsiChar to read, just replace in the code above.
However, a new Delphi project will by default use the Unicode version (or W imports) of a Windows API so that is why my sample below is written for Unicode.
In my implementation I simply have it defined as char. Some developers like the array[0..0] of char syntax because it leaves a clue of variable length array at that position. It is a more accurate translation, but I find it adds little value.
Example:
PDEV_BROADCAST_DEVICEINTERFACE = ^DEV_BROADCAST_DEVICEINTERFACE;
DEV_BROADCAST_DEVICEINTERFACE = record
dbcc_size: DWORD;
dbcc_devicetype: DWORD; // = DBT_DEVTYP_DEVICEINTERFACE
dbcc_reserved: DWORD;
dbcc_classguid: TGUID;
dbcc_name: Char; // <--- [HERE IT IS]. Use AnsiChar is using the A record instead of the W Record
end;
and to use it
procedure TFoo.WMDeviceChange(var AMessage: TMessage);
var
LUsbDeviceName: string;
LPDeviceBroadcastHeader: PDEV_BROADCAST_HDR;
LPBroadcastDeviceIntf: PDEV_BROADCAST_DEVICEINTERFACE;
begin
if (AMessage.wParam = DBT_DEVICEARRIVAL) then
begin
LPDeviceBroadcastHeader := PDEV_BROADCAST_HDR(AMessage.LParam);
if LPDeviceBroadcastHeader^.dbch_devicetype = DBT_DEVTYP_DEVICEINTERFACE then
begin
LPBroadcastDeviceIntf := PDEV_BROADCAST_DEVICEINTERFACE(LPDeviceBroadcastHeader);
LUsbDeviceName := PChar(#LPBroadcastDeviceIntf^.dbcc_name); // <--- [HERE IT IS USED] Use PAnsiChar if using the A Record instead of the W Record
...
end;
end;
end;
See more in my post on pointers and structures and for more explanation on the odd use of a single character array see the the "Records with Variable Length Arrays" section in my post on arrays and pointer math.
What chances do I got in finding all QStrings that do miss a tr()-translate call in a very old and very huge Application?
I was thinking something like... make a special .ts file for debugging use only and add a static prefix to all translations. Then put Qt in some sort of debug mode and list all its QString to qDebug or whatever—with the chance of filtering for everything that's missing the static prefix from the debug translation file. Is this possible?
Or: is there a better way to find untranslated QString occurrences? Thanks
For a big old project, this is probably a lot of work, but one way is below:
First see here, you want this:
QT_NO_CAST_FROM_ASCII disables automatic conversions from C string literals and pointers to Unicode.
Define that for your project, and then you can't write C string literals where QString is expected. Then you will probably get a bunch of build errors, which you fix by doing explicit conversion, using tr where you want.
After that, or perhaps before that to avoid going through same strings twice, do find-in-files (Ctrl+Shift+F in Qt Creator) for regexps like QString.*", and check them all for need of tr.
I need to store some data of table type like a QTableWidget but without a GUI. Something along the line of the following code:
QMap<QString, QString, int, QString, int>
Is there a way of achieve this in Qt? My Qt version is 5.3.
You seem to be unclear on a few concepts.
A map (also known in some languages as a dictionary) is an associative array. It associates a key to a value, that's about it, there are no "fields" involved whatsoever, just a key and a value.
There is no data type in Qt to model a database table. For such tasks you usually directly use SQL, Qt supports SQL with various different database drivers.
If you don't want to use a database but instead want to have "native" C++ types, you can simply create an object with all the desired fields:
struct Entry {
QString s1, s2, s3;
int i1, i2;
};
And then put that into whatever container you want.
QList<Entry> entryList;
QVector<Entry> entryVec;
QSet<Entry> entrySet;
You can wrap the container in a QAbstractListModel, implement the key functions and roles and have that model be used for a table widget or a QML view.
I am stuck with an error in QT compiler however it works fine with VS2010. the error states that
I have seen other posts related to the same error but non has resolved my problem in QT. I have tried _T,L or TEXT but still not working
bq. error: C2664: 'HANDLE
LoadImageW(HINSTANCE,LPCWSTR,UINT,int,int,UINT)' : cannot convert
argument 2 from 'const char *' to 'LPCWSTR' Types pointed to are
unrelated; conversion requires reinterpret_cast, C-style cast or
function-style cast
my code is as below
Bitmap::Bitmap(std::string const& file_name) {
bitmap_ = static_cast<HBITMAP>(::LoadImage(0, file_name.c_str(), IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION));
}
please share if you have any idea to resolve this
Qt does not include a compiler. On Windows you're probably either compiling with mingw or Visual C++. Either way, the issue is that you're calling a function that expects a wide character string but you're trying to hand it an 8-bit character string.
For compatibility reasons, Win32 uses a different set of API functions if you have _UNICODE defined. In your case, you do have _UNICODE defined. You can continue using the 8-bit std::string but simply change the method from LoadImage() to LoadImageA(). Or if you don't mind changing your Bitmap class, you could switch from std::string to std::wstring to take advantage of Windows' Unicode features.
But perhaps the larger question is why use Win32 to load bitmaps and std::string if you're using Qt? Qt's QImage class and QString class provide a full-featured, cross-platform strings and image loaders. Like any comprehensive framework, Qt works best if you only use external features on an as-needed basis.
I'm not sure if this method is the best, but I've used them on my projects and it works fine, see:
char *source = "Hello world";
WCHAR target[size];
MultiByteToWideChar(CP_ACP, 0, source, -1, target, size);
LPCWSTR final = target;
MessageBox(0, final, TEXT("title"), 0); //Sample usage
I've got existing C# code with signature of Foo(long[][] longs) which I need to call from Unmanaged C++ (not C++/CLI). I just can't seem to figure out the right combination of __gc[] and __gc* to make the compiler happy.
With C++/CLI, this is straight-forward:
std::vector<__int64> evens;
evens.push_back(2); evens.push_back(4); evens.push_back(6); evens.push_back(8);
std::vector<__int64> odds;
odds.push_back(1); odds.push_back(3); odds.push_back(5); odds.push_back(7);
std::vector<std::vector<__int64> > ints;
ints.push_back(evens); ints.push_back(odds);
array<array<__int64>^>^ mgdInts = gcnew array<array<__int64>^>(ints.size());
for (size_t i = 0; i<ints.size(); ++i)
{
const std::vector<__int64>& slice = ints[i];
mgdInts[i] = gcnew array<__int64>(slice.size());
for (size_t j=0; j<slice.size(); ++j)
mgdInts[i][j] = slice[j];
}
Edit: As I'm using Visual Studio 2008, the "simple" solution is to put the C++/CLI code in its own file and compile with /clr; of course, it would be easier if I didn't have to do this (e.g., other .h files with Managed C++). The C# code can't change as it's auto-generated from a web reference.
Change the signature from this
Foo(long[][] longs)
to this:
Foo(Array longs)
Then when you look at the resulting type library in OleView.exe, you should see:
HRESULT Foo([in] SAFEARRAY(int64) longs);
From C++, that's fairly straight forward to call. You can just Win32 to create a SAFEARRAY, or I suggest include and then use the CComSafeArray wrapper class in ATL.
Even though both C# and C++ have richer array definitions, the interoperability between the two is typically done though the Type Library marshaller, 99% of which is legacy and based on what's "VB Compatible". The only array types that the Type Library marshaller supports is SAFEARRAY, so that's what you get when you follow the normal way of doing all this.
However, COM supports a richer array system (conformant arrays), which C# understands, it's harder to do, and you can't simply regasm your C# DLL and use the resulting type library in your unmanaged C++ program. Some of the techniques require tweaking the C# code with ILDASM. Others require you to keep two definitions of the interface, one in C++ and one in C#, and make sure they're in sync (no way to convert one to the other), then in the IDL for C++ adorn the parameter with size_is, and in C# with MarshalAs. It's kind of a mess and really the only type people do that is if they have an already published legacy interface that they cannot change. If this is your C# code, and you can define the interface, I wouldn't go there. Still, the technique is available. Here's a refernece: http://support.microsoft.com/kb/305990
Expect about a week or so to get through this if you've never done anything like this before.
The solution I came up with is to use List<>.ToArray():
System::Collections::Generic::List<__int64 __gc[]>* mgdInts = new System::Collections::Generic::List<__int64 __gc[]>(ints.size());
for (size_t i = 0; i<ints.size(); ++i)
{
const std::vector<__int64>& slice = ints[i];
__int64 mgdSlice __gc[] = new __int64 __gc[slice.size()];
for (size_t j=0; j<slice.size(); ++j)
mgdSlice[j] = slice[j];
mgdInts->Add(mgdSlice);
}
ClassLibrary1::Class1::Foo(mgdInts->ToArray());