Skip to Content
DATA prog_id(80). IF parent IS INITIAL. RAISE error_cntl_create. ENDIF. CLASS cl_gui_cfw DEFINITION LOAD. * assign prog_id to get the frontend specific control IF NOT activex IS INITIAL. prog_id = ‘SAPTextLabel.SAPTextLabelUserControl’. ELSEIF NOT javabean IS INITIAL. RAISE gui_type_not_supported. ENDIF. IF prog_id IS INITIAL. RAISE gui_type_not_supported. ENDIF. * Set the window styles of the control when style parameter was not * set with constructor call. * For more information on the styles see WIN32 SDK IF style IS INITIAL. * otherwise the control would be invisible and the mistake would be * hard to find style = cl_gui_control=>ws_visible + cl_gui_control=>ws_child + cl_gui_control=>ws_clipsiblings. ENDIF. * Create the control CALL METHOD super->constructor EXPORTING clsid = prog_id shellstyle = style parent = parent lifetime = lifetime name = name EXCEPTIONS OTHERS = 1. CALL METHOD cl_gui_cfw=>flush EXCEPTIONS cntl_system_error = 1 cntl_error = 2 OTHERS = 3. IF sy-subrc <> 0. CALL METHOD me->install_controls. MESSAGE ID ‘ZES_GENERAL’ TYPE ‘I’ NUMBER 077. RAISE error_cntl_create. ENDIF. * register instance at framework CALL METHOD cl_gui_cfw=>subscribe EXPORTING shellid = h_control-shellid ref = me EXCEPTIONS OTHERS = 1. IF sy-subrc <> 0. RAISE error_cntl_create. ENDIF. *Setting Properties* Now we are ready to set our first property – the Caption. We will just create a method in ABAP Class called SET_CAPTION that accepts a single text string. The following is the code that we use to set a property through the control framework: CALL METHOD set_property EXPORTING property = ‘Caption’ value = caption EXCEPTIONS cntl_system_error = 1 cntl_error = 2 OTHERS = 3. *Calling Methods* Not too hard so far. Now we have our InitFont Method to call. Lets create a method in our ABAP Class called SET_FONT. The following are its input parameters: image
To report this post you need to login first.

21 Comments

You must be Logged on to comment or reply to a post.

  1. Heiko Hänsel
    Hi Thomas,
    I’m trying to integrate a custom control into SAP currently. I wrote a control class in ABAP derived from CL_GUI_CONTROL representing the control. There is no problem calling methods from the control, but no I’m going on to implement event handling for the control. Thus I published an event with ID 1 from the control.
    In the ABAP class I defined the event ID and implemented the code for registering the event handler for this event.
    Now the problem is that the automation controller does not send data to the application server, if the event is raised by the control.
    I know that the event is fired by the control, because I enbedded the control into an Excel sheet for testing purposes and it worked.
    I analyzed the Automation trace and could see that the method RegisterOcxEvent is called at the automation controller successfully.

    I got the assumption that all the SAP controls got additional coding for event processing with the automation controller.

    Can u provide any hint?

    Heiko!

    (0) 
    1. Thomas Jung
      To keep things simple and get people off the ground, so to speak, I left out any event processing.  I could always follow up this weblog with a look at raising events. 

      However I think what you are looking for is the method DISPATCH in your ABAP Control Class.  This event should be inherited from CL_GUI_CONTROL.  This is the method that will be called by the SAPGui when it receives an event from the controls it is hosting. 

      You then can redefine this method and add your own code for getting event prarameters and triggering your proxy ABAP events.  The following is a code sample of a DISPATCH event I wrote for an ABAP wrapper around the Windows Media Player.

      method dispatch.
        data: oldstate type int4,
              newstate type int4,
              start    type boolean,
              readystate type int4.

      *   be sure
        if me->h_control is initial.
          raise cntl_error.
        endif.

        case eventid.
          when me->evt_endofstream.
            raise event endofstream.

          when me->evt_playstatechange.
            call method me->get_event_parameter
              exporting
                parameter_id      = 0
               importing
                 parameter         = oldstate.

            call method me->get_event_parameter
               exporting
                  parameter_id      = 1
               importing
                  parameter         = newstate.

            raise event playstatechange
                exporting
                  oldstate = oldstate
                  newstate = newstate.

          when me->evt_buffering.
            call method me->get_event_parameter
              exporting
                parameter_id      = 0
               importing
                 parameter         = start.

            raise event buffering
              exporting
                start    = start.

          when me->evt_disconnect.
            raise event disconnect.

          when me->evt_displaymodechange.
            raise event displaymodechange.

          when me->evt_error.
            raise event error.

          when me->evt_newstream.
            raise event newstream.

          when me->evt_readystatechange.
            call method me->get_event_parameter
              exporting
                parameter_id      = 0
               importing
                 parameter         = readystate.

            raise event readystatechange
               exporting
                 readystate = readystate.

          when others.
      * don’t care
        endcase.

      endmethod.

      (0) 
      1. Heiko Hänsel
        Hi Thomas,
        thank you for your quick answer and code snipped, but my problem is not the dispatch method, because this method is called after the automation controller at the frontend has send the event data to the application server. AND THATS MY PROBLEM… There is no communication between Frontend and application server, when the event is raised at the frontend. First I thougt it’s a problem in calling the SET_REGISTERED_EVENTS method, but it can’t because the control works in a VBA application.

        Did you experience something like this. What’s wrong with the control?

        Heiko!

        (0) 
        1. Thomas Jung
          Interesting…. You shouldn’t have to do anything from the ActiveX side. In the example I gave, I am calling the Microsoft Windows Media Player directly. Of course Microsoft didn’t put any special coding in there for the SAPGui. You do have to redefine the SET_REGISTERED_EVENTS as well. I can give you my code sample of this method from this example as well:

          method set_registered_events.
          data: simple_event type cntl_simple_event, “// event
          ex_event type cntl_event,”// eventid, is_shellevent
          events_ex type cntl_events. “// table

          * map simple_event into ex_event, append to events_ex
          loop at events into simple_event.
          case simple_event-eventid.
          when me->evt_endofstream.
          ex_event-eventid = me->evt_endofstream.

          ex_event-is_shellevent = ‘ ‘.
          * check for system / application event
          if simple_event-appl_event is initial.
          ex_event-is_systemevent = ‘X’.
          endif.
          append ex_event to events_ex.
          when me->evt_playstatechange.
          ex_event-eventid = me->evt_playstatechange.
          ex_event-is_shellevent = ‘ ‘.
          if simple_event-appl_event is initial.
          ex_event-is_systemevent = ‘X’.
          endif.
          append ex_event to events_ex.
          when others.
          raise illegal_event_combination.
          endcase.

          endloop.

          call method me->set_registered_events_ex
          exporting
          eventtab = events_ex
          exceptions
          cntl_error = 1
          cntl_system_error = 2
          illegal_event_combination = 3
          others = 4.

          case sy-subrc.
          when 0.
          when 1. raise cntl_error.
          when 2. raise cntl_system_error.
          when 3. raise illegal_event_combination.
          when others. raise cntl_error.
          endcase.

          registered_simple_events[] = events.

          endmethod.

          The following is also the Code that I have in my consuming ABAP program. I place this in my PBO when I create my control:
          ****Create the Windows Media Player
          create object mp3_player
          exporting
          parent = custom_container
          exceptions
          error_cntl_create = 1
          error_cntl_init = 2
          error_cntl_link = 3
          error_dp_create = 4
          gui_type_not_supported = 5
          others = 6.

          ****If we can’t create the Media Player, Free other controls and
          ****Exit with an error message.
          if sy-subrc <> 0.
          message i078.
          perform free_controls.
          leave to screen 0.
          endif.

          data: my_simple_event type cntl_simple_event.
          data: my_simple_events type cntl_simple_events.

          ****Register Media Player Events with CFW
          my_simple_event-eventid = mp3_player->evt_endofstream.
          * Specify that it’s an application event
          my_simple_event-appl_event = ”.
          append my_simple_event to my_simple_events.

          * Redefine SET_REGISTERED_EVENTS
          call method mp3_player->set_registered_events
          exporting
          events = my_simple_events
          exceptions
          illegal_event_combination = 1
          others = 2.

          ****Set Show Display = true on Media Player
          call method mp3_player->set_show_display
          exporting
          show_display = mp3_player->true.

          Hopefully one of these two code samples will help you out.

          (0) 
          1. Thomas Jung
            I just thought of something else.  Make sure that you event ID is the same in ABAP as it is in VB.  You should be able to use the Microsoft OLE/COM Object Viewer to see the internal ID assigned to your event. This is how I event IDs for the Windows Media Player.  Althought this may not be your problem since you said you definetly knew what your event id was.
            (0) 
  2. N K
    Hi Thomas,

    I don’t know whether to love you or hate you! This weblog is exactly what I have been looking for – thank you – but I cannot get the event handling to work? Could you please give me a few extra details re finding an event ID (I have read your ActiveX weblog sample as well, but finding the mouse click EventID for the .NET Textbox control is not the same?)

    I have implemented the DISPATCH method, exactly as in your example but it is not called for any events that I trigger in my control?

    I suspect the problem is that I am not sure of what the event ID is? (onClick event of Textbox?)
    Is it requisite that the ID be valid before the DISPATCH method is called?
    I thought I could just put a break point at the beginning of the DISPATCH method, register any eventid even if it does not exist, and look at the EVENTID variable to see what the ID value really is of the event that was triggered? But this does not seem to work as I cannot get my control event to trigger the DISPATCH method at all?

    I am registering the various eventids (1 to 16) as per normal:
    call method txtbox->set_registered_events
      exporting events = my_simple_events.

    Any help will be appreciated!
    Regards,
      Neil

    (0) 
    1. Thomas Jung Post author
      I am afraid that I haven’t dabbled in this particular set of development tools in quite some time now.

      What I can tell you is that it is necessary to register the correct event ID for the DISPATCH method to be called.  There are lots of events that are triggered on the frontend, many of which are fired quite frequently (such as mouse overs).  Now a round trip to the server can be rather costly in processing times.  Therefore you don’t want the client SAPGui to call back to the ABAP class on the Server unless it knows that the server application is particularly interested in the current event. This is why from ABAP you must first register the events with the client control framework before they are even returned to the Dispatch method.

      Event Ids don’t necessarily start with 1 and work their way up unfortunetely. 

      In the past I have used the OLE viewer to pull out these event ids from the control type definition.  The OLE Viewer used to be a tool delivered with Visual Studio 6 (Pre-.Net). 
      It looks like you might still be able to download it for free from microsoft at this link:
      http://www.microsoft.com/windows2000/techinfo/reskit/tools/existing/oleview-o.asp

      Hopefully that puts you on the correct path.  You might also search the internet for some alternative tools of the same type. 

      (0) 
  3. Sam Mesh
    Could you please elaborate the conditions under which some events from ActiveX inside SAPGUI could be lost and the ways to fight this?

    It seems that when SAPGUI flushes (ignores) any events when it is communicating with the SAP System.

    I’ve found the following related links so far (but they did not help in full:):
    Using Classic ActiveX Controls in the ABAP Control Framework (this article:)
    http://www.sapgenie.com/abap/controls/how.htm
    http://help.sap.com/printdocu/core/Print46c/en/data/pdf/BCCICTUT/BCCICTUT.pdf

    (0) 
    1. Thomas Jung Post author
      There is only one situation that I can think of where events can be lost – when two events can occur in parallel.  Generally when a flush occurs, the user interface is frozen (in a wait state) so that other UI elements can’t generate events. 

      The execption here is a timer control.  It fires an event that must be sent to the server via a flush reguardless of what is happening within the UI because it is time based.  Therefore if you press a button on the frontend and a flush occurs and a timer throws an event during the flush – the timer event will be lost. Afterall the ABAP session can’t handle two events simultaniously – there is no synch logic. 

      This example is based upon testing that was done back in 2004.  As a customer at a time we entered our findings in a support message to SAP. We were informed that this was the designed functionality of the Control Framework.  I have not repeated this test in the time since then.

      (0) 
      1. Sam Mesh
        Thanks for the prompt answer. BTW, how could I be notified when you reply to this my comment?

        > We were informed that this was the designed functionality of the Control Framework.
        Our system should handle external events. It is OK to queue them in our system but it is not OK to blindly send them to SAP without knowing when it is capable to handle them. Where could I find an additional information about this “designed functionality of the Control Framework”?

        (0) 
      2. Sam Mesh
        Thanks for the prompt answer. BTW, how could I be notified when you reply to this my comment?

        > We were informed that this was the designed functionality of the Control Framework.
        Our system should handle external events. It is OK to queue them in our system but it is not OK to blindly send them to SAP without knowing when it is capable to handle them. Where could I find an additional information about this “designed functionality of the Control Framework”?

        (0) 
        1. Thomas Jung Post author
          >how could I be notified when you reply to this my comment?
          As the author of the blog, I automatically receive an email with any comments.  However there isn’t really away for other to “subscribe” to the comments in such a way. You can get an RSS feed to all the comments of all blogs on SDN.

          >Where could I find an additional information about this “designed functionality of the Control Framework”?
          There really isn’t much publically available information on the Control Framework any longer. The best documentation I can point you to is from the help portal:
          http://help.sap.com/saphelp_nw2004s/helpdata/en/d2/147a36c70d2354e10000009b38f839/frameset.htm

          This isn’t really a strategic development tool positioned towards customers any longer.  With the introduction of Web Dynpro – customers are really directed toward these newer tools for custom development. 

          (0) 
  4. Juergen Witte
    Hi Thomas,

    thanks for the good explanations. We use our own Active/X Controls in Delphi for SAP for years now without problems. Now we want to switch to .NET Controls written in C#. It seems to work fine except that the SAP GUI doesn’t run the DISPATCH method for the .NET events that are “interopt” to COM. We definitely registered the right DispIDs.

    When using the same test .NET Control from other clients like a Delphi Program the events are called without any problem.

    For example we tried the following .NET component:
    http://blogs.msdn.com/jaimer/archive/2006/10/02/writing-a-.net-activex-control-for-your-sidebar-gadget_2E002E00_.aspx

    and we had to extend it with the ComRegister/Unregister methods:

            [ComRegisterFunction()]
            public static void RegisterClass(string key)
            {

                // Strip off HKEY_CLASSES_ROOT\ from the passed key as I don’t need it
                StringBuilder sb = new StringBuilder(key);
                sb.Replace(@”HKEY_CLASSES_ROOT\”, “”);

                // Open the CLSID\{guid} key for write access
                RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true);

                // And create the ‘Control’ key – this allows it to show up in
                // the ActiveX control container
                RegistryKey ctrl = k.CreateSubKey(“Control”);
                ctrl.Close();

                // Next create the CodeBase entry – needed if not string named and GACced.
                RegistryKey inprocServer32 = k.OpenSubKey(“InprocServer32”, true);
                inprocServer32.SetValue(“CodeBase”, Assembly.GetExecutingAssembly().CodeBase);
                inprocServer32.SetValue(“ThreadingModel”, “Apartment”);
                inprocServer32.Close();

                // Finally close the main key
                k.Close();

            }

            [ComUnregisterFunction()]
            public static void UnregisterClass(string key)
            {
                StringBuilder sb = new StringBuilder(key);
                sb.Replace(@”HKEY_CLASSES_ROOT\”, “”);

                // Open HKCR\CLSID\{guid} for write access
                RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true);

                // Delete the ‘Control’ key, but don’t throw an exception if it does not exist
                k.DeleteSubKey(“Control”, false);

                // Next open up InprocServer32
                RegistryKey inprocServer32 = k.OpenSubKey(“InprocServer32”, true);

                // And delete the CodeBase key, again not throwing if missing
                k.DeleteSubKey(“CodeBase”, false);

                // Finally close the main key
                k.Close();
            }

    So I really expected this to work also with SAP GUI, but it doesn’t.

    Do you have an idea if there is a trick to get the events?

    Thanks in advance,
    Juergen.

    (0) 
    1. Thomas Jung Post author
      I have to admit that it has been nearly 3 years since I have messed around with .Net Controls in the ABAP control framework.  I just haven’t had any need for the topic since coming to work for SAP (this work was all done at my previous employeer and I don’t have access to the coding any more).

      That said – we didn’t have to add any special code to trigger the DISPATCH event.  Certainly nothing like what you have described here.  We simply mapped into control events into the events of our custom control and they automatically exposed through the COM Interop – no coding involved.

      (0) 
  5. Anzar Pradityo
    Hi Thomas,

    It’s been years since you posted this blog 🙂
    Currently, I’m working on a project which involving creating .Net custom control. So, I’ve done your steps so that the control is exposed as COM object. However, I can’t the event ID for the control. I use OLE viewer as you mentioned but it seems the control is not registered as normal activeX object. And when I right-click, the ‘View Information’ is disabled.

    For the all information about SAP Control Framework, the event ID thing is the most confusing. SAP Help doesnt say anything about how to find event ID of the custom control.

    Thanks.

    Anzar

    (0) 
    1. Thomas Jung Post author
      I’m not sure what advice I can give you.  Finding the ActiveX Event IDs doesn’t have anything to do with the SAP development environement.  I used to always use the OLE Viewer.  I’m not sure why your control has this information disabled. 
      (0) 
    1. Community User
      Hi, can you show me how to create a .net events that can work with SAPGUI?
      i have create a .NET control that inherited from system.windows.forms.usercontrol but still SAPGUI cannot catch the control’s events.

      Thanks

      (0) 

Leave a Reply