{"id":1373,"date":"2012-06-18T17:16:01","date_gmt":"2012-06-18T22:16:01","guid":{"rendered":"http:\/\/anvil-of-time.com\/wordpress\/?p=1373"},"modified":"2021-03-11T12:24:52","modified_gmt":"2021-03-11T17:24:52","slug":"powerbuilder-using-c-visual-objects-in-pb-classic-applications","status":"publish","type":"post","link":"https:\/\/anvil-of-time.com\/powerbuilder\/powerbuilder-using-c-visual-objects-in-pb-classic-applications\/","title":{"rendered":"PowerBuilder &#8211; Using C# Visual Objects in PB Classic Applications"},"content":{"rendered":"<p>This article will explain how to build a COM visual component in C# using Visual Studio 2010; it is an extension of my earlier example of using the Interop Forms Toolkit to build a Visual Basic COM object.<\/p>\n<p>First you need to install the Microsoft Interop Toolkit (<a href=\"http:\/\/msdn.microsoft.com\/en-us\/vstudio\/bb419144.aspx\" target=\"_blank\" rel=\"noopener\">available here<\/a>).<br \/>\nThen download the <a href=\"http:\/\/www.codeproject.com\/Articles\/15690\/VB6-C-Interop-Form-Toolkit\" target=\"_blank\" rel=\"noopener\">C# Interop Form Toolkit<\/a> by Leon Langleyben from Codeproject. Installation of this is primarily copying files to the appropriate places based on your Visual Studio install (instructions are provided in Leon&#8217;s article).<\/p>\n<p>Begin by creating a new project (Visual C#) with the &#8216;VB6 Interop UserControl&#8217; Template.<br \/>\n<a href=\"http:\/\/anvil-of-time.com\/wordpress\/wp-content\/uploads\/2012\/06\/csharp01.png\"><img loading=\"lazy\" class=\"aligncenter wp-image-1391 size-full\" title=\"csharp01\" src=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp01.png\" alt=\"\" width=\"710\" height=\"623\" srcset=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp01.png 710w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp01-300x263.png 300w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp01-150x131.png 150w\" sizes=\"(max-width: 710px) 100vw, 710px\" \/><\/a><br \/>\nGive the project a meaningful name, &#8216;IOPCsharpexample&#8217; is my choice.<br \/>\n<a href=\"http:\/\/anvil-of-time.com\/wordpress\/wp-content\/uploads\/2012\/06\/csharp02.png\"><img loading=\"lazy\" class=\"aligncenter wp-image-1393 size-full\" title=\"csharp02\" src=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp02.png\" alt=\"\" width=\"716\" height=\"615\" srcset=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp02.png 716w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp02-300x257.png 300w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp02-150x128.png 150w\" sizes=\"(max-width: 716px) 100vw, 716px\" \/><\/a><br \/>\nVisual Studio creates the Solution with a variety of files\/references. All of the code will be done in the InteropUserControl.cs file.<br \/>\n<a href=\"http:\/\/anvil-of-time.com\/wordpress\/wp-content\/uploads\/2012\/06\/csharp03.png\"><img loading=\"lazy\" class=\"aligncenter wp-image-1395 size-full\" title=\"csharp03\" src=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp03.png\" alt=\"\" width=\"291\" height=\"234\" srcset=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp03.png 291w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp03-150x120.png 150w\" sizes=\"(max-width: 291px) 100vw, 291px\" \/><\/a><\/p>\n<p>Opening the InteropUserControl.cs file (right click on the item in the Solution Explorer and choose &#8216;View Code&#8217;) gives this.<br \/>\n<a href=\"http:\/\/anvil-of-time.com\/wordpress\/wp-content\/uploads\/2012\/06\/csharp000.png\"><img loading=\"lazy\" class=\"aligncenter wp-image-1389 size-full\" title=\"csharp000\" src=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp000.png\" alt=\"\" width=\"777\" height=\"412\" srcset=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp000.png 777w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp000-300x159.png 300w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp000-150x79.png 150w\" sizes=\"(max-width: 777px) 100vw, 777px\" \/><\/a><\/p>\n<p>Clicking on the plus to the left of &#8216;Interfaces&#8217; expands that code section.<br \/>\n<a href=\"http:\/\/anvil-of-time.com\/wordpress\/wp-content\/uploads\/2012\/06\/csharp001.png\"><img loading=\"lazy\" class=\"aligncenter wp-image-1390 size-full\" title=\"csharp001\" src=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp001.png\" alt=\"\" width=\"823\" height=\"521\" srcset=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp001.png 823w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp001-300x189.png 300w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp001-150x94.png 150w\" sizes=\"(max-width: 823px) 100vw, 823px\" \/><\/a><\/p>\n<p>Note that there are two <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/87d83y5b(v=vs.80).aspx\" target=\"_blank\" rel=\"noopener\">interface definitions<\/a>, one for events and another for properties (and methods). This is one place we need to add to in order to expose the control within Powerscript.<\/p>\n<p>To build the actual control, open the Designer window for the InteropUserControl.cs file (right click and choose &#8216;View Designer&#8217;.<br \/>\n<a href=\"http:\/\/anvil-of-time.com\/wordpress\/wp-content\/uploads\/2012\/06\/csharp002.png\"><img loading=\"lazy\" class=\"aligncenter wp-image-1392 size-full\" title=\"csharp002\" src=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp002.png\" alt=\"\" width=\"331\" height=\"283\" srcset=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp002.png 331w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp002-300x256.png 300w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp002-150x128.png 150w\" sizes=\"(max-width: 331px) 100vw, 331px\" \/><\/a><br \/>\nThis gives you the layout of the user control itself.<br \/>\n<a href=\"http:\/\/anvil-of-time.com\/wordpress\/wp-content\/uploads\/2012\/06\/csharp003.png\"><img loading=\"lazy\" class=\"aligncenter wp-image-1394 size-full\" title=\"csharp003\" src=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp003.png\" alt=\"\" width=\"196\" height=\"224\" srcset=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp003.png 196w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp003-131x150.png 131w\" sizes=\"(max-width: 196px) 100vw, 196px\" \/><\/a><br \/>\nAdd a trackbar control from the Tools window.<br \/>\n<a href=\"http:\/\/anvil-of-time.com\/wordpress\/wp-content\/uploads\/2012\/06\/csharp004.png\"><img loading=\"lazy\" class=\"aligncenter wp-image-1375 size-full\" title=\"csharp004\" src=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp004.png\" alt=\"\" width=\"375\" height=\"149\" srcset=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp004.png 375w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp004-300x119.png 300w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp004-150x59.png 150w\" sizes=\"(max-width: 375px) 100vw, 375px\" \/><\/a><br \/>\nChange some of the trackbar attributes in the Properties display.<br \/>\n<a href=\"http:\/\/anvil-of-time.com\/wordpress\/wp-content\/uploads\/2012\/06\/csharp005.png\"><img loading=\"lazy\" class=\"aligncenter wp-image-1376 size-full\" title=\"csharp005\" src=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp005.png\" alt=\"\" width=\"315\" height=\"292\" srcset=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp005.png 315w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp005-300x278.png 300w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp005-150x139.png 150w\" sizes=\"(max-width: 315px) 100vw, 315px\" \/><\/a><br \/>\nThe changes from the default are Name &#8211; TB1, Backcolor &#8211; Yellow, Orientation &#8211; Vertical, TickFrequency &#8211; 10, TickStyle &#8211; Both, Maximum &#8211; 100, and Margin &#8211; 0,0,0,0. Unlike the VB control I demonstrated before, this is a vertical trackbar without any label to display its current value.<br \/>\n<a href=\"http:\/\/anvil-of-time.com\/wordpress\/wp-content\/uploads\/2012\/06\/csharp006.png\"><img loading=\"lazy\" class=\"aligncenter wp-image-1377 size-full\" title=\"csharp006\" src=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp006.png\" alt=\"\" width=\"313\" height=\"532\" srcset=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp006.png 313w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp006-176x300.png 176w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp006-88x150.png 88w\" sizes=\"(max-width: 313px) 100vw, 313px\" \/><\/a><br \/>\nOn the properties view for the trackbar TB1, click on the Events button. This shows a list of the defined events for the control. Double click on the ValueChanged event. This will add a stub for the event on the code page.<br \/>\n<a href=\"http:\/\/anvil-of-time.com\/wordpress\/wp-content\/uploads\/2012\/06\/csharp007.png\"><img loading=\"lazy\" class=\"aligncenter wp-image-1378 size-full\" title=\"csharp007\" src=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp007.png\" alt=\"\" width=\"737\" height=\"542\" srcset=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp007.png 737w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp007-300x220.png 300w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp007-150x110.png 150w\" sizes=\"(max-width: 737px) 100vw, 737px\" \/><\/a><br \/>\nHowever, we must also add an initialization for an event handler to the event within the objects declaration so that it will be exposed.<\/p>\n<p>Use the same steps to expose the Scroll event on the trackbar. Once finished you can see the events created in bold on the Properties window.<br \/>\n<a href=\"http:\/\/anvil-of-time.com\/wordpress\/wp-content\/uploads\/2012\/06\/csharp008.png\"><img loading=\"lazy\" class=\"aligncenter wp-image-1379 size-full\" title=\"csharp008\" src=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp008.png\" alt=\"\" width=\"307\" height=\"299\" srcset=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp008.png 307w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp008-300x292.png 300w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp008-150x146.png 150w\" sizes=\"(max-width: 307px) 100vw, 307px\" \/><\/a><\/p>\n<p>Now to complete the C# code refer to the following:<\/p>\n<pre name=\"code\" class=\"VB\">using System.ComponentModel;\nusing System.Runtime.InteropServices;\nusing Microsoft.VisualBasic;\nusing System.Windows.Forms;\nusing System.Security.Permissions;\nusing System.Drawing;\n\nnamespace IOPCsharpexample\n{\n\n    #region Interfaces\n\n    [ComVisible(true), Guid(InteropUserControl.EventsId), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]\n    public interface __InteropUserControl\n    {\n        [DispId(1)]\n        void Click();\n        [DispId(2)]\n        void DblClick();\n        \/\/add additional events visible in VB6\n        \/\/ these events exposed and shown in PB event list\n        [DispId(3)]\n        void tbScroll();\n        [DispId(4)]\n        void tbValuechanged();\n    }\n\n    [Guid(InteropUserControl.InterfaceId), ComVisible(true)]\n    public interface _InteropUserControl\n    {\n        [DispId(1)]\n        bool Visible { [DispId(1)] get; [DispId(1)] set; }\n        [DispId(2)]\n        bool Enabled { [DispId(2)] get; [DispId(2)] set; }\n        [DispId(3)]\n        int ForegroundColor { [DispId(3)] get; [DispId(3)] set; }\n        [DispId(4)]\n        int BackgroundColor { [DispId(4)] get; [DispId(4)] set; }\n        [DispId(5)]\n        Image BackgroundImage { [DispId(5)] get; [DispId(5)] set; }\n        [DispId(6)]\n        void Refresh();\n        \/\/add additional properties visible in VB6\n        \/\/ PB can call these\n        [DispId(7)]\n        void tbsetbackcolor(int testval);\n        [DispId(8)]\n        int tb1backgroundcolor { [DispId(8)] get; [DispId(8)] set; }\n        [DispId(9)]\n        int tb1value { [DispId(9)] get; [DispId(9)] set; }\n    }\n    #endregion\n\n    [Guid(InteropUserControl.ClassId), ClassInterface(ClassInterfaceType.None)]\n    [ComSourceInterfaces(&quot;IOPCsharpexample.__InteropUserControl&quot;)]\n    [ComClass(InteropUserControl.ClassId, InteropUserControl.InterfaceId, InteropUserControl.EventsId)]\n    public partial class InteropUserControl : UserControl, _InteropUserControl\n    {\n        #region VB6 Interop Code\n\n#if COM_INTEROP_ENABLED\n\n        #region &quot;COM Registration&quot;\n\n        \/\/These  GUIDs provide the COM identity for this class \n        \/\/and its COM interfaces. If you change them, existing \n        \/\/clients will no longer be able to access the class.\n\n        public const string ClassId = &quot;e7c6c97a-af38-4d57-9980-9edd60e1b45c&quot;;\n        public const string InterfaceId = &quot;2aab63cc-a9df-4197-89f4-44150a746301&quot;;\n        public const string EventsId = &quot;1eeca2b9-97ac-4c1c-8dc1-770c941c8ebd&quot;;\n\n        \/\/These routines perform the additional COM registration needed by ActiveX controls\n        [EditorBrowsable(EditorBrowsableState.Never)]\n        [ComRegisterFunction]\n        private static void Register(System.Type t)\n        {\n            ComRegistration.RegisterControl(t);\n        }\n\n        [EditorBrowsable(EditorBrowsableState.Never)]\n        [ComUnregisterFunction]\n        private static void Unregister(System.Type t)\n        {\n            ComRegistration.UnregisterControl(t);\n        }\n\n\n        #endregion\n\n        #region &quot;VB6 Events&quot;\n\n        \/\/This section shows some examples of exposing a UserControl&#039;s events to VB6.  Typically, you just\n        \/\/1) Declare the event as you want it to be shown in VB6\n        \/\/2) Raise the event in the appropriate UserControl event.\n        public delegate void ClickEventHandler();\n        public delegate void DblClickEventHandler();\n        public new event ClickEventHandler Click; \/\/Event must be marked as new since .NET UserControls have the same name.\n        public event DblClickEventHandler DblClick;\n\n        private void InteropUserControl_Click(object sender, System.EventArgs e)\n        {\n            if (null != Click)\n                Click();\n        }\n\n        private void InteropUserControl_DblClick(object sender, System.EventArgs e)\n        {\n            if (null != DblClick)\n                DblClick();\n        }\n\n\n        #endregion\n\n        #region &quot;VB6 Properties&quot;\n\n        \/\/The following are examples of how to expose typical form properties to VB6.  \n        \/\/You can also use these as examples on how to add additional properties.\n\n        \/\/Must Shadow this property as it exists in Windows.Forms and is not overridable\n        public new bool Visible\n        {\n            get { return base.Visible; }\n            set { base.Visible = value; }\n        }\n\n        public new bool Enabled\n        {\n            get { return base.Enabled; }\n            set { base.Enabled = value; }\n        }\n\n        public int ForegroundColor\n        {\n            get \n            {\n                return ActiveXControlHelpers.GetOleColorFromColor(base.ForeColor);\n            }\n            set\n            {\n                base.ForeColor = ActiveXControlHelpers.GetColorFromOleColor(value);\n            }\n        }\n\n        public int BackgroundColor\n        {\n            get\n            {\n                return ActiveXControlHelpers.GetOleColorFromColor(base.BackColor);\n                }\n            set\n            {\n                base.BackColor = ActiveXControlHelpers.GetColorFromOleColor(value);\n            }\n        }\n\n        public override System.Drawing.Image BackgroundImage\n        {\n            get{return null;}\n            set\n            {\n                if(null != value)\n                {\n                    MessageBox.Show(&quot;Setting the background image of an Interop UserControl is not supported, please use a PictureBox instead.&quot;, &quot;Information&quot;);\n                }\n                base.BackgroundImage = null;\n            }\n        }\n\n        #endregion\n\n        #region &quot;VB6 Methods&quot;\n\n            public override void Refresh()\n            {\n                base.Refresh();\n            }\n\n            \/\/Ensures that tabbing across VB6 and .NET controls works as expected\n            private void InteropUserControl_LostFocus(object sender, System.EventArgs e)\n            {\n                ActiveXControlHelpers.HandleFocus(this);\n            }\n\n            public InteropUserControl()\n            {\n                \/\/This call is required by the Windows Form Designer.\n                InitializeComponent();\n\n                \/\/&#039; Add any initialization after the InitializeComponent() call.\n                this.DoubleClick += new System.EventHandler(this.InteropUserControl_DblClick);\n                base.Click += new System.EventHandler(this.InteropUserControl_Click);\n                this.LostFocus += new System.EventHandler(InteropUserControl_LostFocus); \n                this.ControlAdded += new ControlEventHandler(InteropUserControl_ControlAdded);\n                \/\/\/\/\/\/\/\/ new events to expose to PB\n                this.TB1.ValueChanged += new System.EventHandler(TB1_ValueChanged);\n                this.TB1.Scroll += new System.EventHandler(TB1_Scroll);\n                \/\/\/\/\/\/\/\/\/\/\n                \/\/&#039;Raise custom Load event\n                this.OnCreateControl();\n            }\n\n            [SecurityPermission(SecurityAction.LinkDemand, Flags =SecurityPermissionFlag.UnmanagedCode)]\n            protected override void WndProc(ref System.Windows.Forms.Message m)\n            {\n\n                const int WM_SETFOCUS = 0x7;\n                const int WM_PARENTNOTIFY = 0x210;\n                const int WM_DESTROY = 0x2;\n                const int WM_LBUTTONDOWN = 0x201;\n                const int WM_RBUTTONDOWN = 0x204;\n\n                if (m.Msg == WM_SETFOCUS)\n                {\n                    \/\/Raise Enter event\n                    this.OnEnter(System.EventArgs.Empty);\n                }\n                else if( m.Msg == WM_PARENTNOTIFY &amp;&amp; (m.WParam.ToInt32() == WM_LBUTTONDOWN || m.WParam.ToInt32() == WM_RBUTTONDOWN))\n                {\n\n                    if (!this.ContainsFocus)\n                    {\n                        \/\/Raise Enter event\n                        this.OnEnter(System.EventArgs.Empty);\n                    }\n                }\n                else if (m.Msg == WM_DESTROY &amp;&amp; !this.IsDisposed &amp;&amp; !this.Disposing)\n                {\n                    \/\/Used to ensure that VB6 will cleanup control properly\n                    this.Dispose();\n                }\n\n                base.WndProc(ref m);\n            }\n\n            \/\/This event will hook up the necessary handlers\n            private void InteropUserControl_ControlAdded(object sender, ControlEventArgs e)\n            {\n                ActiveXControlHelpers.WireUpHandlers(e.Control, ValidationHandler);\n            }\n\n            \/\/Ensures that the Validating and Validated events fire appropriately\n            internal void ValidationHandler(object sender, System.EventArgs e)\n            {\n                if( this.ContainsFocus) return;\n\n                \/\/Raise Leave event\n                this.OnLeave(e);\n\n                if (this.CausesValidation)\n                {\n                    CancelEventArgs validationArgs = new CancelEventArgs();\n                    this.OnValidating(validationArgs);\n\n                    if(validationArgs.Cancel &amp;&amp; this.ActiveControl != null)\n                        this.ActiveControl.Focus();\n                    else\n                    {\n                        \/\/Raise Validated event\n                        this.OnValidated(e);\n                    }\n                }\n            }\n        #endregion\n\n#endif\n        #endregion\n\n        \/\/Please enter any new code here, below the Interop code\n        \/\/\/\/\/\/\/\/\/\/\/ events to expose to PB\n        public delegate void tbValueChangedEventHandler();\n        public event tbValueChangedEventHandler tbValuechanged;\n        private void TB1_ValueChanged(object sender, System.EventArgs e)\n        {\n            if (tbValuechanged != null)\n            {\n                tbValuechanged();\n            }\n        }\n        public event tbScrollEventHandler tbScroll;\n        public delegate void tbScrollEventHandler();\n        private void TB1_Scroll(object sender, System.EventArgs e)\n        {\n            if (tbScroll != null)\n            {\n                tbScroll();\n            }\n        }\n        \/\/\/\/\/\/\/\/\/\/\/\/\n        \/\/method to call from PB\n        public void tbsetbackcolor(int testval)\n        {\n            Color myColor = ColorTranslator.FromWin32(testval); \/\/translate numeric color\n            TB1.BackColor = myColor; \/\/set background of trackbar\n            BackColor = myColor; \/\/ set background of user control\n        }\n        \/\/\/\/\/\/\/\/\/\/\/\n        \/\/ Property get\/set to call from PB\n        public int tb1backgroundcolor\n        {\n            get { return ActiveXControlHelpers.GetOleColorFromColor(TB1.BackColor); }\n            set { TB1.BackColor = ActiveXControlHelpers.GetColorFromOleColor(value); }\n        }\n        public int tb1value\n        {\n            get { return TB1.Value; }\n            set { TB1.Value = value; }\n        }\n        \/\/\/\/\/\/\/\/\/\/\/\n    }\n}<\/pre>\n<p>Note that the two event stubs created by doubleclicking on the event name in the IDE were moved to the end of the class, after the final &#8216;#endregion&#8217; lable so most of the code outside the interface section is together. In a nutshell to expose the event to PB you have to:<br \/>\nA) add the events after the InitializeComponent call on the class<br \/>\nB) create a public <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/db0etb8x.aspx\" target=\"_blank\" rel=\"noopener\">eventhandler<\/a> <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms173171(v=vs.80).aspx\" target=\"_blank\" rel=\"noopener\">delegate<\/a><br \/>\nC) create a public event which the delegate references<br \/>\nD) code the event (double clicking on the control &#8211; event list gives you the event &#8216;skeleton&#8217;<br \/>\nE) add the event to the event interface<\/p>\n<p>To code a property or method which can be called from PB you have to:<br \/>\nA) create a public method with parameters and return values (if needed) OR a public property with both a get and set section.<br \/>\nB) add the method\/property to the property interface<\/p>\n<p>Important Note: Unlike the default for Visual Basic (or PowerBuilder for that matter), C# is <a href=\"http:\/\/en.wikipedia.org\/wiki\/Strong_typing\" target=\"_blank\" rel=\"noopener\">strongly typed<\/a>. This means that a method with the name &#8216;MyEvent&#8217; is not the same as &#8216;myevent&#8217;, &#8216;Myevent&#8217; or &#8216;myEvent&#8217;. Quite often your code will compile file, but when you try to use your component in PB you will crash and burn.<\/p>\n<p>When this is built in Visual Studio a dll is created and registered on the machine. If you want to take the dll to a different machine you will have to manually register the dll in order to use it in PowerBuilder.<\/p>\n<p>Using the control in PowerBuilder<\/p>\n<p>So now to add the control in Powerbuilder you click on the Insert OLE control icon,<br \/>\n<a href=\"http:\/\/anvil-of-time.com\/wordpress\/wp-content\/uploads\/2012\/06\/csharp010.png\"><img loading=\"lazy\" class=\"aligncenter wp-image-1381 size-full\" title=\"csharp010\" src=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp010.png\" alt=\"\" width=\"124\" height=\"213\" srcset=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp010.png 124w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp010-87x150.png 87w\" sizes=\"(max-width: 124px) 100vw, 124px\" \/><\/a><br \/>\nchoose the Insert Control tab and then the control from the control list.<br \/>\n<a href=\"http:\/\/anvil-of-time.com\/wordpress\/wp-content\/uploads\/2012\/06\/csharp011.png\"><img loading=\"lazy\" class=\"aligncenter wp-image-1382 size-full\" title=\"csharp011\" src=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp011.png\" alt=\"\" width=\"391\" height=\"382\" srcset=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp011.png 391w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp011-300x293.png 300w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp011-150x146.png 150w\" sizes=\"(max-width: 391px) 100vw, 391px\" \/><\/a><\/p>\n<p>The example app created to demonstrate the VB .Net component is expanded to include the C# component as well. A few more PB controls are added to the form which results in this.<br \/>\n<a href=\"http:\/\/anvil-of-time.com\/wordpress\/wp-content\/uploads\/2012\/06\/csharp012.png\"><img loading=\"lazy\" class=\"aligncenter wp-image-1383 size-full\" title=\"csharp012\" src=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp012.png\" alt=\"\" width=\"470\" height=\"450\" srcset=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp012.png 470w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp012-300x287.png 300w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp012-150x143.png 150w\" sizes=\"(max-width: 470px) 100vw, 470px\" \/><\/a><\/p>\n<p>The code in the clicked event of the Set Color button follows:<\/p>\n<pre name=\"code\" class=\"VB\">long ll_vb_color, ll_cs_color\n\/\/ set the desired color on the controls\nIF sle_1.text = string(RGB(0,174,221)) THEN\n\tll_vb_color = 15780518\n\tll_cs_color = RGB(168,255,168)\nELSE\n\tll_vb_color = RGB(0,174,221)\n\tll_cs_color = RGB(196,240,16)\nEND IF\n\/\/ call method on VB .Net control\nole_3.object.event tbSetBackColor(ll_vb_color)\n\/\/ call method on C# .Net control\nole_2.object.tbSetBackColor(ll_cs_color)\n\/\/ get the color value using the &#039;getter&#039; method in VB .Net control\nsle_1.text = string(ole_3.object.tb1backgroundcolor())\n\/\/ get the color value using the &#039;getter&#039; method in C# .Net control\nsle_2.Text = string(ole_2.object.tb1backgroundcolor())<\/pre>\n<p>The only difference in the method calls to the controls (tbSetBackColor method) is in VB you qualify it as an event.<\/p>\n<p>The code in the tbvaluechanged event on the C# control is<\/p>\n<pre name=\"code\" class=\"VB\">st_4.text = string(ole_2.object.tb1value())<\/pre>\n<p>Which is calling the C# get method of the tb1value property.<\/p>\n<p>In the tbscroll event on the control is the following:<\/p>\n<pre name=\"code\" class=\"VB\">long ll_val, ll_color\n\/\/report on the current value of the control\nll_val = ole_2.object.tb1value()\n\/\/move the PB control\nvtb_1.position = ll_val<\/pre>\n<p>As is the case for the VB control, you must have some code in the events you expose or you will get an unhandled exception error.<\/p>\n<p>Running the sample application.<br \/>\n<a href=\"http:\/\/anvil-of-time.com\/wordpress\/wp-content\/uploads\/2012\/06\/csharp013.png\"><img loading=\"lazy\" class=\"aligncenter wp-image-1384 size-full\" title=\"csharp013\" src=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp013.png\" alt=\"\" width=\"370\" height=\"492\" srcset=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp013.png 370w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp013-225x300.png 225w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp013-112x150.png 112w\" sizes=\"(max-width: 370px) 100vw, 370px\" \/><\/a><\/p>\n<p>Clicking the Set Color button changes the .Net controls<br \/>\n<a href=\"http:\/\/anvil-of-time.com\/wordpress\/wp-content\/uploads\/2012\/06\/csharp014.png\"><img loading=\"lazy\" class=\"aligncenter wp-image-1385 size-full\" title=\"csharp014\" src=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp014.png\" alt=\"\" width=\"370\" height=\"498\" srcset=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp014.png 370w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp014-222x300.png 222w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp014-111x150.png 111w\" sizes=\"(max-width: 370px) 100vw, 370px\" \/><\/a><\/p>\n<p>Moving the VB control<br \/>\n<a href=\"http:\/\/anvil-of-time.com\/wordpress\/wp-content\/uploads\/2012\/06\/csharp015.png\"><img loading=\"lazy\" class=\"aligncenter wp-image-1386 size-full\" title=\"csharp015\" src=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp015.png\" alt=\"\" width=\"368\" height=\"494\" srcset=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp015.png 368w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp015-223x300.png 223w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp015-111x150.png 111w\" sizes=\"(max-width: 368px) 100vw, 368px\" \/><\/a><\/p>\n<p>Moving the C# control<br \/>\n<a href=\"http:\/\/anvil-of-time.com\/wordpress\/wp-content\/uploads\/2012\/06\/csharp016.png\"><img loading=\"lazy\" class=\"aligncenter wp-image-1387 size-full\" title=\"csharp016\" src=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp016.png\" alt=\"\" width=\"372\" height=\"498\" srcset=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp016.png 372w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp016-224x300.png 224w, https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharp016-112x150.png 112w\" sizes=\"(max-width: 372px) 100vw, 372px\" \/><\/a><\/p>\n<p>The PowerBuilder code was written in version 12.5.1. Within the <a href=\"https:\/\/anvil-of-time.com\/wp-content\/uploads\/2012\/06\/csharpinteroppb.zip\">csharpinteroppb<\/a> are export files if you are working with an earlier version.<\/p>\n<p><a style=\"display: none;\" href=\"http:\/\/www.codeproject.com\" rel=\"tag\">CodeProject<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This article will explain how to build a COM visual component in C# using Visual Studio 2010; it is an extension of my earlier example of using the Interop Forms Toolkit to build a Visual Basic COM object. First you need to install the Microsoft Interop Toolkit (available here). Then download the C# Interop Form&hellip;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[47,3,10],"tags":[84,49,12,13,16,48],"_links":{"self":[{"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/posts\/1373"}],"collection":[{"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/comments?post=1373"}],"version-history":[{"count":11,"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/posts\/1373\/revisions"}],"predecessor-version":[{"id":2039,"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/posts\/1373\/revisions\/2039"}],"wp:attachment":[{"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/media?parent=1373"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/categories?post=1373"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/tags?post=1373"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}