Announcement

Collapse
No announcement yet.

PB COM DLL from C#

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • PB COM DLL from C#

    Hi,

    I've just started with PB and have been tasked with creating a com dll to be used in a c# project. To begin with I've used the following example to create a com dll:

    Code:
    #COMPILE DLL
    #COM TLIB ON
    
    #RESOURCE "MyClass.pbr"
    
    #DIM ALL
    
    #COM NAME "MyClass", 1.00
    #COM DOC  "Example Class"
    
    $MyClassGuid = GUID$("{00000099-0000-0000-0000-000000000008}")
    $MyIfaceGuid = GUID$("{00000099-0000-0000-0000-000000000009}")
    
    '------------------------------------------------------------------------------------------------------------------------------------------------------
    CLASS MyClass $MyClassGuid AS COM
        INSTANCE Counter AS LONG
    
        INTERFACE MyInterface $MyIfaceGuid
            INHERIT DUAL            ' inherit the base class
    
            METHOD BumpIt(Inc AS LONG) AS LONG
                LOCAL Temp AS LONG
                Temp& = Counter + Inc
                INCR Counter
                METHOD = Temp&
            END METHOD
    
        END INTERFACE
    
    END CLASS
    This successfully compiles, the type library is embedded and the dll is registered.

    If I create a simple PB client to access this class it works. However, from Visual Studio, the following c# code:

    Code:
    using System;
    using MyClass;
    
    namespace simplecom
    {
        public class Class1
        {
            public static void Main(String[] Args)
            {
                MyClassClass Stuff = new MyClassClass();
    
                int value, x, y;
    
                value = 77;
    
                x = Stuff.BUMPIT(ref value);
                y = Stuff.BUMPIT(ref value);
    
                Console.WriteLine("x: {0}, y: {1}", x, y);
            }
        }
    }
    although it compiles (thanks to 9.01 of PB), when run it generates the following exception:

    Code:
    Unhandled Exception: System.InvalidCastException: Unable to cast COM object of type 'MyClass.MyClassClass' to interface type 'MyClass.MYINTERFACE'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{00000099-0000-0000-0000-000000000009}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).
       at MyClass.MyClassClass.BUMPIT(Int32& INC)
       at simplecom.Class1.Main(String[] Args) in z:\Visual Studio 2008\Projects\simplecom\simplecom\Class1.cs:line 16
    I'm at a complete loss, it appears not to like the argumentbeing passed to the method.

    Cheers,
    Niall

  • #2
    >using MyClass;

    Afaik you must add a reference in VS.
    Using is a namespace and imo does not apply to com objects.
    hellobasic

    Comment


    • #3
      I did the Project->Add Reference in VS to select my COM server to import the namespace, the C# won't compile otherwise.

      Comment


      • #4
        I think it is simply a case problem. PB automatically capitalized MyInterface and C# is case sensitive. Try to write the PB method with capitalized letters and see what happens.


        Peter Redei

        Comment


        • #5
          I set the method to all uppercase in PB, but I still get the same runtime error from VS.

          Comment


          • #6
            Try to write the PB method with capitalized letters and see what happens.
            Perhaps a use for...

            Code:
            [CLASS|OVERRIDE] METHOD name [<DispID>] [B][COLOR="Red"][ALIAS "altname"] [/COLOR][/B](var AS type...) [AS type]
            Unfortunately the help file page never explains or demonstrates the use of ALIAS. I shall send in a "Documentation Improvement Suggestion"

            MCM
            Michael Mattias
            Tal Systems (retired)
            Port Washington WI USA
            [email protected]
            http://www.talsystems.com

            Comment


            • #7
              I've also tried using random GUIDs from the PBWin IDE and changed the name of the class from the confusing MyClass.

              Still getting the same runtime error in VS.

              Has anyone actually managed to get COM Objects written in PB to work from C#?

              Comment


              • #8
                Yes.
                I forgot but it is simple.
                Embed the tlb file in the dll.
                hellobasic

                Comment


                • #9
                  My PwrDev object dll template works just fine:
                  Code:
                  using System;
                  using System.Collections.Generic;
                  using System.ComponentModel;
                  using System.Data;
                  using System.Drawing;
                  using System.Text;
                  using System.Windows.Forms;
                  
                  namespace WindowsApplication1
                  {
                      public partial class Form1 : Form
                      {
                          public Form1()
                          {
                              InitializeComponent();
                          }
                  
                          private void Form1_Load(object sender, EventArgs e)
                          {
                              PwrDev_COM_server.CLASS1 c = new PwrDev_COM_server.CLASS1();
                              String T = c.DateValue;
                          }
                      }
                  }
                  Class:

                  Code:
                  '----------------------------------------------------
                  ' Class
                  ' CLASS name  [$GUID]  [AS COM | AS EVENT]
                  ' Use like:
                  '    Local oInterface1 As Interface1
                  '    oInterface1 = Class "Class1"
                  '----------------------------------------------------
                  
                  Class Class1 Guid$("{3BB832AC-D358-4A79-A82C-FF53AEABE2A1}") As Com
                  
                      '----------------------------------------------------
                      ' Class private data.
                      '----------------------------------------------------
                  
                      Instance mDateValue As String
                  
                      '----------------------------------------------------
                      ' Class methods.
                      '----------------------------------------------------
                  
                      ' Class constructor, initialize class here.
                      Class Method Create
                          mDateValue = UCode$( Time$ )
                      End Method
                  
                      ' Class destructor, clean up.
                      Class Method Destroy
                  
                      End Method
                  
                      Class Method ClassMethod1( ByVal Param As Long ) As String
                          Method = Format$( Param )
                      End Method
                  
                      '----------------------------------------------------
                      ' Interfaces.
                      ' (INTERFACE interfacename [$GUID] [AS EVENT] [AS COM])
                      '----------------------------------------------------
                  
                      Interface Interface1 Guid$("{19DF21F0-3118-453C-8A62-CF72D176A807}"): Inherit Dual
                  
                          Property Get DateValue Alias "DateValue"() As String
                              Property = mDateValue
                          End Property
                  
                          Property Set DateValue Alias "DateValue"( ByVal DateValue As String )
                              mDateValue = DateValue
                          End Property
                  
                          Method SetDateValue Alias "SetDateValue"( ByVal DateValue As String )
                              mDateValue = DateValue
                          End Method
                  
                          Method MyClassMethod Alias "MyClassMethod"( ByVal Param As Long ) As String
                              Method = Me.ClassMethod1( Param )
                          End Method
                  
                      End Interface
                  
                  End Class
                  (and the app guids of course)
                  hellobasic

                  Comment


                  • #10
                    I compiled your example PB and tried a simple VS C# test:

                    Code:
                    using System;
                    using edwin;
                    
                    namespace simplecom
                    {
                        public class NewClass
                        {
                            public static void Main(String[] Args)
                            {
                                CLASS1 c = new CLASS1();
                    
                                String T = c.DateValue;
                            }
                        }
                    }
                    but still get the same runtime error:

                    Code:
                    System.InvalidCastException was unhandled
                      Message="Unable to cast COM object of type 'edwin.CLASS1Class' to interface type 'edwin.INTERFACE1'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{19DF21F0-3118-453C-8A62-CF72D176A807}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE))."
                      Source="Interop.edwin"
                      StackTrace:
                           at edwin.CLASS1Class.get_DateValue()
                           at simplecom.NewClass.Main(String[] Args) in z:\Visual Studio 2008\Projects\simplecom\simplecom\Class1.cs:line 12
                           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()
                      InnerException:

                    Comment


                    • #11
                      1) Is there a com name specified?
                      2) For convienance, did you insert the tlb into the dll?
                      3) Why using.. again? it has nothing to do with the namespaces (imo).
                      4) Add reference done?
                      5) dll registered?

                      Pfffftt
                      hellobasic

                      Comment


                      • #12
                        1) Is there a com name specified?

                        if you mean #COM NAME then yes.

                        2) For convienance, did you insert the tlb into the dll?

                        yep.

                        3) Why using.. again? it has nothing to do with the namespaces (imo).

                        why does it matter, you either:

                        use module

                        to import the name or state each declaration tediously:

                        module.CLASS c = new module.CLASS();

                        I tried it your way and it makes no difference to the error.

                        4) Add reference done?

                        I have added a reference to the project. It wouldn't compile otherwise.

                        5) dll registered?

                        I wouldn't be able to add a reference if I hadn't done this.

                        Pfffftt

                        Yep.

                        Comment


                        • #13
                          Using is for namespaces, imo not related to com interfaces and .NET class without namespace.

                          I can help you.. remote (teamviewer.com) or send the dll.
                          hellobasic

                          Comment


                          • #14
                            We have just discovered that if you create a new project in VS and use the Windows Forms Application instead of the Console Application like I was originally, then it actually works!

                            So, the problem appears to be with VS Console App projects.

                            Comment


                            • #15
                              You should really use

                              Code:
                               
                               
                              private void Form1_Shown(object sender, EventArgs e)
                              {
                               
                              }
                              instead of Form1_Load, because it doesn't execute when the form is first loaded. Place a MessageBox.Show("Hello"); there to see if it is executing.

                              I am also getting the exception when trying to load a PB COM LIB from C#.
                              Scott Slater
                              Summit Computer Networks, Inc.
                              www.summitcn.com

                              Comment


                              • #16
                                Originally posted by Niall Hallett View Post
                                So, the problem appears to be with VS Console App projects.
                                Have you verified this? I can't get C# to call PB "COM" at all. As stated earlier, the Form1_Load doesn't execute right away, so you won't see an error by placing the code there. I don't get any error until I actually try creating the object reference elsewhere in the C# code. I have tried various types of base classes in PB too, all with the same result as Niall was experiencing.

                                I would like to see a working example of calling a PB method from a C# program with working results.
                                Scott Slater
                                Summit Computer Networks, Inc.
                                www.summitcn.com

                                Comment


                                • #17
                                  You must have PB9.01 not 9.00 (or CC)
                                  hellobasic

                                  Comment


                                  • #18
                                    Yes, using PB 9.01 with VS 2008 C#
                                    Scott Slater
                                    Summit Computer Networks, Inc.
                                    www.summitcn.com

                                    Comment


                                    • #19
                                      PB Win 9.01 Code:
                                      Code:
                                      #Compile Dll
                                      #Dim All
                                      #Resource "ExToCSharp.pbr"  ' <--- For embeding TLB
                                       
                                      $LIBID = Guid$("{21AADD80-14AF-43B3-B829-841E094BAB2C}")
                                      $CLSID = Guid$("{FFD516C6-B12A-4823-861C-8F3B607E7E1F}")
                                      $IID = Guid$("{8C796C42-3442-4E09-8F5C-839B8E450BAF}")
                                       
                                      #Com Doc "This is a test library created with PowerBASIC for use with C#"
                                      #Com Name "PBTest", 1.00
                                      #Com Guid $LIBID
                                      #Com TLib On
                                       
                                      %USEMACROS=1
                                      #Include "Win32Api.inc"
                                       
                                      Class PBClass $CLSID As Com
                                       
                                         Instance idVal1 As Dword
                                         Instance idVal2 As Dword
                                       
                                         Class Method Create
                                            idVal1 = 1
                                            idVal2 = 2
                                         End Method
                                       
                                         Interface PBInt $IID: Inherit Dual
                                       
                                            Property Get Val1 Alias "Val1" As Dword
                                               Property = idVal1
                                            End Property
                                       
                                            Property Set Val1 Alias "Val1" (ByVal inVal As Dword)
                                               idVal1 = inVal
                                            End Property
                                       
                                            Property Get Val2 Alias "Val2" As Dword
                                               Property = idVal2
                                            End Property
                                       
                                            Property Set Val2 Alias "Val2" (ByVal inVal As Dword)
                                               idVal2 = inVal
                                            End Property
                                       
                                            Method SumVals Alias "SumVals" As Dword
                                               Method = idVal1 + idVal2
                                            End Method
                                       
                                            Method ResetVals Alias "ResetVals"
                                               Me.Create
                                            End Method
                                       
                                            Method Num2String Alias "Num2String"(ByVal inVal As Dword) As String
                                               Method = UCode$(Format$(inVal))
                                            End Method
                                       
                                            Method ClearVals Alias "ClearVals"
                                               idVal1 = 0: idVal2 = 0
                                            End Method
                                         End Interface
                                       
                                      End Class
                                      Compiles fine, and can be accessed from another PB Client Ap without problems.

                                      C# Code:
                                      Code:
                                      using System;
                                      using System.Collections.Generic;
                                      using System.ComponentModel;
                                      using System.Data;
                                      using System.Drawing;
                                      using System.Linq;
                                      using System.Text;
                                      using System.Windows.Forms;
                                      using PBTest;  // <-- PB Library Name, this works because it shows up in intelesense.
                                      // Works without it too, if you use the long names in the calls below.
                                      
                                      // Still throws an exception however when creating the object.
                                      
                                      namespace MyTestAp
                                      {
                                          public partial class Form1 : Form
                                          {
                                              public Form1()
                                              {
                                                  InitializeComponent();
                                              }
                                      
                                              private void Form1_Shown(object sender, EventArgs e)
                                              {
                                                  PBCLASS pb = new PBCLASS();  // <---  Fails on this line!
                                                  pb.Val2 = 7;
                                                  MessageBox.Show(pb.Num2String(pb.Val2));
                                              }
                                          }
                                      }
                                      The C# app gets an exceptio on the ... new PBCLASS() line.
                                      Last edited by Scott Slater; 29 Jun 2009, 03:19 PM. Reason: clarify 9.01 for PB Windows Compiler version.
                                      Scott Slater
                                      Summit Computer Networks, Inc.
                                      www.summitcn.com

                                      Comment


                                      • #20
                                        ## update:

                                        ## UPDATE:

                                        I found out what was causing the problem in my situation. I am running 64-Bit Vista and my build environment on the C# program was set to "Platform = Any". This was building a 64-Bit version apparently, so I explicitly changed the build platform to equal x86 and it now can see the PB Created Obj Code!!

                                        I just wanted to pass this along since I know someone else will encounter a similar similar problem at some point.
                                        Scott Slater
                                        Summit Computer Networks, Inc.
                                        www.summitcn.com

                                        Comment

                                        Working...
                                        X