I am trying to make an audio player that plays .wav files. I wrote a function ReadWaveFile(CString szFilename) for reading the wave data of the file into the WAVEHDR structure. In this function
BOOL CWavePlay::ReadWaveFile(CString szFilename)
{
hmmio = mmioOpen((LPTSTR)&szFilename,NULL,MMIO_READ);
ASSERT(hmmio); //error here: hmmio=0x00000000
if(hmmio==0)
return FALSE;
....
}
mmioOpen is always returning 0 whenever I pass a filepath to this function for opening the specified file. And what baffles me is when i pass the filepath explicitly in mmioOpen API the code works; i.e., a valid handle is returned.
can some body explain why is this happening??
What will happen when you say
MessageBox(NULL,(LPTSTR)&szFilename,"Foo",MB_ICONINFORMATION);
When passing strings to system functions you will need to pick up the pointer to the raw string. For example, if you want to use an std::string object to build your path you will need to say
mmioOpen(filename.c_str(),NULL,MMIO_READ);
Your cast assumes from CString* to LPTSTR assumes that a CString is binary compatible with a LPTSRT which is not the case. When you write LPCTSTR on szFilename you will invoke a cast operator defined on CStrings that converts it to apropriate format. Did you tried just
hmmio = mmioOpen((LPCTSTR)szFilename,NULL,MMIO_READ);
The last cast does not do anything real here so it should be enough.
Related
Being new to C++, I am still struggling with pointers-to-pointers and I am not sure if my method below is returning decoded image bytes properly.
This method gets a base64 encoded image string from API. The method has to follow this signature as it is part of legacy code that is not allowed to abbreviate from the way it was written originally. So the signature has to stay the same. Also, I have omitted here async calls and continuations, exceptions etc for code simplicity.
int __declspec(dllexport) GetInfoAndPicture(CString uid, char **image, long *imageSize)
{
CString request = "";
request.Format(url);
http_client httpClient(url);
http_request msg(methods::POST);
...
http_response httpResponse;
httpResponse = httpClient.request(msg).get(); //blocking
web::json::value jsonValue = httpResponse.extract_json().get();
if (jsonValue.has_string_field(L"img"))
{
web::json::value base64EncodedImageValue = jsonValue.at(L"img");
utility::string_t imageString = base64EncodedImageValue.as_string();
std::vector<unsigned char> imageBytes = utility::conversions::from_base64(imageString);
image = (char**)&imageBytes; //Is this the way to pass image bytes back?
*imageSize = imageBytes.size();
}
...
}
The caller calls this method like so:
char mUid[64];
char* mImage;
long mImageSize;
...
resultCode = GetInfoAndPicture(mUid, &mImage, &mImageSize);
//process image given its data and its size
I know what pointer to pointer is, my question is specific to this line
image = (char**)&imageBytes;
Is this the correct way to return the image decoded from base64 into the calling code via the char** image formal parameter given the above method signature and method call?
I do get error "Program .... File: minkernel\crts\ucrt\src\appcrt\convert\isctype.cpp ... "Expression c >= -1 && c <= 255"" which I believe is related to the fact that this line is not correctly passing data back.
Give the requirements there isn't any way to avoid allocating more memory and copying the bytes. You cannot use the vector directly because that is local to the GetInfoAndPicture function and will be destroyed when that function exits.
If I understand the API correctly then this is what you need to do
//*image = new char[imageBytes.size()]; //use this if caller calls delete[] to deallocate memory
*image = (char*)malloc(imageBytes.size()); //use this if caller calls free(image) to deallocate memory
std::copy(imageBytes.begin(), imageBytes.end(), *image);
*imageSize = imageBytes.size();
Maybe there is some way in your utility::conversions functions of decoding directly to a character array instead of to a vector, but only you would know about that.
The problem is with allocating (and freeing) memory for that image; who is responsible for that?
You can't (shouldn't) allocate memory in one module and free it in another.
Your two options are:
Allocate large enough buffer on the caller side, and have DLL use it utility::conversions::from_base64(). The issue here is: what is large enough? Some Win APIs provide an additional method to query the required size. Doesn't fit this scenario as the DLL would either have to get that image for the second time, or hold it (indefinitely) until you ask for it.
Allocate required buffer in the DLL and return a pointer to it. You need to ensure that it won't be freed until the caller request to free it (in a separate API).
I have the following method which gives out a jsonDoc as a reference
bool MyClass::jsonTest(rapidjson::Document & rjsonDoc)
{
rjsonDoc.SetObject();
rapidjson::Value val(rapidjson::kObjectType);
val.AddMember("a", 1, rjsonDoc.GetAllocator());
val.AddMember("b", 2, rjsonDoc.GetAllocator());
val.AddMember("c", 3, rjsonDoc.GetAllocator());
rjsonDoc.AddMember("Values", val, rjsonDoc.GetAllocator());
//outputs the json into a file
std::FILE* fp = fopen("outputjsonTest.json", "wb"); // non-Windows use "w"
char writeBuffer[65536];
rapidjson::FileWriteStream os(fp, writeBuffer, sizeof(writeBuffer));
rapidjson::Writer<rapidjson::FileWriteStream> writer(os);
rjsonDoc.Accept(writer);
fclose(fp);
return false;
}
The above method when called writes a perfect json into the file outputjsonTest.json
But upon calling the method in another class and writing it into the file,
rapidjson::Document d;
CData_BisconaCtrl dMan;
dMan.jsonTest(d);
//outputs the json into a file
std::FILE* fp = fopen("outputruntest.json", "wb"); // non-Windows use "w"
char writeBuffer[65536];
rapidjson::FileWriteStream os(fp, writeBuffer, sizeof(writeBuffer));
rapidjson::Writer<rapidjson::FileWriteStream> writer(os);
d.Accept(writer);
fclose(fp);
The file, outputruntest.json turns out to be blank.
It seems I cannot use the pass by reference style to return a jsonDocument from a method. Or am I making a mistake? Is it possible to return a jsonDocument in this way, at all?
I see nothing wrong with what you are doing. Moreover, I tried running your code and it seemed to work for me.
That said, you should note that if you try to use the Writer more than once (e.g., to print more than one document or to print the same document a second time), you'll need to Reset() it, first. It will stop producing output at the end of the first document, so if you try to print a second one it won't produce any output (because the result would not be a legal JSON "document").
[Edit:]
Nevertheless, rather than dumping the object to a file, you could try interrogating it to see what's in it. Check its type, size, capacity; see if it has the expected members, or iterate over its members/entries; etc. Failing all that, I would try proving that the basic C++ stuff is working. (I.e.: Is the right method actually being called? Are there any unexpected exceptions which are being handled? Is the method receiving the object that you're sending? Etc.)
Good luck!
I have a DLL that I need to handle in C++. I'm using WxWidgets (standard compilation, but I also tried Unicode on/off) and NetBeans. I also tried dealing with this without WxWidgets (windows.h) and had same problems.
Here is how I access the DLL functions using WxWidgets:
// -------------------- POINTERS TO FUNCTIONS
typedef bool(*TYPE_DLL_SetLicense)(char*, char*);
typedef bool(*TYPE_DLL_PingConnection)(char*);
typedef char*(*TYPE_DLL_ERR_DESCRIPTION)(void);
class DLL_Library
{
public:
// pointers to functions inside dll
TYPE_DLL_SetLicense DLL_SetLicense; //initialize - will wor fine as it returns only true/false (buffer only provide data)
TYPE_DLL_PingConnection DLL_PingConnection; //ping to serwer. Will return trahs, becouse it uses buffer to provide data ang get answear back
TYPE_DLL_ERR_DESCRIPTION DLL_ERR_DESCRIPTION; //error description. No buffer, no trouble. Returns correct string.
wxDynamicLibrary dynLib2;
int initialize(void)
{
//patch to dll
wxString path = wxStandardPaths::Get().GetExecutablePath().BeforeLast('\\') + _("\\DLL_dll\\DLLMOK.dll");
if(!wxFile::Exists(path)) return -1;
//load dll
if(!dynLib2.Load(path)) return -2;
//Assign functions in dll to variable
DLL_SetLicense=(TYPE_DLL_SetLicense) dynLib2.GetSymbol(wxT("DLL_SetLicense"));
DLL_PingConnection=(TYPE_DLL_PingConnection) dynLib2.GetSymbol(wxT("DLL_PingConnection"));
DLL_ERR_DESCRIPTION=(TYPE_DLL_ERR_DESCRIPTION) dynLib2.GetSymbol(wxT("DLL_ERROR_DESCRIPTION"));
return 0;
}
};
And here is the function I run. It should return and XML content, that I try to save to the file.
//DLL_PingConnection
//result ping to be save in file
wxFile file_ping_xml;
plik_ping_xml.Open(wxT("C:\\dll\\ping.xml"),wxFile::write);
char buffor_ping_xml[2000];
//I run the function here
bool is_ping = DLL_PingConnection(buffor_ping_xml);
if(is_ping)
{
tex_box->AppendText(wxT("DLL_PingConnection True\n"));
//we save result to file
bool is_write_ping_ok = file_ping_xml.Write(buffor_ping_xml,2000);
if (is_write_ping_ok){tex_box->AppendText(wxT("Save to file is ok ok\n"));}
else {tex_box->AppendText(wxT("Save to file failed :( \n"));}
}
else
{
tex_box->AppendText(wxT("DLL_PingConnection False\n"));
}
std::cout << "Error description: " << DLL_ERR_DESCRIPTION() << "\n"; //will work fine both in saving to file, and in streaming to screen.
The problem is that inside the file instead of good content I get rubbish like this:
NOTE that this only happens in functions that use buffers like:
char buffer[2000] //buffer will contain for example file xml
function do_sth_with_xml(buffer) //buffer containing xml will (should) be overwriten with xml results of the function - in our case DLL_PingCONNECTION should save in buffer xml with connection data
Documentation say that the DLL operates on Windows-1250. File ping.xml I have set to windows ANSI, but I don't think problem lies here.
EDIT: I have written problem without WxWidgets (I load DLL using windows.h) - same problems. Here is the code: Getting trash data in char* while using it as buffer in function . Please help :(
This
DLL_PingConnection=(TYPE_DLL_PingConnection)
shouldn't it be
DLL_PingConnection=(TYPE_DLL_PingConnection) dynLib2.GetSymbol(wxT("DLL_PingConnection"));
?
seems otherwise you will not get a valid pointer to the function in the DLL.
as a general rule you should check return values, especially from a DLL
you load dynamically since it happens that you sometimes get another version
of the DLL which may have a function with same name but other signature or
where is missing entirely.
You named a function
DLL_PingConnection=(TYPE_DLL_PingConnection) dynLib2.GetSymbol(....
and call it with
OSOZ.OSOZ_PingConnection(buffor_ping_xml);
you typedef a function
typedef bool(*TYPE_DLL_PingConnection)(char*);
you create a variable
char buffor_ping_xml[2000];
in your typedef it is char* and your buffor_ping_xml is char
how can that work ?
try
char *buffor_ping_xml = new char[2000];
/* or */
wchar_t *buffor_ping_xml = new wchar_t[2000];
/* or */
wxChar *buffor_ping_xml = new wxchar[2000];
bool is_ping = DLL_PingConnection(buffor_ping_xml);
wxString mystring = wxString::FromUTF8(buffor_ping_xml);
write mystring to file.
To Do:
look in your wxwidgets\libs folder for your libs
are there libwxmsw29ud_* with a 'u' in the name (after version number here 29)?
If not You can not use unicode
If yes next steps
for all different test char *, wchar_t *, wxChar * give the files different name.
for example file_ping_xml.Open(wxT("C:\dll\ping_w_t_FromUTF8.xml"), ...
for wchar_t * in combination with
wxString mystring = wxString::FromUTF8(buffor_ping_xml);
also in combination with
wxString mystring(buffor_ping_xml);
Then check out the look like, of the files in a browser .
To test you can go to your wxWidgets sample folder . Compile in the folder C:\wxWidgets\samples\docview\docview.cpp . Open with docview.exe a unicode file . How does it look.
Unicode download file
Unicode-related compilation settings
You should define wxUSE_UNICODE to 1 to compile your program in Unicode mode. This currently works for wxMSW, wxGTK, wxMac and wxX11. If you compile your program in ANSI mode you can still define wxUSE_WCHAR_T to get some limited support for wchar_t type.
Here is answear: Getting trash data in char* while using it as buffer in function.
Thanks everyone - expecially for patience.
im using WIN32_FIND_DATA to store the data findfirstfile outputs. i want the file location (C:\file) as a string but i don't know how to get it or any other data from it.
Edit: here is my code
PTSTR pszFileName;
PTSTR pszFileName2[100];
if (search_handle)
{
do
{
pszFileName = file.cFileName;
pszFileName2[loop] = pszFileName;
Sleep(100);
loop++;
std::wcout << file.cFileName << std::endl;
}
while(FindNextFile(search_handle,&file));
CloseHandle(search_handle);
}
WIN32_FIND_DATA is a struct. Check out the cFileName member.
For example:
WIN32_FIND_DATA FindData = {0};
HANDLE hFind = FindFirstFile(pszPattern, &FindData);
if (hFind != INVALID_HANDLE_VALUE)
{
do
{
PTSTR pszFileName = FindData.cFileName;
// TODO: Use pszFileName in some way...
} while (FindNextFile(hFind, &FindData));
FindClose(hFind);
}
Update in response to comments
In this example the storage for the string is on the stack, and the same buffer is used for every call. This means that every FindNextFile() overwrites the previous string. You will have to make a copy of the string.
Since you're using C++ and classes in std I suggest you store it in std::string (or better yet, make sure you define UNICODE and _UNICODE and use wstring.) Initializing a new string class will do the allocation and copying on your behalf.
Alternatively you can copy the string using the typical C techniques (for example: using malloc + memcpy, strdup, or similar), but it sounds like you might want a refresher in strings, pointers, and memory allocation in C before you get to that.
By the way -- to check for error, your code compares the find handle against NULL; this is incorrect. FindFirstFile() returns INVALID_HANDLE_VALUE (which works out to (HANDLE)-1) on failure. Additionally, to close the handle you will want to use FindClose(), and not CloseHandle(). (A "find handle" isn't really a handle to a kernel object in the same sense that a file handle, handle to a module, or a thread or process handle is. They've just overloaded the type.)
The problem is that you're storing the address of the filename in your array. Each time that FindNextFile() is called, it replaces the data in the struct with the information for the next file. You need to allocate memory for the string in your array, and then copy the string from the structure to your array (using something like strncpy_s(), probably).
Your code is just storing the pointer to the filename member of the struct, once per found file. If you look at the address each element in the array is pointing to, they're all pointing to the same place.
I'm creating an IStream as follow:
IStream* stream;
result = CreateStreamOnHGlobal(0, TRUE, &stream);
Then I have a CImage object that I save to this stream:
image->Save(stream, Gdiplus::ImageFormatBMP);
I need to get the size of bytes written to this IStream.
How can I do this?
There is no Length or something like this in the IStream...
thanks!
IStream::Stat should do what you want.
Or you can use:
ULARGE_INTEGER liSize;
IStream_Size(pStream, &liSize);
other functions you might find useful in this context:
IStream_Reset(pStream); // reset seek position to beginning
IStream_Read(pStream, mem, size);
Both IStream_Size as well as IStream::Stat can be used to request the size. IStream_Size appears to be a convenience wrapper around IStream::Stat (that's oddly only available as a C COM macro). If that is indeed the case then there's a lot of data queried: An entire STATSTG, optionally without the pwcsName member.
In that case, a less costly way to get the same information would be IStream::Seek:
HRESULT get_size(IStream* stream, ULARGE_INTEGER& size) {
return IStream->Seek({}, STREAM_SEEK_END, &size);
}
This changes the stream's current read or write pointer. If you need to save the current position you can use the following:
ULARGE_INTEGER current{};
stream->Seek({}, STREAM_SEEK_CUR, ¤t);