Tuesday, November 1, 2011

DirectoryInfo needs an Empty()

I want to have an empty directory to save the results of some re-runnable process (e.g., one that dumps PNGs of all the controls on a form for documentation purposes).

di = New IO.DirectoryInfo("SomeDirectoryToExistAndBeEmpty")
If di.Exists Then
   For Each fi As IO.FileInfo In di.GetFiles
      fi.Delete()
  
Next
   For Each dir As IO.DirectoryInfo In di.GetDirectories
      dir.Delete(
True)
  
Next
Else
   di.Create()
End If

(in this case there are no read-only files or any special attributes since I am generating and regenerating the files myself)

Form_Load and BeginInvoke

I inherited a form that did a lot of processing during the load event and I had a problem with displaying a mostly blank form...

Private Sub Form_Load(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs)
       DrawInitialScreen() 'draw something to see
       If DataFileProvided Then ' e.g. via Args, then also do this stuff:
          Me.BeginInvoke(New MethodInvoker(AddressOf Me.Refresh)) 'this will show the screen, then
         
Me.BeginInvoke(New MethodInvoker(AddressOf OpenFile))   'this will do a lot of work
      
End If
    End If
End Sub

Using BeginInvoke allows the load event to finish, then do the Screen refresh showing something besides a lot of white space.
The second BeginInvoke allows the Refresh to finish before starting the long work of processing a data file.

Another approach would be to load the file on a worker thread and sync things up when done, but since the user can't do anything until the file is loaded a simple progress bar was sufficient here.

Another combination that appears to work that I somehow missed* before going to BeginInvoke is this:

Private Sub Form_Load(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs)
       DrawInitialScreen() 'draw something to see
       If DataFileProvided Then ' e.g. via Args, then also do this stuff:
          Me.Visible = True
          Me.Refresh
          OpenFile
       End If
    End If
End Sub

*I find it hard to believe that Refresh is not the first thing I tried.  I seem to recall it just wouldn't work with something horrible like a DoEvents.  Which was fatal in this app because the legacy code would start processing mouse-moves trying to use the data that hasn't been loaded yet.  There is also a progress meter that needs to refresh during the load (which works just fine), although there was a textbox that would not -- both on a toolstrip.  I believe the progress uses its parent control to refresh, I'll have to look at the textbox again.

Does Refresh always work?

I recall instances in the past where I couldn't succeed with Refresh, but so far I can't find an example.  I redid the project above that prompted this investigation with Refresh and it worked this time.  I don't see why it shouldn't work, here is Refresh()



Public Overridable Sub Refresh()
Me.Invalidate(True)
Me.Update
End Sub


Update is just a wrapper around UpdateWindow.  I would say Invalidate() puts a WM_PAINT in the queue for each control, then Update() scans the queue and sends the WM_PAINT to the control. From MSDN (makes it sound a little different than what I am saying but I think they are simplifying for clarity):



"The UpdateWindow function updates the client area of the specified window by sending a WM_PAINT message to the window if the window's update region is not empty. The function sends a WM_PAINT message directly to the window procedure of the specified window, bypassing the application queue. If the update region is empty, no message is sent."



Sounds good.  Under what conditions wouldn't this paint the whole form?  Maybe my previous problems were actually bad custom controls or some-other non-Windows issue and this whole entry was wasted on a non-problem.



What's old is new again




However, check this out:




http://geekswithblogs.net/NewThingsILearned/archive/2008/08/25/refresh--update-wpf-controls.aspx 

 




Also, Hide-and-see


When hiding a form and then re-showing it, e.g., Show() or Visible=True; is a Refresh needed there, too? It would seem so.

Wednesday, October 26, 2011

Form.Main is not STA thread

 

When debugging in VS2005 I get an exception if I try to open a Dialog Box.  first question is why is this WinForms app not STA??

System.Threading.ThreadStateException was unhandled
  Message="Current thread must be set to single thread apartment (STA) mode before OLE calls can be made. Ensure that your Main function has STAThreadAttribute marked on it. This exception is only raised if a debugger is attached to the process."
  Source="System.Windows.Forms"
  StackTrace:
       at System.Windows.Forms.FileDialog.RunDialog(IntPtr hWndOwner)
       at System.Windows.Forms.CommonDialog.ShowDialog(IWin32Window owner)
       at System.Windows.Forms.CommonDialog.ShowDialog()
       at TorPlugin.TorPanel.Button3_Click(Object sender, EventArgs e) in C:\Projects\OAMSIMULATOR\Inspector\plugins\TorPlugin\TorPanel.vb:line 132
       at System.Windows.Forms.Control.OnClick(EventArgs e)
       at System.Windows.Forms.Button.OnClick(EventArgs e)
       at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
       at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ButtonBase.WndProc(Message& m)
       at System.Windows.Forms.Button.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.Run(Form mainForm)
       at TorPlugin.Form1.Main() in C:\Projects\OAMSIMULATOR\Inspector\plugins\TorPlugin\Form1.vb:line 39
       at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()

?System.Threading.Thread.CurrentThread.GetApartmentState
MTA {1}

 

<STAThread()> _
Shared Sub Main()

Application.Run(New Form1())
End Sub


<STAThread()> _
Shared Sub Main()
  
Debug.Print("Sub Main is " & System.Threading.Thread.CurrentThread.GetApartmentState.ToString)
   Application.Run(New Form1())
End Sub


Sub Main is MTA


 


A bug


When running under VS2005 in debug mode using ThreadingModel.vshost.exe to launch ThreadingModel.exe, the Threading Model is supposed to be STA. It is STA, provided that there is not a ThreadingModel.dll file in the same directory as ThreadingModel.exe. If a ThreadingModel.dll file exists in the same directory. The Threading Model ends up being MTA.

This was indeed the case.  I built to bin\App where there was no TorPlugin.dll and then voila':


Sub Main is STA


 

HOWTO: Work with MOD files (WLW post 1)

IFRAME not what I expected, was hoping for something like PDF embedding
Looks like this theme isn’t going to work either.  Didn’t expected all the shrunken pictures
Scenario Two:  Developing the MODs -- working with the developer MODs.

Overall Objectives: Simple checklist of steps without the need to modify TacTrain.exe.config or other onerous manual manipulations.

Scenario Two
Description:  You intend to do development that includes modifying MOD files.  In this example, I'll add a prerequisite to one of the Hard Drives.  I'll run TacTrain to check that the prerequisite is needed, add the prerequisite, confirm it works, and then check-in the MOD files.

Concepts: 
·         A new DAT may require an updated MOD file ( specifically when deleting rows from a table)
·         There is one production MOD file named CompleteOA2.MOD that is the combination of several developer MOD files found in [C:\Projects\OAMSIMULATOR\BuildDAT\MOD Files]
·         When developing, the developer MOD file(s) will be modified
·         Developer MOD files will be combined into CompleteOA2.MOD and then all MOD files checked-in.

Using XplODer.exe in "Gadget" mode - attach to TacTrain while it is running.
XplODer will launch a gadget form with the MOD file checklist.  The gadget will interact with TacTrain to override TacTrain.exe.config to set it up for MOD file development and automate MOD-file related tasks.  The gadget form will also launch Oamy XplODer to use for making modifications.  Finally the gadget form will remove the override to TacTrain.exe.config.

This step-by-step assumes the default setup for TacTrain with regards to inspector: i.e., it is "Hidden" and is loading "CompleteOA2.MOD".  In other cases, some steps may be skipped.


clip_image002Step-by-Step
·         Run your TacTrain project, to get Oamsworld loaded: select Maintenance, OA-1, Stand-Alone Freeplay  (OA-1 just to avoid the MOD file right now).
·         Run XplODer.exe [C:\Program Files\SDSSIM Mk2\XplODer.exe], Select the MODs tab and resize to  see checklist
(Short Version, Just follow six steps on MOD tab, below)
clip_image004
·         NOTE: Checking the boxes on this checklist CAUSE settings to change or other things to happen, it is NOT just a box to fill in to show you've completed a step (i.e. checking the box executes a step or a portion of it).  Clicking an already checked box will cause it to re-execute it function.
1.       This will make sure XplODer appears for developing, even if you restart TacTrain.
(Step #'s will correspond to check boxes in image above)
a.       Load OA-1 if you didn't already, going to Cabinet View is sufficient.
b.      Check the Box.  Since TacTrain was running first, an Oamy XplODer form should have appeared already. ( The instructions for Box 1 assumes the Gadget was running first and is waiting for you to start TacTrain.) 
c.       EXIT back to TacTrain Front-End.
2.       This prepares TacTrain to use the developer MODs.
a.       Check the box.
b.      Load OA-2 and start making modifications
c.       I will add a prerequisite to the TDP Harddrive, so I'm going to go to the Modifications tab and select  "Q70_OM2_v2_TDP_SDP_VME7809_CCA.MOD" to hint to XplODer that I want to add to this file.
d.      Now I'll use XplODer to add the Prerequisite, it will be added to "Q70_OM2_v2_TDP_SDP_VME7809_CCA.MOD"

2c. The Modifications tab shows that the Developer MODs are in use and Q70_OM2_v2_TDP_SDP_VME7809_CCA.MOD  has been selectectclip_image006

The hard drive -- find the oamys.
I have no idea what the name of the harddrive is nor any good starting point to browse to it so I'll just type in "hard" in the Find box to search for it.
Pressing "enter" displays the results where I see "HardDrivePhysicalLRU" and "SDPHardDrivePhysicalLRU" where I can find the drives I'm interested in.
I click on HDD#2 so I can copy the name for the PrereqObjectState, then I go and right-click on HDD#1 to add a prerequisite (see context menu in image below).
clip_image007

For most modifications, you just make the change and it is recorded, but adding a prereq takes some extra steps to fill out what is essentially a placeholder -- so I'll click on the last item in the modifications list box, it is the new prereq with a few fields filled in and some empty.
I'll paste in the PrereqObjectName and then select the states from the drop-down:
clip_image008

Since this was a placeholder, this modification hasn't happened yet -- I can manually execute it now:
clip_image009

Now, I can go to the console room and verify that I can't put HDD#1 back in the slot if the HDD#2 is there.
I can also check the data tables:
clip_image011
clip_image013

Note: I can exit back to VS2005, close the project and pick up the next day and still be in MOD developer mode -- the settings stick.  I could re-open the Gadget form and pick up the checklist where I left off (the boxes would all be unchecked, though) and/or  I can just change the settings using the Options | MODs menu just like in Scenario One HOWTO.

back to the checklist...
3.       Save the combined MODs. 
a.       Everything checks out, so I'm going to exit back out to give the MOD files a chance to run one more time.  If you were doing SQL or using data-tables or something else you would probably need to rake here to get everything in its final data-table order.
b.      Now, or earlier during development you may have got the "Mod updated itself" message, you should be saying "yes" during the development phase, do so now if you need to. (see image 3b.)
c.       VSS -- Check out CompleteOA2.MOD
d.      Check the box to combine and save. (see image 3d.)
e.      VSS -- Check in CompleteOA2.MOD (plus any Developer MODs).

Fig. 3b. save auto-updated files (say "Yes")clip_image014

Fig. 3d. Combine and Save (just hit "OK")
clip_image016

4.       (Optional) You could run it one more time using the single combined MOD.  Just follow the instructions in Check box item 4.
5.       Check the box to remove XplODer override (e.g., back to "hidden")
6.       Check the box to remove mod file override (e.g., developer MODs).  TacTrain should now be back to normal, e.g., determined by TacTrain.exe.config

Done
So far you've configured TacTrain to use the developer MODs and show XplODer for runtime inspection and editing, made the changes and then put everything back to "normal".  The checklist includes VSS so there is nothing left to do for this process.

Other considerations
MessageBox at startup: The step-by-step has you start Tactrain first, but if you started XplODer first and Tactrain.vshost.exe is detected, you will be prompted:
clip_image017
For this scenario, select "Yes" to launch the Inspection Gadget and wait for TacTrain to start.
The gadget can stay open to be re-used whenever TacTrain is running.

TacTrain.exe:  The same checklist is used whether in the VS2005 environment or not -- you do not need to be debugging.
(TacTrain.exe and TacTrain.vshost.exe are separate EXEs and will have their own settings.)


Embed Test

Going to try Live Writer a bit later (what is this Times? Ugh!)
Ok, here's the embed (looks like my font got bigger too)



How to in IFRAME above