VS2017: cannot add strings/wstrings - c++

I have trouble understanding why the following code does not do what it should, VS2017 does not show an error and the solution is created, but the string is never what it should be:
void COrion::AddJournalMessage(CTextData *msg, const string &name)
{
WISPFUN_DEBUG("c194_f101");
CTextData *jmsg = new CTextData(msg);
jmsg->Text = name + jmsg->Text;
}
jmsg->Text is std::string.
now at runtime let's say 'name' is "Player:" and 'jmsg->Text' is "Hello World", I would expect the text after the code to be "Player:Hello World", but it is not. It's only "Player:" and I don't understand why.
I found a workaround in a way:
jmsg->Text = name.c_str() + jmsg->Text;
with this change it is "Player:Hello World".
Problem is, I still don't understand why the first one does not work.
Can someone explain where the problem is?
Is it specific to VS or something?
to make it clear: this is from an open source project I want to use, not code I wrote myself, but the problem has been the source of many bugs, since it is used in this way alot.
edit
CTextData class:
class CTextData : public CRenderTextObject
{
public:
bool Unicode = false;
TEXT_TYPE Type = TT_CLIENT;
uchar Font = 0;
uint Timer = 0;
uint MoveTimer = 0;
string Text = "";
wstring UnicodeText = L"";
uchar Alpha = 0xFF;
CRenderWorldObject *Owner = NULL;
CTextData();
CTextData(CTextData *obj);
virtual ~CTextData();
virtual bool IsText() { return true; }
bool CanBeDrawedInJournalGump();
CGLTextTexture m_Texture;
void GenerateTexture(
int maxWidth,
ushort flags = 0,
TEXT_ALIGN_TYPE align = TS_LEFT,
uchar cell = 30,
int font = -1);
};

Related

Convert std::string to STRSAFE_LPCWSTR in an utility method

I'm relatively new to C++ and I'm trying out Windows Notification using Win32 API.
This is the method I have:
BOOL Notification::ShowNotification(std::string title, std::string info) {
NOTIFYICONDATA nid = {
sizeof(nid)
};
nid.uFlags = NIF_INFO | NIF_GUID;
nid.guidItem = __uuidof(AppIcon);
nid.dwInfoFlags = NIIF_USER | NIIF_LARGE_ICON;
std::wstring wtitle = std::wstring(title.begin(), title.end());
const wchar_t * wchar_title = (STRSAFE_LPCWSTR) wtitle.c_str();
StringCchCopy(nid.szInfoTitle, sizeof(nid.szInfoTitle), wchar_title);
std::wstring wInfo = std::wstring(info.begin(), info.end());
const wchar_t * wchar_Info = (STRSAFE_LPCWSTR) wInfo.c_str();
StringCchCopy(nid.szInfo, sizeof(nid.szInfo), wchar_Info);
LoadIconMetric(g_hInst, MAKEINTRESOURCE(IDI_NOTIFICATIONICON), LIM_LARGE, & nid.hBalloonIcon);
return Shell_NotifyIcon(NIM_MODIFY, & nid);
}
As you can see, there is duplicate code for converting the string type to STRSAFE_LPCWSTR for the variables title and info. I was thinking of a small utility method that would replace the duplicate code.
Something like this:
void Notification::ConvertToLPCWSTR(std::string input, STRSAFE_LPCWSTR &result)
{
std::wstring wide_string = std::wstring(input.begin(), input.end());
result = (STRSAFE_LPCWSTR)wide_string.c_str();
}
And then use it from the ShowNotification method like this, where wchar_title is passed by reference:
STRSAFE_LPCWSTR wchar_title;
ConvertToLPCWSTR(title, wchar_title);
But it is failing because wide_string variable is stack allocated and it goes out of scope when ConvertToLPCWSTR execution is finished, because of which wchar_title is pointing at deallocated memory.
Anyone know of a good way to fix this ?
You need to move all three lines of the repeated code into a small utility function.
static void Notification::ConvertToLPCWSTR(const std::string& input, LPWSTR result, size_t result_max_size) {
std::wstring wInfo = std::wstring(input.begin(), input.end());
const wchar_t * wchar_Info = (STRSAFE_LPCWSTR) wInfo.c_str();
StringCchCopy(result, result_max_size, wchar_Info);
}
And call like
ConvertToLPCWSTR(info, nid.szInfo, sizeof(nid.szInfo));

How do I enumerate volumes on MacOSX in C++?

I'm brand new to Mac development/xcode. I'm trying to do what I feel should be extremely simple, but over a week of research has yielded no results.
I want to list the external usb drive available as a vector of strings.
I don't want their cryptic information like address serial or anything. I just want their paths IE: "D:/" or "Sandisk USB".
I accomplished this in Windows quite easily using the code found below, but finding out how to do this on Mac has me pulling my hair out.
The only thing I've found seems to be done for Objective C, - How to enumerate volumes on Mac OS X?
but my project uses c++.
Can someone please provide a simple example or point me in the right direction.
struct ESDriveDescription
{
std::string path;
std::string label;
ESDriveDescription() = default;
ESDriveDescription(const std::string &path, const std::string &label)
: path(path), label(label)
{}
};
int ESFileUtils::getExternalStorageDevicePaths(vector<ESDriveDescription> &paths){
// Letters in alphabet * 3 characters per drive path, + nul term + final nul
// NOTE: constexpr not supported in vs2013
static const DWORD DRIVE_BUFFER_SIZE = 26 * 4 + 1;
static const DWORD VOLUME_LABEL_MAX = 32;
const char* removableDriveNames[26] = { 0 };
char allDrives[DRIVE_BUFFER_SIZE] = { 0 };
int numRemovableDrives = 0;
DWORD n = GetLogicalDriveStringsA(DRIVE_BUFFER_SIZE, allDrives);
for (DWORD i = 0; i < n; i += 4) {
const char* driveName = &allDrives[i];
UINT type = GetDriveTypeA(driveName);
if (type == DRIVE_REMOVABLE)
removableDriveNames[numRemovableDrives++] = driveName;
}
char label[VOLUME_LABEL_MAX] = { 0 };
for (int i = 0; i < numRemovableDrives; i++) {
const char* driveName = removableDriveNames[i];
GetVolumeInformationA(driveName, label, VOLUME_LABEL_MAX, 0, 0, 0, 0, 0);
paths.emplace_back(driveName, label);
}
return numRemovableDrives;
}

Saving changes to LLVM BasicBlock Pass

I successfully added some Metadata to a Basic Block in LLVM. Then I used Mod->dump() to display it on the screen.
The data is added successfully to my byte code, i.e. metadata is displayed on the screen.
My problem is that these changes are not updated in my original file.
How can I solve this problem?
class BasicBlock1 : public BasicBlockPass {
public:
BasicBlock1()
: BasicBlockPass(ID)
{}
virtual bool runOnBasicBlock(BasicBlock &BB) {
Value *A[] = {MDString::get(getGlobalContext(), "mymetadata")};
MDNode *Node = MDNode::get(getGlobalContext(), A);
for (BasicBlock::iterator ii = BB.begin(), ii_e = BB.end();
ii != ii_e; ++ii) {
ii->setMetadata("XXX", Node);
}
return true;
}
static char ID;
};
char FunctionPrint::ID = 0;
char BasicBlock1::ID =0;
int main(int argc, char **argv) {
Module *Mod = ParseIRFile(argv[1], Err, getGlobalContext());
PM.add(new BasicBlock1());
PM.run(*Mod);
Mod->dump();
return 0;
}
You write:
The data is added successfully to my byte code, i.e. metadata is displayed on the screen.
My problem is that these changes are not updated in my original file.
In your code snippet, you do not write your modified module anywhere, you just print it to the output. You can write it using:
std::string ErrorInfo;
raw_fd_ostream OS(argv[1], ErrorInfo, sys::fs::F_Binary);
if (ErrorInfo.empty()) WriteBitcodeToFile(*Mod, OS);

Calling Windows API with libffi on MinGW

I'm trying to have FFI support for my new programming language, which is written in C++ with QT Creator using the MinGW toolchain.
To do this I used a custom-built version of libffi found here: http://ftp.gnome.org/pub/GNOME/binaries/win32/dependencies/libffi-dev_3.0.6-1_win32.zip
I also tried it with another build: http://pkgs.org/fedora-14/fedora-updates-i386/mingw32-libffi-3.0.9-1.fc14.noarch.rpm.html by downloading the SRPM file on Linux, extracting it, and copying the needed files to a Windows partition.
Anyway, I included the required header file, added the import library to the project and put the .dll beside the application's .exe, it compiles and runs, calling MessageBeep() successfully. I tried it next with MessageBoxA(), but it keeps crashing. The debugger doesn't seem to provide much useful information (edit: beside the fact that a call to MessageBoxA did happen) so I keep fiddling with stuff and re-running to no avail.
To isolate the problem from the details of my language, I tried to manually call MessageBoxA by filling myself all the parameters, resulting in the code below, still crashing.
So my question distills to: How can I get the code snippet below to run under QT Creator/MinGW and actually show a message box?
#include "libffi/include/ffi.h"
#include <QLibrary>
void testMessageBox()
{
int n = 4;
ffi_cif cif;
ffi_type **ffi_argTypes = new ffi_type*[n];
void **values = new void*[n];
values[0] = new ulong(0);
values[1] = (void *) "hello";
values[2] = (void *) "mommy";
values[3] = new int32_t(0);
ffi_argTypes[0] = &ffi_type_ulong;
ffi_argTypes[1] = &ffi_type_pointer;
ffi_argTypes[2] = &ffi_type_pointer;
ffi_argTypes[3] = &ffi_type_uint32;
ffi_type *c_retType = &ffi_type_sint32;
int32_t rc; // return value
if (ffi_prep_cif(&cif, FFI_STDCALL, n, c_retType, ffi_argTypes) == FFI_OK)
{
QLibrary lib("user32.dll");
lib.load();
void *msgbox = lib.resolve("MessageBoxA");
ffi_call(&cif, (void (*)()) msgbox, &rc, values);
}
}
you should pass the address to the values array instead of the values. the working code under mingw64 is
#include <stdio.h>
#include <ffi.h>
#include <Windows.h>
int main()
{
ffi_cif cif;
HINSTANCE dllHandle = LoadLibrary("user32.dll");
int n = 4;
ffi_type *ffi_argTypes[4];
void *values[4];
UINT64 a=0;
UINT32 b=0;
TCHAR* s1= "hello";
TCHAR* s2= "hello2";
values[0] = &a;
values[1] = &s1;
values[2] = &s2;
values[3] = &b;
ffi_argTypes[0] = &ffi_type_uint64;
ffi_argTypes[1] = &ffi_type_pointer;
ffi_argTypes[2] = &ffi_type_pointer;
ffi_argTypes[3] = &ffi_type_uint;
ffi_type *c_retType = &ffi_type_sint;
ffi_type rc; // return value
if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, &ffi_type_sint, ffi_argTypes) == FFI_OK) {
ffi_call(&cif, FFI_FN(GetProcAddress(dllHandle,"MessageBoxA")), &rc, values);
}
return 0;
}

Function has corrupt return value

I have a situation in Visual C++ 2008 that I have not seen before. I have a class with 4 STL objects (list and vector to be precise) and integers.
It has a method:
inline int id() { return m_id; }
The return value from this method is corrupt, and I have no idea why.
debugger screenshot http://img687.imageshack.us/img687/6728/returnvalue.png
I'd like to believe its a stack smash, but as far as I know, I have no buffer over-runs or allocation issues.
Some more observations
Here's something that puts me off. The debugger prints right values in the place mentioned // wrong ID.
m_header = new DnsHeader();
assert(_CrtCheckMemory());
if (m_header->init(bytes, size))
{
eprintf("0The header ID is %d\n", m_header->id()); // wrong ID!!!
inside m_header->init()
m_qdcount = ntohs(h->qdcount);
m_ancount = ntohs(h->ancount);
m_nscount = ntohs(h->nscount);
m_arcount = ntohs(h->arcount);
eprintf("The details are %d,%d,%d,%d\n", m_qdcount, m_ancount, m_nscount, m_arcount);
// copy the flags
// this doesn't work with a bitfield struct :(
// memcpy(&m_flags, bytes + 2, sizeof(m_flags));
//unpack_flags(bytes + 2); //TODO
m_init = true;
}
eprintf("Assigning an id of %d\n", m_id); // Correct ID.
return
m_header->id() is an inline function in the header file
inline int id() { return m_id; }
I don't really know how best to post the code snippets I have , but here's my best shot at it. Please do let me know if they are insufficient:
Class DnsHeader has an object m_header inside DnsPacket.
Main body:
DnsPacket *p ;
p = new DnsPacket(r);
assert (_CrtCheckMemory());
p->add_bytes(buf, r); // add bytes to a vector m_bytes inside DnsPacket
if (p->parse())
{
read_packet(sin, *p);
}
p->parse:
size_t size = m_bytes.size(); // m_bytes is a vector
unsigned char *bytes = new u_char[m_bytes.size()];
copy(m_bytes.begin(), m_bytes.end(), bytes);
m_header = new DnsHeader();
eprintf("m_header allocated at %x\n", m_header);
assert(_CrtCheckMemory());
if (m_header->init(bytes, size)) // just set the ID and a bunch of other ints here.
{
size_t pos = DnsHeader::SIZE; // const int
if (pos != size)
; // XXX perhaps generate a warning about extraneous data?
if (ok)
m_parsed = true;
}
else
{
m_parsed = false;
}
if (!ok) {
m_parsed = false;
}
return m_parsed;
}
read_packet:
DnsHeader& h = p.header();
eprintf("The header ID is %d\n", h.id()); // ID is wrong here
...
DnsHeader constructor:
m_id = -1;
m_qdcount = m_ancount = m_nscount = m_arcount = 0;
memset(&m_flags, 0, sizeof(m_flags)); // m_flags is a struct
m_flags.rd = 1;
p.header():
return *m_header;
m_header->init: (u_char* bytes, int size)
header_fmt *h = (header_fmt *)bytes;
m_id = ntohs(h->id);
eprintf("Assigning an id of %d/%d\n", ntohs(h->id), m_id); // ID is correct here
m_qdcount = ntohs(h->qdcount);
m_ancount = ntohs(h->ancount);
m_nscount = ntohs(h->nscount);
m_arcount = ntohs(h->arcount);
You seem to be using a pointer to an invalid class somehow. The return value shown is the value that VS usually uses to initialize memory with:
2^32 - 842150451 = 0xCDCDCDCD
You probably have not initialized the class that this function is a member of.
Without seeing more of the code in context.. it might be that the m_id is out of the scope you expect it to be in.
Reinstalled VC++. That fixed everything.
Thank you for your time and support everybody! :) Appreciate it!