Menu

Windows programs that actively do something

Dan Senior
2009-10-22
2012-09-26
  • Dan Senior

    Dan Senior - 2009-10-22

    This may be a simple question..

    I want to make a program that runs in Windows using dialog boxes and such, but
    unlike applications like calculator that sit and wait for you to do something,
    I want something more like media player that plays but still lets you use the
    controls.

    The getmessage function doesn't move on until it gets a message, so I can't
    use that standard pump if I want to make a program that is actively doing
    something in the background.

    Do I need to make a multi-thread program where one thread handles the window
    elements and one thread runs the program?

    What my program will do is monitor a certain directory and when there are
    files added to the directory, it will process them and send them key by key to
    an external system. But while it is doing that I want to be able to have watch
    windows, menus, etc.

    What are your thoughts?

    -Dan

     
  • cpns

    cpns - 2009-10-23

    I can think of three solutions; two of them general, and one specific to your
    particular problem (and probably the best solution in this case).

    The general solutions are:

    1) Create a worker thread to perform the activity concurrently to the message
    handling procedure.

    2) Use a timer to periodically sent WM_TIMER messages to your message handling
    procedure and do a 'bit of work' on each event. In this case simply check the
    folder you are monitoring.

    Method 1 is a bit heavyweight for this particular task, where method 2 would
    be more appropriate. However there is another method which is probably better
    still. The operating system can watch for file system events for you and send
    messages to your message handler when they occur. This is how tools such as
    Google Desktop work - only indexing files when they change. In .NET this is
    easily achieved using the . I am sure I have seen this done in plain Win32,
    but cannot immediately find the appropriate API.

    Clifford

    : http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher%28VS.80
    %29.aspx

     
  • Dan Senior

    Dan Senior - 2009-10-28

    Thank you, that's pretty much what I was thinking was either a concurrent
    thread or a timer... I was just hoping maybe there is some sort of an
    alternate command to getmessage that instead of waiting would fall through and
    let me do other things. However, if theoretically there was something like
    that, I would still have to break the program down into little pieces and have
    it do a small portion and come back to check the message queue again,
    otherwise the window controls would lag considerably. Therefore, in theory a
    timer is pretty much the same thing, just perhaps not quite as tight because
    depending on how long I go between calls, there could be unused time. I'll
    play with it, until I have a program complicated enough to need a worker
    thread and then I will see how that works.

    Interesting to think about just how many programs in Windows really do just
    sit and wait... it was hard for me to think of an example of a program that
    doesn't.

    As far as checking for the file, I will do some research and see if I can find
    something I can use in Dev, or I can just have part of the timer loop be
    looking... I will still need a timer either way because once the file is found
    and it begins the process of processing and exporting, it could be a lengthy
    process so I would still need the system to be able to do the window calls as
    well. Eventually, I want to be able to do COM support in and out and plug-ins
    too so I'll take it all into consideration.

    -Dan

     
  • cpns

    cpns - 2009-10-29

    Having GetMesage() fall through detrimentally would affect the performance of
    other programs running on your machine by hogging a large number of CPU
    cycles. In old 16 bit versions of Windows that used cooperative multi-tasking,
    it would haveground everything else to a halt by taking all cycles outside
    of interrupt handlers. Even with pre-emptive multi-tasking, the Windows
    scheduler expects applications to behave responsibly, and continuously using
    all the available time-slice will affect other processes that might otherwise
    run.

    However, should wou wish to do that it is easily done. You can call , and then
    only call GetMessage() to clear the queue is there is a message available;
    this effecting a non-blocking message handler.

    It is a rather inelegant solution however. Threads are not difficult to use
    (although again much simpler in .NET - the Win32 API suffers from the weight
    of its legacy, and the fact that it is not object oriented).

    Clifford

    : http://msdn.microsoft.com/en-
    us/library/ms644943%28VS.85%29.aspx

     
  • Dan Senior

    Dan Senior - 2009-10-29

    Thanks... I am concerned about not hogging all the CPU's resources, I do want
    my programs to "play nice" so I'll keep that in mind, if there comes
    a critical part that has to be done with tight timing, I suppose I could try
    the peekmessage command, but then again if it is that critical of an operation
    I probably don't need to worry about menus and windows, etc. because the
    operation itself would be more important.

    I was hoping even doing a timer wouldn't tie up my computer too much, if I did
    it for every half a second or something. I haven't tried it yet, I am still
    planning. I will probably use multi-threading when all the pieces come
    together... start with a timer and then as I add pieces I will change the
    timer to a thread and have flags, like a state machine, to coordinate all the
    pieces. Then when I add COM support (I want to be able to query the status of
    my program from VBA, because the majority of the files to process will come
    from Excel), that will probably be its own thread as well.

    I am just used to programming DOS-style, where I get to control everything...
    but I have to let go a little and let Windows help me.

    Now I see all my options on the table, I can play around a bit.

    -Dan

     
  • cpns

    cpns - 2009-10-29

    Even very rapid timer event messages (say 50 to 100 per second) would not in
    themselves trouble a modern CPU, it is rather how much work you do in each
    event that would be critical. For example is you had a timer event every 100ms
    and the processing took 90ms, that would be 90% of the CPU dedicated to your
    task. If you are watching for file or folder changes the polling rate would be
    determined entirely on how soon after such an event you need your program to
    react.

    Either way, the Windows Task Manager will tell you teh total CPU load and teh
    specific load for individual processes. Use that to check the behaviour of
    your program. On the processes list you can add all sorts of additional
    metrics for display too.

     
  • Dan Senior

    Dan Senior - 2009-11-05

    Thinking about the process, I think a timer is the best way to go for now, I
    just have to alter the way I was going to structure my program. With threads,
    I have to worry about routines being threadsafe, and working with mutexes and
    making sure I have a big enough heap... that's a lot of issues to deal with
    that a timer does not have.

    That sounds manageable. It wouldn't be too hard for me to time each loop and
    keep some sort of statistic of average cycle time so I could adjust the
    timer... maybe even have some sort of dynamic process to self-adjust or to run
    more or less code depending on how fast it is running. As you say, I just need
    to monitor the percentage of time my routine is spending, try to keep below a
    certain percent so the rest of the system can run well.

    I am not really asking a question now, but since I know other people read
    these I will go ahead and present a small outline of what I came up with to
    make it work.

    The program is a data feeding program to automate tasks in an AS/400 system.
    (The primary use will be to feed lists of data, but it will contain a
    scripting protocol as well which could lead to other types of tasks.) It will
    replace a process I have been using Visual Basic in Excel to do, thereby
    freeing my Excel application to be able to do other things while the program
    processes the data and also making it easier for me to simplify tasks I do so
    I can delegate to others when I need to.

    The data will come from files placed into a queue. There will be multiple ways
    to add files to the queue, and options such as file priority and what time the
    file should process... what's important at this level is that either we are
    processing a file or we are not. I will have a separate routine to manage the
    queue, under a combination of window control events and a slice of the timer
    routine (or its own timer) to do quick monitoring every minute or so.

    Anyway, with the main loop on the timer, I think of it as if I am building an
    underwater project and I don't have oxygen... as soon as I am in the water I
    have a very short amount of time to do one task and come back up for air.

    Since I want to play nice with the system, the first thing I will do is see if
    I am processing a file or not... if I am not, I will check the status of the
    queue to see if it is time to start processing another file. If not, I leave.
    Let the other running programs have the advantage.

    Then, I am processing so I am in the main loop. At this point, if there will
    be multiple steps, I could break them up into step 1, 2, 3, etc. and use a
    switch statement and a counter so on each time into the loop it will go
    directly to the part of the program it needs to be in.

    Since I am dealing with an external system, sometimes it will be busy and I
    can't send out data. If I were programming straight, using a thread or a
    console program, I would just have the program wait. But since I am on a timer
    and I don't want to make all of my applications stop and wait for the AS/400,
    if the AS/400 can't take input at this time I will continue to process the
    file and put the future keystrokes into a buffer. (So I will have three
    tasks... 1. if the AS/400 is available, send a line from the buffer. 2.
    process the file a line at a time, and 3. do what the line wants to do. Then
    exit the routine.)

    If I come to where I need to read the AS/400 (either the status or something
    on the screen), or make a decision (the files can be straight data or a
    scripting language I am developing which will allow for input and decision-
    making), it will stop queuing the buffer and stop processing the file and keep
    feeding the buffer into the system until it is empty, then resume with the
    processing, meaning once the buffer is empty, it is caught up, then it can
    take a snapshot of the as/400's state or read the screen or make the decision.

    If I break the program into tasks, say task 1 is handle the buffer, task 2 is
    parse a line from the file, task 3 is execute the line, then I can use a
    select switch to control the steps. I can take a timer reading when I enter
    the routine, then check at the end of each task how much time I have left
    until I need to bail from the routine, and decide if I should run the next
    step or not. If I do bail, when it gets back it can branch to that step and
    continue.

    In that way, I can have the program actively processing and sending data and
    yielding to the system if the system is being slow... but also still have
    access to my menus, watch screens, etc. (Another reason I am writing this code
    is that it will track a number of things as it goes along and be able to show
    status logs and track errors and have options such as taking snapshots of the
    system after each line is transmitted or at specified points so when there is
    an error it can show the last five screens for debugging purposes, etc.)

    It should be a nice application to have... unfortunately company policy states
    that if I make it on their time with their equipment it is theirs, so I will
    be able to share it within the company but not beyond that. But I know it will
    get use.

     
  • Dan Senior

    Dan Senior - 2009-11-05

    Anyway, my point about programming timers as a method of having active modules
    on top of windowing framework is:

    1. If you don't have anything to do, get out as soon as possible,

    2. Make the process as simple as possible, and

    3. if you need to do multiple things, you can break the process into pieces and do one piece on each loop, by using a switch statement and a counter.

    Think of it as being underwater and coming up for air every so often.

     
  • cpns

    cpns - 2009-11-06

    I am not sure why you need to worry about a 'big enough heap' when using
    threads; that is the responsibility of the operating system. Thread safety is
    only an issue when threads share data or resources, or non-reentrant
    functions. The 'contact points' are usually easy to spot, and IPC rather than
    shared memory is a safer method of thread communication.

    That said, I agree a timer is the obvious way to go. I think you are making it
    far more complex than it is however, checking for a file system change as you
    suggested is trivial, you should probably just set the time to match the
    response-time you require from the system and be done with it. If it does not
    achieve that then you are screwed in any case. Remember on-time is good
    enough, ahead-of-time is no advantage.

     
  • Dan Senior

    Dan Senior - 2009-11-06

    I actually had this somewhat a long reply but I cut it down a bit, it's not
    really important you know my programming experience or why I want to use Dev
    C++ or why I will probably end up using VC++ or what else I still need to
    research... none of that is relevant in a discussion about timer based
    multitasking. So if I need to say those things later I will but right now I
    will just delete those sections and make this an easier read.

    Checking for a file on the queue is the easy part, I won't go over that more
    because it's not my main concern. That will be in and out, no problem.

    My concern is that once I am actually processing the file, if I am processing
    a large file (say 10,000 records), and parsing a script where it might take
    five or six commands before it has the data to send (of course that is on the
    script programmer as well), and there's going to be pockets of time between
    calls, I want to take advantage of the as/400's wait state so when it is ready
    I am ready. That is a variable amount of time, so I think a buffer will be ok.
    Ultimately I am trying to shave down the amount of time the AS/400 has to run,
    so I think pre-processing might help if the AS/400 is waiting and I have
    processing to do before I can send data anyway.

    But the issue I think is being pointed out is trying to do three things in one
    timer cycle and using variable timers (either changing how often I call or how
    much I do in each loop). As I was thinking about this reply I came to the
    realization that you are right.

    The way I see it, there are two choices here:

    1. Jump into the routine more often and do less each time, or

    2. Jump into the routine less often and do more.

    I was thinking option 2 but option 1 is better for Windows and still gets the
    same thing done, just maybe a little differently.

    Either way, I will want to break my routine into steps and use a counter and a
    switch statement to control what part of the program I am in on each entry to
    the routine. I think that is a fast and easy way to do it. I can even use
    constants like Send Buffer = 1, Parse = 2, Action = 3 to make the code more
    readable and understandable. (Of course comments don't hurt either. And having
    constants or not, either way, if I add a step between, I have to change the
    numbers.)

    It's possible I may need to break down the parsing step into sub-steps, if
    it's a complicated line and it will obviously take a while to parse, that will
    have to be a multiple number of cycles.

    For example, if I have a command such as !1500, which will just send out the
    number "1500" to be entered in, that will be a very simple parse, just take
    the text and put it in the buffer.

    However, if I have a command such as set a, (b*(c+5+(d/e))-f)+g, which will
    evaluate the equation and put into variable A, that is going to take a lot of
    time to process (if we are talking milliseconds), because it has to pull the
    values of each variable, and evaluate the equation a level at a time. But if
    each level is a cycle, that should be ok, thinking small... and it will just
    be a given that having long formulas will slow down the process but at least
    it won't negatively affect the other programs. And actually, the way I already
    have the expression parser written in VBA (which I am converting now), it
    already uses a loop so it won't be that hard to say a loop is a timer cycle.

    Thinking that what I have been using is VBA, and what the team I would share
    this with has been using is VB Script that has been using COM technology to
    read and parse an Excel file, I guess even doing one step each loop (or one
    step over three or four loops) and taking the chance that there could be
    unused pockets of time, would still be miles faster than we have been having.

    Really, when I think about it, if I use threading, the Windows scheduler is
    going to break it down into small chunks anyway and run each part a bit at a
    time on its own, and it probably won't be truly continuously running, it will
    have gaps between as well. By using a timer, I am basically just replacing the
    scheduler and making my own.

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.