I have this structure:
using SPECIAL_EVENT_S = struct tagSpecialEvent
{
COleDateTime datEvent;
CString strEvent;
CString strLocation;
int iSRREventType;
int iSMREventType;
int iForeignLanguageGroupMenuID;
COleDateTime datEventStartTime;
COleDateTime datEventFinishTime;
BOOL bEventAllDay;
BOOL bSetReminder;
int iReminderUnitType;
int iReminderInterval;
int iImageWidthPercent;
CString strImagePath;
CString strTextBeforeImage;
CString strTextAfterImage;
CChristianLifeMinistryDefines::VideoConferenceEventType eType;
};
And I have instances of this structure as pointers in CListBox items. I now have a need to duplicate a structure so that it is a new instance. At the moment I am doing it like this:
auto* psThisEvent = static_cast<SPECIAL_EVENT_S*>(m_lbEvents.GetItemDataPtr(iThisEventIndex));
if (psThisEvent == nullptr)
return;
auto* psNewEvent = new SPECIAL_EVENT_S;
if (psNewEvent == nullptr)
return;
psNewEvent->bEventAllDay = psThisEvent->bEventAllDay;
psNewEvent->bSetReminder = psThisEvent->bSetReminder;
psNewEvent->datEvent = datNewEvent;
psNewEvent->datEventFinishTime = psThisEvent->datEventFinishTime;
psNewEvent->datEventStartTime = psThisEvent->datEventStartTime;
psNewEvent->eType = psThisEvent->eType;
psNewEvent->iForeignLanguageGroupMenuID = psThisEvent->iForeignLanguageGroupMenuID;
psNewEvent->iImageWidthPercent = psThisEvent->iImageWidthPercent;
psNewEvent->iReminderInterval = psThisEvent->iReminderInterval;
psNewEvent->iReminderUnitType = psThisEvent->iReminderUnitType;
psNewEvent->iSMREventType = psThisEvent->iSMREventType;
psNewEvent->iSRREventType = psThisEvent->iSRREventType;
psNewEvent->strEvent = psThisEvent->strEvent;
psNewEvent->strImagePath = psThisEvent->strImagePath;
psNewEvent->strLocation = psThisEvent->strLocation;
psNewEvent->strTextAfterImage = psThisEvent->strTextAfterImage;
psNewEvent->strTextBeforeImage = psThisEvent->strTextBeforeImage;
Is this the right way to go about this? I saw this question but I am not sure if it is safe to use memcpy in this case.
I am not sure if it is safe to use memcpy in this case.
Your doubts are well-founded. The SPECIAL_EVENT_S structure has members that are not trivially copyable (i.e. cannot be properly copied using memcpy). For example, it contains several CString members – a class with embedded data buffers and pointers; thus if the structure is simply copied memory-to-memory, then destroying one structure (the destination) will potentially cause those data buffers of the CString objects in the other structure (the source) to be invalidated. You must call the CString copy constructor for each of those objects. (The same may also be true of the COleDateTime member objects.)
As mentioned in the comments, calling the implicitly-defined copy constructor or copy assignment operator for the SPECIAL_EVENT_S should take care of this; something along the lines of:
*psNewEvent = *psThisEvent;
But, as you have correctly noted, you will then need to explicitly assign the datEvent member after that copy constructor/assignment:
psNewEvent->datEvent = datNewEvent;
Related
In ClaiR it is not (yet) possible to write changes made in the AST back to file.
For this reason, I create a list lrel[int, int, str] changes = []; with startposition and endposition of the substring to remove, and a string with which it needs to be replaced.
When I have a full list of changes I want to make to a source file, I sort the changes and open the file with fb = chars(readFile(f));
make the changes
public list[int] changeCharList(list[int] charList, lrel[int, int, str] changesList) {
int offset = 0;
for (t <- [0 .. size(changesList)]) {
tuple[int startIndex, int endIndex, str changeWithString] change = changesList[t];
int startIndexWithOffset = change.startIndex + offset;
int endIndexWithOffset = change.endIndex + offset;
list[int] changeWithChars = chars(change.changeWithString);
for (i <- [startIndexWithOffset .. endIndexWithOffset]) {
charList = delete(charList, startIndexWithOffset);
}
for (i <- [0 .. size(changeWithChars)]) {
charList = insertAt(charList, startIndexWithOffset + i, changeWithChars[i]);
}
offset += size(changeWithChars) - (change.endIndex - change.startIndex);
}
return charList;
}
and write to file writeFileBytes(f, fb);
This approach works for source files without expanded macros, but it does not work for sources files with expanded macros. In the later case the offsets used in the AST do not map the offsets with the file opened using readFile.
As a workaround I can comment macros before running Rascal and uncomment them after running Rascal. I do not like this.
Is there a way to recalculate the offsets in such a way that the AST offsets map the file read offsets?
I'm using CTreeCtrl to display some data. With each entry in the tree, I have some associated data which I keep in a struct. I save this data with the item by putting the pointer to the struct in the lParam value in each entry in the tree.
This is my add entries code to the tree:
void CClassView::AddElementToTree(Element* _pElement, HTREEITEM _hRoot)
{
HTREEITEM hBranch;
TVINSERTSTRUCT tvInsert;
ZeroMemory(&tvInsert, sizeof(tvInsert));
tvInsert.hParent = _hRoot;
tvInsert.hInsertAfter = NULL;
tvInsert.item.mask = TVIF_TEXT;
WCHAR szText[64] = {'\0'};
tvInsert.item.pszText = szText;
for(std::vector<Element*>::iterator i = _pElement->pChildren.begin(); i != _pElement->pChildren.end(); ++i)
{
wcscpy_s(szText, (*i)->GetName().c_str());
tvInsert.item.lParam = (LPARAM)(*i);
hBranch = m_wndClassView.InsertItem(&tvInsert);
AddElementToTree(*i, hBranch);
}
}
Essentially this function recursively add an element to the tree, with its children. _pElement I pass externally. This is a member variable of my class so I know it is not destroyed unless the program ends.
When the user selects an entry in the tree view, I handle the selchanged message:
void CLayerTree::OnTvnSelchanged(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
Element* pElement = (Element*)pNMTreeView->itemNew.lParam;
*pResult = 0;
}
pElement is always NULL. I debugged the program and it seems lParam is also zero.
Am I doing anything wrong? I know that the memory of my struct has not been deallocated. Is it something wrong I'm doing adding the entry to the tree?
Any help would be appreciated.
TVIF_PARAM must be set in the mask!
I'm new to both protocol buffers and C++, so this may be a basic question, but I haven't had any luck finding answers. Basically, I want the functionality of a dictionary defined in my .proto file like an enum. I'm using the protocol buffer to send data, and I want to define units and their respective names. An enum would allow me to define the units, but I don't know how to map the human-readable strings to that.
As an example of what I mean, the .proto file might look something like:
message DataPack {
// obviously not valid, but something like this
dict UnitType {
KmPerHour = "km/h";
MiPerHour = "mph";
}
required int id = 1;
repeated DataPoint pt = 2;
message DataPoint {
required int id = 1;
required int value = 2;
optional UnitType theunit = 3;
}
}
and then have something like to create / handle messages:
// construct
DataPack pack;
pack->set_id(123);
DataPack::DataPoint pt = pack.add_point();
pt->set_id(456);
pt->set_value(789);
pt->set_unit(DataPack::UnitType::KmPerHour);
// read values
DataPack::UnitType theunit = pt.unit();
cout << theunit.name << endl; // print "km/h"
I could just define an enum with the unit names and write a function to map them to strings on the receiving end, but it would make more sense to have them defined in the same spot, and that solution seems too complicated (at least, for someone who has lately been spoiled by the conveniences of Python). Is there an easier way to accomplish this?
You could use custom options to associate a string with each enum member:
https://developers.google.com/protocol-buffers/docs/proto#options
It would look like this in the .proto:
extend google.protobuf.FieldOptions {
optional string name = 12345;
}
enum UnitType {
KmPerHour = 1 [(name) = "km/h"];
MiPerHour = 2 [(name) = "mph"];
}
Beware, though, that some third-party protobuf libraries don't understand these options.
In proto3, it's:
extend google.protobuf.EnumValueOptions {
string name = 12345;
}
enum UnitType {
KM_PER_HOUR = 0 [(name) = "km/h"];
MI_PER_HOUR = 1 [(name) = "mph"];
}
and to access it in Java:
UnitType.KM_PER_HOUR.getValueDescriptor().getOptions().getExtension(MyOuterClass.name);
I define a com object as a dynamic type in c# I am able to call methods quite easily.
However when I try to access a property on the same object I get an invalid cast exception.
The object in question is an array, passed to managed code from JavaScript, and I wish to get the length property of it as an int.
I know I am missing something odd because I am not getting a 'does not contain a definition' exception and I can access the property easily using reflection/InvokeMember.
Why can I not convert the length property of the dynamic type to an int?
For example
This Fails
dynamic com = comObject;
int i = com.length; // RTBE here.
This Works
Type type = comObject.GetType();
int i = (int)type.InvokeMember("length", BindingFlags.GetProperty, null, comObject, null);
* Update *
After a lot of testing I have narrowed this oddness to cases of multi-dimensional arrays.
The com object in question is a parameter passed from a html document to managed code. For all intents and purposes the object sometimes looks like this in JavaScript.
var x = ["a1", "a2", "a3"];
When an array like this comes to managed code I am able to get the length AOK using the type dynamic. (i.e. the first example here that fails actually works). However, if it is a multi-dimensional array such as the following structure in JavaScript.
var y = [["b1", "b2", "b3"], "a2", "a3"];
Then I get an error when trying to access its length property dynamically. Note, I can still access the length via reflection in this case. It seems to me that for some reason the length property does not get correctly mapped when a multidimensional array is used as a dynmaic type...
In my case what I have done to solve(!?) this is add a 'length_' property to the array like so before passing it.
var y = [["b1", "b2", "b3"], "a2", "a3"];
y.length_ = y.length;
Now in managed code I can accesses this property as expected without error. Far from ideal but seems to work...
dynamic com = comObject;
int i = com.length_; // 3!
Further Update
Ok, so it seems that as well as the length property the objects index gets lost to the dynamic type as well. Again it is accessible via reflection though...
Fails
dynamic com = comObject; // js array i.e. var x = [1, 2];
int i = com[0]; // MissingMemberException - Error while invoking [PROPERTYGET, DISPID(0)].
int i = com["0"]; // MissingMemberException - Error while invoking [PROPERTYGET, DISPID(0)].
Works
Type type = comObject.GetType();
int i = (int)type.InvokeMember("0", BindingFlags.GetProperty, null, comObject, null); // 1
In simple terms you can't access the length property of a multi-dimensional array in c# via the type dynamic unless, it seems, you have used the length property in JavaScript first...
The simple test below shows this very clearly. I hope this saves someone else the head scratching I have been having over the last day or so.
[ComVisibleAttribute(true)]
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
webBrowser1.ObjectForScripting = this;
StringBuilder html = new StringBuilder();
html.Append("<script>");
html.Append("var arr1 = [1, 2, 3, 4];");
html.Append("var arr2 = [arr1, 2, 3, 4];");
html.Append("var fn1 = function() { return arr1; };");
html.Append("var fn2 = function() { return arr2; };");
html.Append("var fn3 = function() { alert(arr2.length); }");
html.Append("</script>");
webBrowser1.DocumentText = html.ToString();
webBrowser1.DocumentCompleted += (o, e) =>
{
dynamic arr1 = webBrowser1.Document.InvokeScript("fn1");
int i = arr1.length;
MessageBox.Show(i.ToString()); //4
// If I call fn3 here then the arr2.length *is* available as int i2 below!
////webBrowser1.Document.InvokeScript("fn3"); // 4
dynamic arr2 = webBrowser1.Document.InvokeScript("fn2");
int i2 = arr2.length;
MessageBox.Show(i2.ToString()); // unless fn3 is called you get...
/*
System.MissingMemberException was unhandled by user code
Message=Error while invoking length.
Source=System.Dynamic
StackTrace:
at System.Dynamic.ComRuntimeHelpers.CheckThrowException(Int32 hresult, ExcepInfo& excepInfo, UInt32 argErr, String message)
at CallSite.Target(Closure , CallSite , ComObject )
at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
at CallSite.Target(Closure , CallSite , Object )
at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
*/
};
}
}
update
It seems (see comments) that this behaviour is fixed if the WebBrowser control uses version 9 of Internet Explorer (...the control uses the version of IE on the machine). I can only presume that the IE9 'Chakra' JavaScript engine is doing something extra/different to the old js engine in this case.
In the big picture I want to create a frame based application in Bada that has a single UI control - a label. So far so good, but I want it to display a number of my choosing and decrement it repeatedly every X seconds. The threading is fine (I think), but I can't pass the label pointer as a class variable.
//MyTask.h
//...
result Construct(Label* pLabel, int seconds);
//...
Label* pLabel;
//MyTask.cpp
//...
result
MyTask::Construct(Label* pLabel, int seconds) {
result r = E_SUCCESS;
r = Thread::Construct(THREAD_TYPE_EVENT_DRIVEN);
AppLog("I'm in da constructor");
this->pLabel = pLabel;
this->seconds = seconds;
return r;
}
//...
bool
Threading::OnAppInitializing(AppRegistry& appRegistry)
{
// ...
Label* pLabel = new Label();
pLabel = static_cast<Label*>(pForm->GetControl(L"IDC_LABEL1"));
MyTask* task = new MyTask();
task->Construct(&pLabel); // HERE IS THE ERROR no matching for Label**
task->Start();
// ...
}
The problem is that I have tried every possible combination of *, &, and just plain pLabel, known in Combinatorics...
It is not extremely important that I get this (it is just for training) but I am dying to understand how to solve the problem.
Have you tried:
task->Construct(pLabel, 0);
And by that I want to point out that you are missing the second parameter for MyTask::Construct.
No, I haven't. I don't know of a second parameter. But this problem is solved. If I declare a variable Object* __pVar, then the constructor should be Init(Object* pVar), and if I want to initialize an instance variable I should write
Object* pVar = new Object();
MyClass* mClass = new MyClass();
mClass->Construct(pVar);