Using Visual Studio 2010 and working with an MFC SDI Application.
I have a CMFCToolbar object owned by the Main Frame.
When the document in this application is created, the MainFrame calls a function to replace one of the buttons in the CMFCToolbar object with a CMFCToolbarMenuButton. The contents of the menu button are populated with information from the document. The menu creation always works. The call to ReplaceButton always succeeds. But there's a visual symptom of the call that I haven't yet figured out.
Any time ReplaceButton is called, the button disappears. Not only is it not drawn, it's not clickable. It's temporarily gone. I assume this is because there's a dangling reference to the old button, which I have just destroyed with the call to ReplaceButton.
I've tried calling Invalidate(), RecalcLayout() to trigger a re-draw, but neither has worked yet. The only reliable method I have for getting the button to show up is re-sizing the application window manually or by un-docking/re-docking the toolbar. I assume there's some kind of lower-level refresh that occurs in these situations, but I don't know how to trigger it manually.
Is there a way to make sure my button is drawn immediately?
Edit: code sample
Count = m_Doc->...->GetCount();
for (Index = 0; Index < Count; ++Index)
{
Caption.Format(L"%s", m_Doc->...->GetName());
m_pLayerMenu->AppendMenu(MF_ENABLED | MF_STRING, LAYER_DROP_SEED+Index, Caption.GetData());
}
m_wndBrushBar.ReplaceButton(ID_BRUSH_TERRAIN,
CMFCToolBarMenuButton(ID_BRUSH_TERRAIN, *m_pLayerMenu, GetCmdMgr()->GetCmdImage(ID_BRUSH_TERRAIN)));
Update:
Calling m_wndBrushBar.AdjustLayout() seems to stabilize the visual behavior of these CMFCToolbar buttons. So that's a partial solution.
Partial because of the following:
It's hard to tell what the real visual behavior is. It turns out that all visual settings/states are stored in the Registry with these MFC objects, and it can hold onto states of dynamically created objects that really alter the startup behavior of the app.
I've gone in to delete the registry values under
Current User -> "Local App-Wizard Generated Applications" -> [My App Name].
Done this a number of times, just to find out what the real behavior of my app is. Feel like I'm missing some fundamental knowledge with the current version of MFC. Lots of bugs arising from the registry deal.
Is there a way to prevent registry settings for certain objects, or to shut off this behavior altogether? Otherwise, I guess my shutdown process will have to be a LOT more thorough with resetting all the visual elements. Registry values seem to ignore, override, or bypass my startup code. I can code how I want an object to look at startup, but if there are values in the registry, it does no good.
You've discovered a sometimes annoying aspect for the CMFC code. That is, the concept of a Workspace. The Workspace manages the concept of the application state. I, too, have had problems like the one you describe. But, you have the flexibility to manage how those objects are recreated by overriding the LoadState () and SaveState () methods.
Related
My UWP app goes into UI freeze state sometimes and I don't know why。 I've checked the code about view model and async-await calls. And I've tried to use the performance profile tool in Visual Studio to get timeline but it only shows the time and duration time about the UI freeze. I have run out of ideas now.
I tried the dotTrace but it seems that I cannot use it to profile UWP application. Even I " disable the Compile with .NET Native tool chain option in Visual Studio (via the menu Project | Properties... | Build) and rebuild the project."
https://learn.microsoft.com/en-gb/visualstudio/profiling/profiling-feature-tour?view=vs-2019
There are many reasons for UI freezing, including code endless loops, asynchronous methods are not handled properly, program errors, etc.
Most of them occur in asynchronous method processing and UI rendering.
When calling asynchronous methods, use the async/await keywords, like:
//define
public async Task asyncMethod()
{ }
//use
await asyncMethod();
Reduce resource consumption when rendering a large number of data templates through virtualization.
If you have a large list to render, if virtualization is not enabled (referring to controls with virtualization, such as ListView), or used, but the conditions of virtualization are destroyed (such as adding ScrollViewer outside ListView ), This will also cause the UI to freeze and will not return to normal until the list is rendered.
Please check your code for the above problems, or provide a minimal reproducible demo so that we can analyze where the problem occurs.
Best regards.
I would suggest you try to use the Visual Studio debugger to find out what the code is doing.
First, make sure that you are set "Debug" mode and that the debugger is going to run on "Local Machine" (there are other options here, but I'm trying to keep things simple).
Then, click on the "Local Machine" button to run your app using the debugger.
Once your app freezes, click on Debug-Break All:
After that, I suggest you use the various Debug commands to further debug your application.
For example, you can use the "Call Stack" menu item/window to view what your code is doing. You can also use the "Threads" menu to see what threads are running. If you have suspect areas in your code, you might consider adding System.Diagnostics.Debug.WriteLine() statements to print out informative messages, and then use the "Output" menu item/window to see what is happening.
If your app first freezes, and then crashes after some time, then this could be because your tasks don't have correct exception handling. You might consider adding an UnobservedTaskException handler to your code to help you find this problem.
The accessible objects in my custom table control are stored in a doubly linked list in the table itself (so they can be invalidated when the table window is destroyed). Right now, my WM_GETOBJECT handler contains the following erroneous code sequence (where t is the table and ta is the new accessible object):
ta->next = t->firstAcc;
t->firstAcc->prev = ta;
t->firstAcc = ta;
This is an error because when the linked list is empty, t->firstAcc will be NULL, so the second line will lead to a null pointer exception.
...except not. When Inspect.exe queries my table's accessible object, it seems to "intercept" the null pointer exception, bringing my program back to a stable state and repeating the process all over again a few times before finally giving up and just grabbing the standard accessible object instead. The program still runs and seems to run quite well!
And it's not just Inspect.exe; UI Accessibility Checker also exhibits this behavior too.
This is Inspect.exe 7.2.0.0 and UI Accessibility Checker 3.0, both running on Windows 7 64-bit. I forget if both came with Visual Studio 2013 Express for Windows Desktop or not (with one of the Windows SDKs instead). The accessible objects are MSAA IAccessible objects because Windows XP compatibility is still required.
Obviously this makes debugging bugs like this problematic. So my questions are simple:
How are Inspect.exe and UI Accessibility Checker doing this? Is it special code that they share or is there something about MSAA or OLE or COM that does this?
Is there anything I can do about this? Neither of these programs have options to turn off the behavior. Could I just get the accessible object myself (posing as a client) to test this behavior? (That would work for the top-level object, but doing thorough tests for navigation would be a bit more painful.) And if so, would I need to initialize COM (for something in the same process) or run as administrator (because of UIPI)?
Thanks.
I'm trying to add support for tracking application usage to a WP7 app (e.g., how many times has the app been run, including wakeups from tombstoning). I thought I was doing this in a pretty straight-forward way, but I'm frequently getting IsolatedStorageExceptions, and I'm kind of at a loss for debugging it at the moment.
Paraphrasing from my App.xaml.cs
private void HandleAppCounter() {
int i = 0;
settings.TryGetValue<int>("usage", out i);
i++;
settings["usage"] = i;
settings.Save();
}
I call this function when the app is launching or activating. The thing is, it works just fine. But the thing is, if I make another call to isolated storage soon after then that is what blows up. And furthermore, it seems to only blow up if the next call happens pretty soon after.. although I'm having trouble understanding that as well.
The next action performed is usually a user clicking an item in a list. If it happens immediately when it's displayed, I get a crash from isolated storage. If the user waits a few seconds after the app is launched and then clicks it, there is no crash.
If the above code in HandleAppCounter() is commented out, then the user can click either immediately or later and it never crashes.
Can anyone give me some tips on how to debug this? I'm kind of running into a wall here.
I would suggest stepping away from your custom implementation for a sec and try the same behaviour with the default IsolatedStorageSettings class, if it is still a problem then you should report it to Microsoft Connect site as a bug, otherwise there is some kind of an error in your settings class.
If you're using IsolatedStorageSettings you might want to make sure, that whenever you're querying/adding a key, the key is there, if not you must create it.
If you're using IsolatedStorage filesystem then make sure you are always closing the streams when you're reading/writing. If you don't you will get absurd exceptions.
I'm in VS2010, in a new Word Add-In project. This is my first attempt at Word development using VSTO. The example I'm trying has this line:
Document vstoDoc = Globals.Factory.GetVstoObject(this.Application.ActiveDocument);
But when I add this line Visual Studio says it can't find "Factory". Indeed, it's not in Intellisense.
I've got references to:
Accessibility
Microsoft.Office.Interop.Word
Microsoft.Office.Tools.Common.v9.0
Microsoft.Office.Tools.v9.0
Microsoft.Office.Tools.Word.v9.0
Microsoft.VisualStudio.Tools.Applications.Runtime.v9.0
Office
and all the usual System references.
Where am I going wrong and why can't I get to "Factory"?
stdole
That example looks a bit weird to me. Never seen that sort of reference before.
Generally, with Vsto, you hook into EVENTS on, say, the main Word App object.
Then, from within the event, you usually are passed a reference to the particular DOC object that the event is occurring for (say, being opened or saved, etc). In that way, there shouldn't be any need for using the "globals" object or the "factory" object, whereever they might be.
What method is that code in? A little more context might help.
I think the recommended way of doing this is:
Globals.ThisAddin.Application.ActiveDocument
I'm facing some troubles still while learning, so I guess it tends to get worse once I play with the big kids: warnings in dynamics aren't as precise and informative as VS's, there are no mouse-over tips, and exceptions to show me exactly where I've got it wrong.
I'm just too used to Visual Studio, it's intellisense and all the tools (dynamics is quite new when compared to Visual Studio)
More than solving simple code issues, i'd like to learn how to solve upcomming ones i might have in code not written by me or anything else i'd solve in 3 minutes in Visual Studio, as well as tips on how to survive in dynamics ax without all the Visual Studio tools.
The code editor in Dynamics AX has some intellisense, typing the name of a table or class variable followed by . or :: will give you a list of fields or methods available for that item. After you type the ( to start a method call, a tooltip pops up with parameters available on that method. When starting a new line, you can right click and List Tables, List Classes, List Types, etc. Most of those commands are also available via Shortcut Keys. Note that the intellisense only works if all the code in the method up to the location of your cursor is syntactically correct.
Make sure you have updated the cross reference in your development environment (Tools/Development tools/Cross-reference/Periodic/Update). With an updated cross reference, you can right click an any table, field, class, method, extended data type, or enum in the AOT and choose Add-Ins/Cross-reference/Used by to see where that item is used in the system.
You can also use Tools/Development tools/Code explorer to view the source to the application with all types, variables, and methods turned into hyperlinks so you can click to go right to the definition of that item.
Another useful tool is Application hierarchy tree, available either under Tools/Development tools, or on the right click Add-Ins menu. This will show you the class hierarchy, so you can easily see, for example, that SalesFormLetter derives from FormLetter, which derives from RunBaseBatch.
In the editor, you can highlight text and right click to Lookup Properties/Methods or Lookup Definition.
If you are trying to track down where in the system a particular infolog message is generated there are two strategies to use:
Set a breakpoint on the first line
of the method Info.add(). Then when
you run the code generating the
message, you will pop into the
debugger as soon as the infolog is
generated. You can then look at the stack
trace in the debugger to see where the code is that
generated the message.
Run Tools/Development
tools/Label/Label editor and search
for the text of the message. Select
the Label ID of the message, then
click Used by to see where that
message is used in the system.
There is also http://www.axassist.com/ which extends intellisense and many other extensions
What these guys said already is very interesting and helpful.
I'd like to add that within AX in real life you are probably working with multiple contexts. e.g. Code running in the client, code running in server, code running in p-code and in IL, COM integrations, Enterprise portal and so on.
My point is, if you want to figure something out through debugging, you must first understand where the code(s) you'd like to debug is running.
Knowing that is important because you might have to allow debugging or give permissions in multiple places.
Examples:
Windows AD debugging users (add yourself)
Allow debugging on client
Allow it on server
Disable IL if you want to use MorphX, otherwise attach the process in VS.
Allow World Wide Web Publishing Service to interact with desktop for EP.
One last thing, you are starting to work with ax right now, perhaps you will need to work with AX7(Dynamics 365 for Operations). This version of the system works only with visual studio. It is still x++, but you have a lot of the things VS provides you.
Take a look on EditorScripts Class,On AX Editor you can use it by right click and choose "Scripts". It is a kind of intellisense that can make by your self, for example: here is my in-line comment whenever I type "mycom" and press "tab"
public void template_flow_mycom(Editor editor)
{
xppSource xppSource = new xppSource(editor.columnNo());
int currentline = editor.currentLineNo();
int currentcol = editor.columnNo();
Source template = "//Partner comment "+date2str(today(),123,2,1,3,1,4, DateFlags::FormatAll )+" at "+time2str(timenow(), 1, 1)+" by MAX - Begin\n";
template+=strRep(" ", currentcol)+ "\n";
template+=strRep(" ", currentcol)+ "//Partner comment "+date2str(today(),123,2,1,3,1,4, DateFlags::FormatAll )+" at "+time2str(timenow(), 1, 1)+" by MAX - End\n";
editor.insertLines(template);
//move cursor to the empty line between the comments
editor.gotoLine(currentline+2);
editor.gotoCol(currentcol+4);
}