Using this msdn reference I created a small use case.
#include <iostream>
#include <windows.h>
int main()
{
const std::wstring dir_path = L"\\\\?\\c:\\temp\\ThisIsPrettyLongNameForDirectory\\ThisIsPrettyLongNameForDirectory\\ThisIsPrettyLongNameForDirectory\\ThisIsPrettyLongNameForDirectory\\ThisIsPrettyLongNameForDirectory\\ThisIsPrettyLongNameForDirectory\\ThisIsPrettyLongNameForDirectory\\ThisIsPrettyLongNameForDirectory\\ThisIsPrettyLongNameForDirectory\\ThisIsPrettyLongNameForDirectory\\ThisIsPrettyLongNameForDirectory\\ThisIsPrettyLongNameForDirectory\\ThisIsPrettyLongNameForDirectory";
if (!CreateDirectoryW(dir_path.c_str(), NULL))
{
std::cout << " Error occurred while creation of directory!!! " << GetLastError() << std::endl;
}
else
{
std::cout << "Lenth is " << dir_path.length() << std::endl;
if (dir_path.length() > 255)
{
if (!SetCurrentDirectoryW(buf.c_str()))
{
std::cout << " Error occurred!!! " << GetLastError() << std::endl;
}
else
{
std::cout << " Successful!!!" << std::endl;
}
}
}
return 0;
}
However, I get the output as
Error occurred while creation of directory!!! 3
Error code 3 points me to
ERROR_PATH_NOT_FOUND
3 (0x3)
The system cannot find the path specified.
Are there any other way to use long path names in CreateDirectoryW or SetCurrentDirectoryW APIs that I am unaware of ?
PS:I am using VS 2015 Update 3 compiler on Windows 7.
You have to create each directory on the path one by one. So the parent directory to the directory you pass must exist before you call CreateDirectory.
This information can be found by reading the documentation. It specifically calls out that error code and says:
One or more intermediate directories do not exist; this function will only create the final directory in the path.
Related
I am building an application and I need to get the HDD size:
I am working on Mac OS. I have tried this:
#include <sys/param.h>
#include <sys/mount.h>
float MonitoringWorker::getHDDSize()
{
struct statfs statf;
statfs(".", &statf);
std::cout << "statf.f_bsize = " << statf.f_bsize << std::endl;
std::cout << "statf.f_blocks = " << statf.f_blocks << std::endl;
std::cout << "statf.f_bavail = " << statf.f_bavail << std::endl;
std::cout << "statf.f_bfree = "<< statf.f_bfree << std::endl;
std::cout << "GB = "<< ((statf.f_bsize * statf.f_blocks) / kBytesInGB)<< std::endl;
return 0;
}
I am seeing that the result in GB is 465. However checking System Information tells me that I have 500GB
What am I doing wrong? Is this best way to get those numbers?
Note: I am using C++ on Mac OS, can't use Objective-C
Thanks in advance
I am trying to use exiftool form Cocoa
#include <iostream>
#include "ExifTool.h" // this is a .mm file so that we can include C++ code/structures
#implementation MyClass
-(id)myInit
{
if (self = [super init])
{
ExifTool* tool = new ExifTool("/Users/trygve/Tools/exiftool");
}
}
This is obviously just a test but in the "new ExifTool" line I get a crash:
dyld`dyld_fatal_error:
0x7fff5fc01074 <+0>: int3
-> 0x7fff5fc01075 <+1>: nop
Thread 1: EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0)
dyld: Symbol not found: __ZN8ExifToolC1EPKcS1_
The following code works fine in a straight C++ terminal program. This is from the examples on the exiftool developer page. Why does this code work fine, but when I try to use it from a Cocoa .mm file, it does not?
#include <iostream>
#include "ExifTool.h"
int main(int argc, char **argv)
{
if (argc < 2) {
std::cout << "Example1: Read metadata from an image." << std::endl;
std::cout << "Please specify input file name" << std::endl;
return 1;
}
// create our ExifTool object
ExifTool *et = new ExifTool("/Users/trygve/Tools/exiftool");
// read metadata from the image
TagInfo *info = et->ImageInfo(argv[1],NULL,5);
if (info) {
// print returned information
for (TagInfo *i=info; i; i=i->next) {
std::cout << i->name << " = " << i->value << std::endl;
}
// we are responsible for deleting the information when done
delete info;
} else if (et->LastComplete() <= 0) {
std::cerr << "Error executing exiftool!" << std::endl;
}
// print exiftool stderr messages
char *err = et->GetError();
if (err) std::cerr << err;
delete et; // delete our ExifTool object
return 0;
}
It turns out that the C++ code files associated with this were getting copied into the app rather than compiled. It works as expected. With just the header files there was no error, and a pretty cryptic crash.
according to cplusplus.com on std::bad_alloc
Type of the exceptions thrown by the standard definitions of operator new and operator new[] when they fail to allocate the requested storage space.
However, in my code the new operator is not used:
#include <iostream>
#include <boost/filesystem.hpp>
#include <cstdint>
using namespace std;
using namespace boost::filesystem;
int main()
{
path p{};
std::cin >> p;
if (exists(p)) // does p actually exist?
{
if (is_regular_file(p)) // is p a regular file?
cout << p << " size is " << file_size(p) << '\n';
else if (is_directory(p)) // is p a directory?
cout << p << "is a directory\n";
else
cout << p << "exists, but is neither a regular file nor a directory\n";
}
else
cout << p << "does not exist\n";
return 0;
}
(code taken from boost filesystem tutorial)
and yet the console says:
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Aborted (core dumped)
I'd like to transmit a shared_ptr object via boost asio from a client to a server. Here is my code:
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/asio.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <chrono>
#include <iostream>
#include <sstream>
#include <string>
#include <thread>
using namespace std;
class Message {
public:
Message() {
}
virtual ~Message() {
}
string text;
private:
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive &ar, const unsigned int version) {
ar &text;
}
};
BOOST_CLASS_EXPORT(Message)
void runClient() {
// Give server time to startup
this_thread::sleep_for(chrono::milliseconds(3000));
boost::asio::ip::tcp::iostream stream("localhost", "3000");
boost::archive::text_oarchive archive(stream);
for (int i = 0; i < 10; i++) {
std::shared_ptr<Message> dl = std::make_shared<Message>();
stringstream ss;
ss << "Hello " << i;
dl->text = ss.str();
archive << dl;
}
stream.close();
cout << "Client shutdown" << endl;
}
void handleIncommingClientConnection(boost::asio::ip::tcp::acceptor &acceptor) {
boost::asio::ip::tcp::iostream stream;
acceptor.accept(*stream.rdbuf());
boost::archive::text_iarchive archive(stream);
while (true) {
std::shared_ptr<Message> m;
try {
archive >> m;
cout << m->text << endl;
} catch (std::exception &ex) {
cout << ex.what() << endl;
if (stream.eof()) {
cout << "eof" << endl;
stream.close();
cout << "Server: shutdown client handling..." << endl;
break;
} else
throw ex;
}
}
}
void runServer() {
boost::asio::io_service ios;
boost::asio::ip::tcp::endpoint endpoint = boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 3000);
boost::asio::ip::tcp::acceptor acceptor(ios, endpoint);
handleIncommingClientConnection(acceptor);
}
int main(int argc, char **argv) {
thread clientThread(runClient);
thread serverThread(runServer);
clientThread.join();
serverThread.join();
return 0;
}
Here is the program output:
Hello 0
Hello 1
Hello 2
Hello 3
Hello 3
Hello 3
Hello 3
Hello 3
Client shutdown
Hello 3
Hello 3
input stream error
eof
Server: shutdown client handling...
I am expecting the following output:
Hello 0
Hello 1
Hello 2
Hello 3
Hello 4
Hello 5
Hello 6
Hello 7
Client shutdown
Hello 8
Hello 9
input stream error
eof
Server: shutdown client handling...
When changing the shared_ptr to a simple object (std::shared_ptr<Message> m; to Message m) everything works as expected. I want to stick to the shared_ptr. What do I need to change?
Serialization alone seems to work:
stringstream stream;
{
boost::archive::text_oarchive archive(stream);
std::shared_ptr<Message> dl = std::make_shared<Message>();
stringstream ss;
ss << "Hello World!";
dl->text = ss.str();
archive << dl;
}
{
boost::archive::text_iarchive archive(stream);
std::shared_ptr<Message> m;
archive >> m;
cout << m->text << endl;
}
Output: Hello World!
The issues you're encountering are due to object tracking done by Boost.Serialization.
Depending on how the class is used and other factors, serialized
objects may be tracked by memory address. This prevents the same
object from being written to or read from an archive multiple times.
These stored addresses can also be used to delete objects created
during a loading process that has been interrupted by throwing of an
exception.
The documentation actually foreshadows this specific issue happening:
This could cause problems in progams[sic] where the copies of different
objects are saved from the same address.
Furthermore, the Class Serialization Traits documentation on object tracking tells us that in this particular situation, object tracking is enabled:
Default tracking traits are:
For primitive, track_never.
For pointers, track_never. That is, addresses of addresses are not tracked by default.
All current serialization wrappers such as boost::serialization::nvp, track_never.
For all other types, track_selectively. That is addresses of serialized objects are tracked if and only if one or more of the
following is true:
an object of this type is anywhere in the program serialized through a pointer.
the class is explicitly "exported" - see below.
the class is explicitly "registered" in the archive
Going back to your situation -- in the client, due to how your loop body is written, the 5th (and following) Message instance were allocated at the same address as the 4th Message instance. You can verify this by inspecting the values of dl.get() in each iteration. (In my tests on coliru, all of the instances were allocated at the same address, so YMMV).
Due to how object tracking works, all those shared_ptr instances were considered to point to the same Message instance (even though you changed the value meanwhile -- the library does not expect this happening), so the additional occurrences were just serialized as additional references. Upon deserialization... to be honest this smells of memory leaks and/or dangling reference issues (opinion, haven't investigated this in detail).
Summed up, the main issue with the code as shown is that it breaks a prerequisite of the serialization library, which is that you're serializing some constant state, and on deserialization you recreate that same state.
One way to address this would be to have an initialized std::vector of shared_ptr<Message> containing all the messages to transmit in this particular transaction. Similarly, you'd deserialize the whole vector on the other side. If you expect to have some persistent connection, then add framing to the protocol, with each frame containing an archive that contains one sequence of messages.
Minimal code modifications to make this work -- add include
#include <boost/serialization/vector.hpp>
Change runClient() as such:
void runClient() {
// Give server time to startup
this_thread::sleep_for(chrono::milliseconds(3000));
boost::asio::ip::tcp::iostream stream("127.0.0.1", "3000");
std::vector<std::shared_ptr<Message>> messages;
for (int i = 0; i < 10; i++) {
std::shared_ptr<Message> dl = std::make_shared<Message>();
stringstream ss;
ss << "Hello " << i;
dl->text = ss.str();
messages.emplace_back(dl);
}
boost::archive::text_oarchive archive(stream);
archive << messages;
stream.close();
cout << "Client shutdown" << endl;
}
And change handleIncommingClientConnection(...) as such:
void handleIncommingClientConnection(boost::asio::ip::tcp::acceptor &acceptor) {
boost::asio::ip::tcp::iostream stream;
acceptor.accept(*stream.rdbuf());
boost::archive::text_iarchive archive(stream);
while (true) {
try {
std::vector<std::shared_ptr<Message>> messages;
archive >> messages;
for (auto const& m : messages) {
cout << m->text << endl;
}
} catch (std::exception &ex) {
cout << ex.what() << endl;
if (stream.eof()) {
cout << "eof" << endl;
stream.close();
cout << "Server: shutdown client handling..." << endl;
break;
} else
throw ex;
}
}
}
NB: This doesn't add any support for multiple frames -- the client is expected to close the connection after it sent one vector of messages, otherwise the behaviour is undefined.
Sample on Coliru
Further resources:
boost serialization multiple objects
In Boost.Test, how can I obtain the name of the current auto test case?
Example:
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_CASE(MyTest)
{
std::cerr << "Starting " << test_name << std::endl;
// lots of code here
std::cerr << "Ending " << test_name << std::endl;
}
In the example, I want the variable test_name to contain "MyTest".
There is an undocumented* function that may be called for that purpose. The following line will flush the name of the current test to cerr:
#include <boost/test/framework.hpp>
...
std::cerr << boost::unit_test::framework::current_test_case().p_name
<< std::endl;
Note however that using this API does not flush the parameters in case of parametrized tests.
You might also be interested in the test checkpoints** (which seems to be what you want to do.)
#include <boost/test/included/unit_test.hpp>
...
BOOST_AUTO_TEST_CASE(MyTest)
{
BOOST_TEST_CHECKPOINT("Starting");
// lots of code here
BOOST_TEST_CHECKPOINT("Ending");
}
EDIT
* The current_test_case() function is now documented, see the official Boost documentation.
** BOOST_TEST_CHECKPOINT was previously called BOOST_CHECKPOINT. See the Boost changelog (1.35.0).
A different question about suite names gives a way to extract the name rather than just printing it:
auto test_name = std::string(boost::unit_test::framework::current_test_case().p_name)