• Home >>  Java >>  Programming Tips
  • another use of seh


  • Rating : Excellent[0]   Very Good[0]   Average[0]   Below Average[0]   Poor[0]
  • Pub Date: 10/14/2008
  • admin [ View Profile ]

  • Abstract
  • Suppose you have written a function with a specific set of parameters. However, this function is designed in such a way that sometimes it needs more parameters. What does that mean? Wait, I'll explain.If this function is called by your own functions, which in turn are also called by your functions and so on, then you can simply supply all possible parameters to all functions from which our "problematic" function can ever be ca......

  • Introduction
  •  Sponsored Links
  • introduction

    suppose you have written a function with a specific set of parameters. however, this function is designed in such a way that sometimes it needs more parameters. what does that mean? wait, i'll explain.

    if this function is called by your own functions, which in turn are also called by your functions and so on, then you can simply supply all possible parameters to all functions from which our "problematic" function can ever be called. thus our function will always receive all the parameters it may ever need. but the disadvantage of this solution is that you have to supply all possible parameters to every function in the chain. this takes more stack, and makes the program totally unreadable. and also, you have to modify dozens of your code to add one single parameter to a single function, because you'll have to add it to all your functions.

    there can also be another situation, where your function is called from within another function, which is not yours. in fact - your function is a callback function with a predefined set of parameters, which can't be changed. well, usually in such situations, smart design always allows you to specify at least one parameter to your callback function (a context), but, alas, not all designs are smart :). also, sometimes you'd like to have more parameters anyway.

    so, what can be done in such situations?

    1. use of global variables. before your function could be called, you set some values to global variables, which are accessible from anywhere. this is the most straight and stupid way. use of global variables should be avoided as much as possible. what if you call this function in more than one situation? and what if you call this function from within another pending call to the same function? and what will you do in the multi-tasking environment? well, all that can be solved, but in very ugly ways.
    2. we can improve a bit the previous solution by using tls. we won't have to bother about multi-tasking synchronization. however, it still has almost the same disadvantages. in addition, you must initialize the tls (allocate a tls index), hence your code needs a global initialization/uninitialization.
    3. and, finally, there is a way to supply a parameter to a function without the use of global variables. it uses seh (windows structured exception handling). take a look at the following sample:
    const dword exception_fetchparam_b = 0x800a0001l;
    
    void func_nested(int a)
    {
        // do some job. at some situation we realize
    
        // that we need another parameter.
    
        // let's fetch it.
    
        int b;
    
        ulong_ptr nexceptionparam = (ulong_ptr) &b;
        raiseexception(exception_fetchparam_b, 0, 1, &nexceptionparam);
    
        // by now 'b' is filled. continue our work as usual.
    
    }
    
    void func_intermediate(int a)
    {
        // do some job. at some point call nested function
    
        func_nested(a);
    }
    
    void func_top()
    {
        // at this point we have all possible parameters.
    
    
        exception_pointers* pexception;
        __try
        {
            func_intermediate(12);
        }
        __except
            (
              pexception = getexceptioninformation(),
              exception_fetchparam_b == pexception->exceptionrecord->exceptioncode ?
               (
                 assert(1 == pexception->exceptionrecord->numberparameters),
                 assert(pexception->exceptionrecord->exceptioninformation[0]),
                 *((int*) pexception->exceptionrecord->exceptioninformation[0]) = 14,
                 exception_continue_execution
               ) :
              exception_continue_search
            )
        {
            // this point must not be reached,
    
            // since we never return exception_execute_handler
    
        }
    }

    in this sample, we start from func_top, where we have all possible parameters, from there we call func_intermediate, and this function eventually calls func_nested. at some point, it realizes that it needs one more parameter. it raises a seh exception with one parameter, which is a pointer to a placeholder for a missing parameter. next, the os looks for a suitable handler for this exception. our handler detects this exception by querying its code, writes the missing parameter, and then reports to the os that the exception is dismissed by returning exception_continue_execution code.

    next, this sample can be extended to an arbitrary number of 'missing' parameters. take a look:

    dword parseexception(exception_pointers* pexception)
    {
        switch (pexception->exceptionrecord->exceptioncode)
        {
        case exception_fetchparam_b:
            assert(1 == pexception->exceptionrecord->numberparameters);
            assert(pexception->exceptionrecord->exceptioninformation[0]);
            *((int*) pexception->exceptionrecord->exceptioninformation[0]) = 14;
            return exception_continue_execution;
    
        case exception_fetchparam_c:
            assert(1 == pexception->exceptionrecord->numberparameters);
            assert(pexception->exceptionrecord->exceptioninformation[0]);
            *((int*) pexception->exceptionrecord->exceptioninformation[0]) = 16;
            return exception_continue_execution;
    
            // and so on. fill the needed parameter by querying exception code.
    
        }
        return exception_continue_search;
    }
    
    void func_top()
    {
        // at this point we have all possible parameters.
    
        __try
        {
            func_intermediate(12);
        }
        __except(parseexception(getexceptioninformation()))
        {
            // this point must not be reached,
    
            // since we never return exception_execute_handler
    
        }
    }

    performance

    it is believed that exception-handling mechanism is very slow and heavy. this is not accurate. it becomes really heavy only if the exception has been issued (handler returns exception_execute_handler). in such a case takes place so-called unwind operation, which is a rapid return from all nested scopes, during which also guarded sections are executed (__finally blocks). in our case, the exception is not issued. we just use seh mechanism to communicate between some nested point and the __except block. such a trick can be compared to a function call by its complexity.

    btw: when you call raiseexception function and your program runs under a debugger - it may write in the console something like "first-chance exception blablabla...". if you do this too frequently - the debugger can consume too much cpu for those outputs, but that doesn't mean that this method is heavy.

    where to use

    this method is very powerful. it allows you to fetch parameters in almost any place in your application from up to winmain function.

    general rule: you must be absolutely sure that the call to your function will take place in the same thread you put the __try - __except block, otherwise the exception will lead to a crash.

    another precaution: some people like to dismiss all exceptions in their code, to make buggy programs look more stable. so, if one of your nested functions uses such a dirty trick - this method won't be too useful. but i personally believe that is not a correct concept.

    there seems to be a bit weird thing when raising such an exception from within a window procedure, where the handler resides out of the getmessage -> dispatchmessage loop, or the domodal functions. it seems to work ok, but the user32 issues a page error exception (which it dismisses too).

  • RATE THIS ARTICLE :
  •  
    • Latest Comments:
      • Add a comment
      • Title:
      • Comment
      •  
    Other popular Programming Tips articles:
    • VSS: protocol handler for Visual SourceSafe

      Imagine that you could open a document in a Visual SourceSafe database with one mouse click.

    • How to use google and other tips for finding programming help

      Code Project is a wonderful resource. Certainly, my career as a developer is built on the help I got here learning MFC in late 1999. However, it's increasingly the case that a lot of the questions on our forums are easily answered by a simple google search, so I'm writing this article to explain how

    • broadcast a message to multiple instances of an application

      This application describes how to broadcast a message to multiple instance of an application using SendMessageNotify API. DetailsFollow the following steps to broadcast message :-Register the message function and get its id using RegisterWindowMessageAPI. This function will return a unique id for th

    • about rss

      Want more traffic? Searching for an easy way to distribute your news? You need an RSS news feed. Thousands of web sites today use RSS as a "what's new" mechanism to drive traffic their way. RSS provides an easy way to monitor fresh content. RSS feeds highlight new material so that you don'

    • Developing applications that always decease gracefully.

      It is always a dream for every programmer under the sun, to write programs that never smash. So this article presents some guidelines in trapping exceptions which can kill applications, and thereby ensuring the graceful exit of a program. I have included some code snippets that show how to trap exce

    • unit test utility: restoring database state after each unit test execution

      Need: Lets start with an example, suppose we are writing unit tests for following two cases: GetCustomersByIdGreaterThan() AddCustomer() Initial state of database is like We run first unit test case for GetCustomersByIdGreaterThan()[Test]public void CanGetCustomersByIdGreaterThan(){const int CUSTOME

    • complexconverter - make configuration still more flexible

      Normal|0; 0; 765; 321|2|Knoten0|2|Knoten1|0|False|Knoten2|3|Knoten4|0|False|Knoten5|0|False|Knoten6|0|False|False|True|Knoten7|2|Knoten8|0|False|Knoten9|0|False|False|90|90|90|90|2|4|01|02|03|04|4|11|12|13|14Inside ComplexConverterComplexConverter has a problem, when set up, or conversion-code is ch

    • driving or automating gui applications

      Sometimes you want or need to control (or automate the use of) an application but the application provides no automation API (command line interface or CLI, COM component, .NET API DLL, web service, etc.), so what do you do? You're left with (graphical) user interface (GUI) automation. Although, in

    • unit testing starter - vs.net 2008

      Unit Testing starter - VS.NET 2008 Hi Everybody,As you know, VS.NET 2008 comes with unit testing integrated within. To start with a testdriven approach, we need to understand how unit testing works in VS.NET 2008. Many of usmight be using already available tools / frameworks for this, viz - NUnit (M

    • cost reduced swap

      void main() { int i=10,j=20; j=i+j-(i=j); } Here the two variables are swapped in a single statement . The cost is reduced than the known swapping methods. Temporary variables are not used.addition and subtraction only.can be used for any data types and this is efficient than the normal methods.time

    About Us |Contact us |Site Map |Csharp |Visual C / C++ |Visual basic |Java |SQL |Linux / Unix |Ajax
    ©2007-2018 CodeCoolest.com. Ptolive.cn Asp.net source code All Rights Reserved.