Lets say I have this class in foobar-shared.lib:
class FooBar {
std::string m_helloWorld;
}
And I have a call in foobar-from.exe using SendCopyData like so:
extern HWND hMainWnd; // foobar-from.exe
{
FooBar fooBar;
HWND hWnd = FindAppWindow(); // foobar-to.exe
COPYDATASTRUCT cds;
cds.dwData = ('f'|('o'<<8)|('o'<<16));
cds.cbData = sizeof(FooBar);
cds.lpData = (LPVOID)fooBar;
SendCopyData(hWnd, (WPARAM)hMainWnd, (LPARAM)&cds);
}
When from a foobar-to.exe, I handle OnCopyData:
BOOL CMainFrame::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct) {
if (pCopyDataStruct->dwData==('f'|('o'<<8)|('o'<<16))) {
FooBar fooBar = *(FooBar *)pCopyDataStruct->lpData;
}
}
This worked fine when FooBar was a struct, but now that it's a class I get this error:
First-chance exception at 0x0064ef81 in foobar-to.exe: 0xC0000005:
Access violation reading location 0x0231dd7c.
I assumed originally that this was because my fooBar instance is on the stack, so I tried moving it to the heap but got a slightly different error (I can post the result here if necessary).
According to MSDN, "The data being passed must not contain pointers or other references to objects not accessible to the application receiving the data." so I suspect that this only possible with struct data. Am I correct?
you are both correct and incorrect.
your problem here is that you don't know the implementation details of std::string. unfortunately, it seems this (standard) class uses a dynamicaly allocated buffer to store its character data. that's why WM_COPYDATA doesn't work with it.
but if your class does not contain a pointer to any external data, as suggested in the documentation, then it would be perfectly valid to copy it using WM_COPYDATA. unfortunately, this greatly limits the possible types for members of your class.
(think WM_COPYDATA is like sending data over a network: you should take care of serializing your class before sending it out in the wild...)
Related
I'm building a publish-subscribe class (called SystermInterface), which is responsible to receive updates from its instances, and publish them to subscribers.
Adding a subscriber callback function is trivial and has no issues, but removing it yields an error, because std::function<()> is not comparable in C++.
std::vector<std::function<void()> subs;
void subscribe(std::function<void()> f)
{
subs.push_back(f);
}
void unsubscribe(std::function<void()> f)
{
std::remove(subs.begin(), subs.end(), f); // Error
}
I've came down to five solutions to this error:
Registering the function using a weak_ptr, where the subscriber must keep the returned shared_ptr alive.
Solution example at this link.
Instead of registering at a vector, map the callback function by a custom key, unique per callback function.
Solution example at this link
Using vector of function pointers. Example
Make the callback function comparable by utilizing the address.
Use an interface class (parent class) to call a virtual function.
In my design, all intended classes inherits a parent class called
ServiceCore, So instead of registering a callback function, just
register ServiceCore reference in the vector.
Given that the SystemInterface class has a field attribute per instance (ID) (Which is managed by ServiceCore, and supplied to SystemInterface by constructing a ServiceCore child instance).
To my perspective, the first solution is neat and would work, but it requires handling at subscribers, which is something I don't really prefer.
The second solution would make my implementation more complex, where my implementation looks as:
using namespace std;
enum INFO_SUB_IMPORTANCE : uint8_t
{
INFO_SUB_PRIMARY, // Only gets the important updates.
INFO_SUB_COMPLEMENTARY, // Gets more.
INFO_SUB_ALL // Gets all updates
};
using CBF = function<void(string,string)>;
using INFO_SUBTREE = map<INFO_SUB_IMPORTANCE, vector<CBF>>;
using REQINF_SUBS = map<string, INFO_SUBTREE>; // It's keyed by an iterator, explaining it goes out of the question scope.
using INFSRC_SUBS = map<string, INFO_SUBTREE>;
using WILD_SUBS = INFO_SUBTREE;
REQINF_SUBS infoSubrs;
INFSRC_SUBS sourceSubrs;
WILD_SUBS wildSubrs;
void subscribeInfo(string info, INFO_SUB_IMPORTANCE imp, CBF f) {
infoSubrs[info][imp].push_back(f);
}
void subscribeSource(string source, INFO_SUB_IMPORTANCE imp, CBF f) {
sourceSubrs[source][imp].push_back(f);
}
void subscribeWild(INFO_SUB_IMPORTANCE imp, CBF f) {
wildSubrs[imp].push_back(f);
}
The second solution would require INFO_SUBTREE to be an extended map, but can be keyed by an ID:
using KEY_T = uint32_t; // or string...
using INFO_SUBTREE = map<INFO_SUB_IMPORTANCE, map<KEY_T,CBF>>;
For the third solution, I'm not aware of the limitations given by using function pointers, and the consequences of the fourth solution.
The Fifth solution would eliminate the purpose of dealing with CBFs, but it'll be more complex at subscriber-side, where a subscriber is required to override the virtual function and so receives all updates at one place, in which further requires filteration of the message id and so direct the payload to the intended routines using multiple if/else blocks, which will increase by increasing subscriptions.
What I'm looking for is an advice for the best available option.
Regarding your proposed solutions:
That would work. It can be made easy for the caller: have subscribe() create the shared_ptr and corresponding weak_ptr objects, and let it return the shared_ptr.
Then the caller must not lose the key. In a way this is similar to the above.
This of course is less generic, and then you can no longer have (the equivalent of) captures.
You can't: there is no way to get the address of the function stored inside a std::function. You can do &f inside subscribe() but that will only give you the address of the local variable f, which will go out of scope as soon as you return.
That works, and is in a way similar to 1 and 2, although now the "key" is provided by the caller.
Options 1, 2 and 5 are similar in that there is some other data stored in subs that refers to the actual std::function: either a std::shared_ptr, a key or a pointer to a base class. I'll present option 6 here, which is kind of similar in spirit but avoids storing any extra data:
Store a std::function<void()> directly, and return the index in the vector where it was stored. When removing an item, don't std::remove() it, but just set it to std::nullptr. Next time subscribe() is called, it checks if there is an empty element in the vector and reuses it:
std::vector<std::function<void()> subs;
std::size_t subscribe(std::function<void()> f) {
if (auto it = std::find(subs.begin(), subs.end(), std::nullptr); it != subs.end()) {
*it = f;
return std::distance(subs.begin(), it);
} else {
subs.push_back(f);
return subs.size() - 1;
}
}
void unsubscribe(std::size_t index) {
subs[index] = std::nullptr;
}
The code that actually calls the functions stored in subs must now of course first check against std::nullptrs. The above works because std::nullptr is treated as the "empty" function, and there is an operator==() overload that can check a std::function against std::nullptr, thus making std::find() work.
One drawback of option 6 as shown above is that a std::size_t is a rather generic type. To make it safer, you might wrap it in a class SubscriptionHandle or something like that.
As for the best solution: option 1 is quite heavy-weight. Options 2 and 5 are very reasonable, but 6 is, I think, the most efficient.
Given the following code how can I convert the v8::Local<v8::Value> into a uint32_t. Or other types based on the Is* method?
v8::Local<v8::Value> value;
v8::Local<v8::Context> context = v8::Context::New(v8::Isolate::GetCurrent());
if(value->IsUint32()) {
v8::MaybeLocal<Int32> maybeLocal = value->Uint32Value(context);
uint32_t i = maybeLocal;
}
Your posted code doesn't work because value->Uint32Value(context) doesn't return a v8::MaybeLocal<Int32>. C++ types are your friend (just like TypeScript)!
You have two possibilities:
(1) You can use Value::Uint32Value(...) which returns a Maybe<uint32_t>. Since you already checked that value->IsUint32(), this conversion cannot fail, so you can extract the uint32_t wrapped in the Maybe using Maybe::ToChecked().
(2) You can use Value::ToUint32(...) which returns a MaybeLocal<Uint32>. Again, since you already checked that value->IsUint32(), that cannot fail, so you can get a Local<Uint32> via MaybeLocal::ToLocalChecked(), and then simply use -> syntax to call the wrapped Uint32's Value() method, which gives a uint32_t.
If you're only interested in the final uint32_t (and not in the intermediate Local<Uint32>, which you could pass back to JavaScript), then option (1) will be slightly more efficient.
Note that IsUint32() will say false for objects like {valueOf: () => 42; }. If you want to handle such objects, then attempt the conversion, and handle failures, e.g.:
Maybe<uint32_t> maybe_uint = value->Uint32Value(context);
if (maybe_uint.IsJust()) {
uint32_t i = maybe_uint.FromJust();
} else {
// Conversion failed. Maybe it threw an exception (use a `v8::TryCatch` to catch it), or maybe the object wasn't convertible to a uint32.
// Handle that somehow.
}
Also, note that most of these concepts are illustrated in V8's samples and API tests. Reading comments and implementations in the API headers themselves also provides a lot of insight.
Final note: you'll probably want to track the current context you're using, rather than creating a fresh context every time you need one.
I have an easy question about shared pointers and move semantics. Imagine that I have a class with a private member variable like this:
class C
{
private:
std::shared_ptr<std::vector<uint8_t>> buffer;
}
I need to provide public getters and setters. The getter seems obvious:
std::shared_ptr<std::vector<uint8_t>> C::GetBuffer()
{
return buffer;
}
However, being new to C++ I'm having trouble writing the setter. I could do something like this:
void C::SetBuffer(std::shared_ptr<std::vector<uint8_t>> input)
{
buffer = input;
}
However that results in a copy of input to buffer, but I don't really want the caller to have shared ownership. Instead I want to move the data. I tried to solve this with:
void C::SetBuffer(std::shared_ptr<std::vector<uint8_t>>& input)
{
buffer(std::move(input));
}
But this is an error: "call of an object of a class type without appropriate operator() or conversion functions to pointer-to-function type."
Can somebody help me understand:
1. What is going on here?
2. How to best implement the setter?
You can fix the error you're getting by writing this:
void C::SetBuffer( std::shared_ptr<std::vector<uint8_t> > &input ) {
buffer = move(input);
}
This will call shared_ptr's move-assignment operator, which will pilfer input. However, this won't really stop the caller from having shared ownership. Once you accept (or dispense) a shared_ptr from/to an unknown client, you don't have much in the way of control about who shares ownership. Even if input is pilfered, there's no reason to expect that input was the only copy of the shared_ptr you just received. If, for example, the function that called SetBuffer() took whatever became input from its caller by value, that higher-level copy of the pointer will continue to share ownership.
Note that your getter has a similar issue. You're returning a shared_ptr to your own internal object (and what's more, it's a shared_ptr-to-non-const, so the client can modify the shared state) and wherever that shared_ptr gets passed around after you provide it, those copies will also share (mutable) ownership.
If you really want to ensure you have exclusive ownership, you can hold a unique_ptr instead of a shared_ptr and have your getter pass back a const-reference, and your setter take either a unique_ptr or a value.
If your goal is to allow a caller to pass sole ownership of a buffer to your object, you should accept it by unique_ptr instead of shared_ptr:
void C::SetBuffer(std::unique_ptr<std::vector<uint8_t>> input)
{
buffer = std::move(input);
}
Rvalue unique_ptr is convertible to shared_ptr for exactly this purpose.
I am trying to use a FILE pointer multiple times through out my application
for this I though I create a function and pass the pointer through that. Basically I have this bit of code
FILE* fp;
_wfopen_s (&fp, L"ftest.txt", L"r");
_setmode (_fileno(fp), _O_U8TEXT);
wifstream file(fp);
which is repeated and now instead I want to have something like this:
wifstream file(SetFilePointer(L"ftest.txt",L"r"));
....
wofstream output(SetFilePointer(L"flist.txt",L"w"));
and for the function :
FILE* SetFilePointer(const wchar_t* filePath, const wchar_t * openMode)
{
shared_ptr<FILE> fp = make_shared<FILE>();
_wfopen_s (fp.get(), L"ftest.txt", L"r");
_setmode (_fileno(fp.get()), _O_U8TEXT);
return fp.get();
}
this doesn't simply work. I tried using &*fp instead of fp.get() but still no luck.
You aren't supposed to create FILE instances with new and destroy them with delete, like make_shared does. Instead, FILEs are created with fopen (or in this case, _wfopen_s) and destroyed with fclose. These functions do the allocating and deallocating internally using some unspecified means.
Note that _wfopen_s does not take a pointer but a pointer to pointer - it changes the pointer you gave it to point to the new FILE object it allocates. You cannot get the address of the pointer contained in shared_ptr to form a pointer-to-pointer to it, and this is a very good thing - it would horribly break the ownership semantics of shared_ptr and lead to memory leaks or worse.
However, you can use shared_ptr to manage arbitrary "handle"-like types, as it can take a custom deleter object or function:
FILE* tmp;
shared_ptr<FILE> fp;
if(_wfopen_s(&tmp, L"ftest.txt", L"r") == 0) {
// Note that we use the shared_ptr constructor, not make_shared
fp = shared_ptr<FILE>(tmp, std::fclose);
} else {
// Remember to handle errors somehow!
}
Please do take a look at the link #KerrekSB gave, it covers this same idea with more detail.
Has anyone managed to do this? I tried making a managed wrapper class for IPropertyStore but am getting AccessViolationExceptions on the methods (i.e. IPropertyStore::GetValue) that take a pointer to PROPVARIANT (rendered as a MarshalAs(UnmanagedType.Struct) out parameter in my managed version) Probably my understanding of COM and interop is inadequate --- I'm not sure if the problems are in my PROPVARIANT struct declaration (which currently just uses StructLayout.Sequential, declares a sequence of bytes, and manually manipulates the bytes to get values of the various types in the union etc.), COM issues with what process owns what, or something else. I've tried various other versions of the PROPVARIANT such as using StructLayout.Explicit for the unions, nothing's worked. Retrieving PROPERTYKEYs with IPropertyStore::GetAt --- which is declared natively as taking a pointer to PROPERTYKEY and as having an out parameter of my own StructLayout.Sequential PROPERTYKEY in my wrapper --- works just fine, by the way.
You should check out http://code.msdn.microsoft.com/WindowsAPICodePack . It has support for consuming the Windows Property System, and a bunch of other windows shell capabilities. I think it's exactly what you are looking for.
Well, here's the version from MS.Internal.Interop (a trove of knowledge):
[StructLayout(LayoutKind.Sequential), FriendAccessAllowed]
internal struct PROPVARIANT
{
internal VARTYPE vt;
internal ushort wReserved1;
internal ushort wReserved2;
internal ushort wReserved3;
internal PropVariantUnion union;
}
[FriendAccessAllowed]
internal enum VARTYPE : short
{
VT_BSTR = 8,
VT_FILETIME = 0x40,
VT_LPSTR = 30,
// etc...
}
[StructLayout(LayoutKind.Explicit), FriendAccessAllowed]
internal struct PropVariantUnion
{
[FieldOffset(0)]
internal BLOB blob;
[FieldOffset(0)]
internal short boolVal;
// etc... see MS.Internal.Interop for full definition
}
These definitions will help you make sure your structures are at least correct. As for your other problems, I don't have an answer.