Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. dual interface

dual interface

Scheduled Pinned Locked Moved C / C++ / MFC
questioncom
63 Posts 7 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • G George_George

    Thanks Scott, I like your long and comprehensive post. Two more comments, 1. To implement dual interface is easy, i.e. making the component implement a customized interface, and making the customized interface inherits IDispatch. So, I think since it is easy, every COM component should implement it and be a dual interface. Why implementing dual interface is not mandatory -- i.e. for some other reasons, developer will not implement dual interface? 2. For the compile time binding as you mentioned -- just clarify one point, I think COM consumer should not create and component and call its implementation method directly (call the component other than call the interface) -- but should use QueryInterface to get the interface which the COM component implements, then call the methods (using vtable) through the interface. Correct? regards, George

    S Offline
    S Offline
    Scott Holt
    wrote on last edited by
    #38

    On point 1: I rarely implement dual interfaces because I develop COM servers and COM clients as part of a package application, and my client components always have "up front" knowledge of what the server can do. So, I typically do not implement the IDispatch interface. This results in a little less complexity in my application and improved performance. My belief is that you should only implement IDispatch if a) you are developing a COM component that you are going to make publicly available to other developers so that they might use it in their applications, or b) your COM component needs to be used by a scripting language, for example VBScript within a web page, in which case you must implement IDispatch so that the VBScript can bind to your COM component at run time (late binding). The application that I support is all written in C++ (no scripting languages) and contains no components that are intended to be available for use by other developers outside my company. On point 2: You are correct, the client should always call "QueryInterface" to get a pointer to the desired interface exported by a server, then call the methods of that interface via the pointer. Since the methods of the interface are all defined as virtual functions in C++, you are implicitly invoking the methods through the virtual function table. (Of course, virtual functions are intrinsic to the C++ language and existed long before COM was created.) :)

    G 1 Reply Last reply
    0
    • C CPallini

      George_George wrote:

      Just through of another question, to implement dual interface is easy, i.e. making the component implement a customized interface, and making the customized interface inherits IDispatch. So, I think since it is easy

      Most of COM components implement dual interface.

      George_George wrote:

      So, I think since it is easy, every COM component should implement it and be a dual interface.

      (1) Is not that easy if you're doing it hand-crafting (without the help of a wizard or a framework such MFC or ATL) (2) Keeping COM requirements minimal is (IMHO) a good design approach.

      George_George wrote:

      i.e. for some other reasons, developer will not implement dual interface?

      Because, for instance, all the clients (of the COM server they're building) are written in VTABLE binding language (like C++ or VB6 clients). AS you know VTABLE binding is more efficient than IDispatch mechanism. Final note: if you don't need a feature, why doing efforts to implement it? :)

      If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler. -- Alfonso the Wise, 13th Century King of Castile.
      This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong. -- Iain Clarke
      [My articles]

      G Offline
      G Offline
      George_George
      wrote on last edited by
      #39

      Cool, CPallini! have a good weekend, George

      1 Reply Last reply
      0
      • C CPallini

        George_George wrote:

        Why implementing dual interface is not mandatory

        Keeping COM requirements minimal is a good design approach IMHO (and building a dual interface is not that easy, without wizards or framework, like MFC or ATL, support).

        George_George wrote:

        i.e. for some other reasons, developer will not implement dual interface?

        Because none of the intended clients need it (for instance C++ or VB6 clients don't need IDispatch). As you know IDispatch mechanism is less efficient than VTABLE binding. Anyway most of COM servers actually implement dual interface (by free choiche). :)

        If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler. -- Alfonso the Wise, 13th Century King of Castile.
        This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong. -- Iain Clarke
        [My articles]

        G Offline
        G Offline
        George_George
        wrote on last edited by
        #40

        Hi CPallini, I further question. If we want to support IDispatch, all types in methods' parameter/return value must be auomtation compatible? If yes, why? :-) regards, George

        C 1 Reply Last reply
        0
        • S Scott Holt

          On point 1: I rarely implement dual interfaces because I develop COM servers and COM clients as part of a package application, and my client components always have "up front" knowledge of what the server can do. So, I typically do not implement the IDispatch interface. This results in a little less complexity in my application and improved performance. My belief is that you should only implement IDispatch if a) you are developing a COM component that you are going to make publicly available to other developers so that they might use it in their applications, or b) your COM component needs to be used by a scripting language, for example VBScript within a web page, in which case you must implement IDispatch so that the VBScript can bind to your COM component at run time (late binding). The application that I support is all written in C++ (no scripting languages) and contains no components that are intended to be available for use by other developers outside my company. On point 2: You are correct, the client should always call "QueryInterface" to get a pointer to the desired interface exported by a server, then call the methods of that interface via the pointer. Since the methods of the interface are all defined as virtual functions in C++, you are implicitly invoking the methods through the virtual function table. (Of course, virtual functions are intrinsic to the C++ language and existed long before COM was created.) :)

          G Offline
          G Offline
          George_George
          wrote on last edited by
          #41

          Thanks Scott, 1. Why "you are developing a COM component that you are going to make publicly available to other developers" as you mentioned, I must expose IDisaptch? I could expose vtable only and let them use C++. :-) Any comments or any important points which I missed in my above statements? 2. I further question. If we want to support IDispatch, all types in methods' parameter/return value must be auomtation compatible? If yes, why? :-) regards, George

          S 1 Reply Last reply
          0
          • G George_George

            Hi CPallini, I further question. If we want to support IDispatch, all types in methods' parameter/return value must be auomtation compatible? If yes, why? :-) regards, George

            C Offline
            C Offline
            CPallini
            wrote on last edited by
            #42

            Because automation clients have no clue of other types. :)

            If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler. -- Alfonso the Wise, 13th Century King of Castile.
            This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong. -- Iain Clarke
            [My articles]

            G 1 Reply Last reply
            0
            • C CPallini

              Because automation clients have no clue of other types. :)

              If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler. -- Alfonso the Wise, 13th Century King of Castile.
              This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong. -- Iain Clarke
              [My articles]

              G Offline
              G Offline
              George_George
              wrote on last edited by
              #43

              Thanks CPallini, But can't we include the complex type definition in IDL and build the IDL into typelib and let client use the typelib? regards, George

              C 1 Reply Last reply
              0
              • G George_George

                Thanks CPallini, But can't we include the complex type definition in IDL and build the IDL into typelib and let client use the typelib? regards, George

                C Offline
                C Offline
                CPallini
                wrote on last edited by
                #44

                AFAIK automation clients don't use typelibs. :)

                If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler. -- Alfonso the Wise, 13th Century King of Castile.
                This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong. -- Iain Clarke
                [My articles]

                G 1 Reply Last reply
                0
                • C CPallini

                  AFAIK automation clients don't use typelibs. :)

                  If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler. -- Alfonso the Wise, 13th Century King of Castile.
                  This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong. -- Iain Clarke
                  [My articles]

                  G Offline
                  G Offline
                  George_George
                  wrote on last edited by
                  #45

                  Sorry my bad, CPallini. I always write C++ native client actually. :-) If the automation client (I think you mean client like VB or JScript) does not use typelib, what will they use to invoke? Just read some document about interface/coclass/methods signature information and use GUID or ProgID, then call IDispatch.invoke? regards, George

                  C 1 Reply Last reply
                  0
                  • G George_George

                    Sorry my bad, CPallini. I always write C++ native client actually. :-) If the automation client (I think you mean client like VB or JScript) does not use typelib, what will they use to invoke? Just read some document about interface/coclass/methods signature information and use GUID or ProgID, then call IDispatch.invoke? regards, George

                    C Offline
                    C Offline
                    CPallini
                    wrote on last edited by
                    #46

                    Yes, VBScript clients, for instance, do something like this. :)

                    If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler. -- Alfonso the Wise, 13th Century King of Castile.
                    This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong. -- Iain Clarke
                    [My articles]

                    G 1 Reply Last reply
                    0
                    • C CPallini

                      Yes, VBScript clients, for instance, do something like this. :)

                      If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler. -- Alfonso the Wise, 13th Century King of Castile.
                      This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong. -- Iain Clarke
                      [My articles]

                      G Offline
                      G Offline
                      George_George
                      wrote on last edited by
                      #47

                      Thanks CPallini, Sorry we are talking about two things. :-) I mean VB -- Visual Basic. Any way, here are my questions, let us talk VB and script language (VB Script or JScript) separately. 1. Could VB client use TLB file? 2. Could script client use TLB file? 3. If I define customized type (e.g. a structure) in IDL file, use such customized type as input parameter or return type for some methods, and generate related TLB. Could VB client use such methods? 4. If I define customized type (e.g. a structure) in IDL file, use such customized type as input parameter or return type for some methods, and generate related TLB. Could script client use such methods? regards, George

                      C 1 Reply Last reply
                      0
                      • G George_George

                        Thanks CPallini, Sorry we are talking about two things. :-) I mean VB -- Visual Basic. Any way, here are my questions, let us talk VB and script language (VB Script or JScript) separately. 1. Could VB client use TLB file? 2. Could script client use TLB file? 3. If I define customized type (e.g. a structure) in IDL file, use such customized type as input parameter or return type for some methods, and generate related TLB. Could VB client use such methods? 4. If I define customized type (e.g. a structure) in IDL file, use such customized type as input parameter or return type for some methods, and generate related TLB. Could script client use such methods? regards, George

                        C Offline
                        C Offline
                        CPallini
                        wrote on last edited by
                        #48

                        George_George wrote:

                        I mean VB -- Visual Basic. Any way, here are my questions, let us talk VB and script language (VB Script or JScript) separately.

                        I suppose 'VB' standing for 'Visual Basic 6'.

                        George_George wrote:

                        1. Could VB client use TLB file?

                        AFAIK Yes.

                        George_George wrote:

                        2. Could script client use TLB file?

                        Nope.

                        George_George wrote:

                        3. If I define customized type (e.g. a structure) in IDL file, use such customized type as input parameter or return type for some methods, and generate related TLB. Could VB client use such methods?

                        I don't know. :-O :-D

                        George_George wrote:

                        4. If I define customized type (e.g. a structure) in IDL file, use such customized type as input parameter or return type for some methods, and generate related TLB. Could script client use such methods?

                        Nope. :)

                        If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler. -- Alfonso the Wise, 13th Century King of Castile.
                        This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong. -- Iain Clarke
                        [My articles]

                        G 1 Reply Last reply
                        0
                        • C CPallini

                          George_George wrote:

                          I mean VB -- Visual Basic. Any way, here are my questions, let us talk VB and script language (VB Script or JScript) separately.

                          I suppose 'VB' standing for 'Visual Basic 6'.

                          George_George wrote:

                          1. Could VB client use TLB file?

                          AFAIK Yes.

                          George_George wrote:

                          2. Could script client use TLB file?

                          Nope.

                          George_George wrote:

                          3. If I define customized type (e.g. a structure) in IDL file, use such customized type as input parameter or return type for some methods, and generate related TLB. Could VB client use such methods?

                          I don't know. :-O :-D

                          George_George wrote:

                          4. If I define customized type (e.g. a structure) in IDL file, use such customized type as input parameter or return type for some methods, and generate related TLB. Could script client use such methods?

                          Nope. :)

                          If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler. -- Alfonso the Wise, 13th Century King of Castile.
                          This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong. -- Iain Clarke
                          [My articles]

                          G Offline
                          G Offline
                          George_George
                          wrote on last edited by
                          #49

                          Thanks CPallini! For item 4, you mean for script client, if I define customized type (e.g. a structure) in IDL file, use such customized type as input parameter or return type for some methods, and generate related TLB. Script client can not use such methods? I feel surprised so confirm here again. :-) regards, George

                          C 1 Reply Last reply
                          0
                          • G George_George

                            Thanks CPallini! For item 4, you mean for script client, if I define customized type (e.g. a structure) in IDL file, use such customized type as input parameter or return type for some methods, and generate related TLB. Script client can not use such methods? I feel surprised so confirm here again. :-) regards, George

                            C Offline
                            C Offline
                            CPallini
                            wrote on last edited by
                            #50

                            Scripts client use only VARIANT datatype only via IDispatch. Of course, you know, this is going on my arrogant... :)

                            If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler. -- Alfonso the Wise, 13th Century King of Castile.
                            This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong. -- Iain Clarke
                            [My articles]

                            G 1 Reply Last reply
                            0
                            • C CPallini

                              Scripts client use only VARIANT datatype only via IDispatch. Of course, you know, this is going on my arrogant... :)

                              If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler. -- Alfonso the Wise, 13th Century King of Castile.
                              This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong. -- Iain Clarke
                              [My articles]

                              G Offline
                              G Offline
                              George_George
                              wrote on last edited by
                              #51

                              Thanks CPallini, I did some search but find no results. Do you have any documents referrals which describes whether script language could use TLB or not? regards, George

                              C 1 Reply Last reply
                              0
                              • G George_George

                                Thanks CPallini, I did some search but find no results. Do you have any documents referrals which describes whether script language could use TLB or not? regards, George

                                C Offline
                                C Offline
                                CPallini
                                wrote on last edited by
                                #52

                                Oh, well no. But I'm pretty sure: VBScript & JScript (I'm not talkingt about the .NET one) have only VARIANT datatype and can only access COM components via IDispatch. You may have a look to VBScript or JScript reference documentation on MSDN. :)

                                If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler. -- Alfonso the Wise, 13th Century King of Castile.
                                This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong. -- Iain Clarke
                                [My articles]

                                G 1 Reply Last reply
                                0
                                • C CPallini

                                  Oh, well no. But I'm pretty sure: VBScript & JScript (I'm not talkingt about the .NET one) have only VARIANT datatype and can only access COM components via IDispatch. You may have a look to VBScript or JScript reference documentation on MSDN. :)

                                  If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler. -- Alfonso the Wise, 13th Century King of Castile.
                                  This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong. -- Iain Clarke
                                  [My articles]

                                  G Offline
                                  G Offline
                                  George_George
                                  wrote on last edited by
                                  #53

                                  Thanks for your long help, CPallini! Let us continue to discuss here. :-) http://www.codeproject.com/script/Forums/View.aspx?fid=1647&msg=2725088[^] regards, George

                                  1 Reply Last reply
                                  0
                                  • G George_George

                                    Thanks Scott, 1. Why "you are developing a COM component that you are going to make publicly available to other developers" as you mentioned, I must expose IDisaptch? I could expose vtable only and let them use C++. :-) Any comments or any important points which I missed in my above statements? 2. I further question. If we want to support IDispatch, all types in methods' parameter/return value must be auomtation compatible? If yes, why? :-) regards, George

                                    S Offline
                                    S Offline
                                    Scott Holt
                                    wrote on last edited by
                                    #54

                                    Yes, on point number 1...You ONLY have to support IDispatch if you want scripting languages or other languages that use late binding to be able to use to your COM server component. Of course, this is very often the case these days with so many COM components being written to plug into web sites and be called from VB script, Java script, etc. I'm sorry I should have made this more clear. So, you CAN have a COM component publicly available that does NOT support IDispatch, but it will need to be linked with the client program at compile (build) time. On point 2: YES, all parameter/return values MUST be automation compatible. Basically, this means that everything must be VARIANT, BSTR, long integer, etc. Why? Because COM is a defined standard that all programming languages that wish to be COM compliant must adhere to if they wish to interface with each other, and IDispatch is a defined interface within the standard. If you wish to use much of the automation linkage already put into place by Microsoft, and the COM subsystem (also implemented by Microsoft via Windows), you'll have to adhere to the standards of the subsystem components. For example, of you try to pass a "C-style" string from a C++ program to a VB program through a COM interface, the VB program will probably crash because it doesn't "understand" the structure of a C-style string. Incidentally, I had to read two or three books on COM and diligently work the examples before I got it figured out. I tried using ATL and the Visual Studio wizards to create my COM components, but quickly gave up on this because it was very inflexible when I wanted to make additions or changes to my COM classes. I ended up hand-building, from scratch, all of my COM components, but now I have a library of components for use in my applications. Scott :)

                                    G 1 Reply Last reply
                                    0
                                    • S Scott Holt

                                      Yes, on point number 1...You ONLY have to support IDispatch if you want scripting languages or other languages that use late binding to be able to use to your COM server component. Of course, this is very often the case these days with so many COM components being written to plug into web sites and be called from VB script, Java script, etc. I'm sorry I should have made this more clear. So, you CAN have a COM component publicly available that does NOT support IDispatch, but it will need to be linked with the client program at compile (build) time. On point 2: YES, all parameter/return values MUST be automation compatible. Basically, this means that everything must be VARIANT, BSTR, long integer, etc. Why? Because COM is a defined standard that all programming languages that wish to be COM compliant must adhere to if they wish to interface with each other, and IDispatch is a defined interface within the standard. If you wish to use much of the automation linkage already put into place by Microsoft, and the COM subsystem (also implemented by Microsoft via Windows), you'll have to adhere to the standards of the subsystem components. For example, of you try to pass a "C-style" string from a C++ program to a VB program through a COM interface, the VB program will probably crash because it doesn't "understand" the structure of a C-style string. Incidentally, I had to read two or three books on COM and diligently work the examples before I got it figured out. I tried using ATL and the Visual Studio wizards to create my COM components, but quickly gave up on this because it was very inflexible when I wanted to make additions or changes to my COM classes. I ended up hand-building, from scratch, all of my COM components, but now I have a library of components for use in my applications. Scott :)

                                      G Offline
                                      G Offline
                                      George_George
                                      wrote on last edited by
                                      #55

                                      Thanks Scott, Your answer is really great! Just want to clarify two things. 1. No matter who (I mean COM consumer) will use IDispatch interface, like C++/VB such advanced client or script client, all the parameter types and return value types we use IDispatch.Invoke to pass in/out should be VARIANT, correct? 2. My current confusion is, in IDL I have defined some customized data type (some struct) and in some methods I use such customized data type as input parameter or return value. If I want to support IDispatch.Invoke to consume the methods, could I use such customized data type either as input parameter or return value, even for advanced client C++/VB? :-) regards, George

                                      S 1 Reply Last reply
                                      0
                                      • G George_George

                                        Thanks Scott, Your answer is really great! Just want to clarify two things. 1. No matter who (I mean COM consumer) will use IDispatch interface, like C++/VB such advanced client or script client, all the parameter types and return value types we use IDispatch.Invoke to pass in/out should be VARIANT, correct? 2. My current confusion is, in IDL I have defined some customized data type (some struct) and in some methods I use such customized data type as input parameter or return value. If I want to support IDispatch.Invoke to consume the methods, could I use such customized data type either as input parameter or return value, even for advanced client C++/VB? :-) regards, George

                                        S Offline
                                        S Offline
                                        Scott Holt
                                        wrote on last edited by
                                        #56
                                        1. Well, not necessarily: for example, automation directly supports BSTR (b-strings) and 4-byte integer values (known as long integers in C++), BUT...to keep things more simple, I would recommend just using VARIANT for all of your parameters, as you suggest. If you study the VARIANT data type closely, you'll see that the VARIANT structure itself actually can hold many other data types. Its up to you to figure out what a VARIANT contains by looking at the '.vt' member of the structure. Also, if you're writing in VB, VB can automatically convert from VARIANT to other data types for you. I believe C# can do this also, although I haven't really dabbled in C# yet. If you're writing in C++, you can use the _variant_t class which provides many conversion operators (I use _variant_t all the time in my C++ code). 2) I wouldn't necessarily recommend using a custom data type through the IDispatch interface unless your ready to write "custom marshalling" routines. "Marshaling" is the process of packaging up your function calls and parameters, then passing them across process boundaries, and possibly even across machine boundaries if you are going to have a client on one machine invoke a COM server on another machine (which is another really cool thing to do with COM). Microsoft provides COM components that can performing the marshalling for you based on the information you have in your IDL. Is there a way you can take your custom data type and make it "look" like a standard type? For example, could your custom data type be type cast as a long integer (vt = VT_I4) and placed into a VARIANT for the function call? And then when the server gets the parameter value, it can type cast it again into whatever you need it to be? Scott
                                        G 1 Reply Last reply
                                        0
                                        • S Scott Holt
                                          1. Well, not necessarily: for example, automation directly supports BSTR (b-strings) and 4-byte integer values (known as long integers in C++), BUT...to keep things more simple, I would recommend just using VARIANT for all of your parameters, as you suggest. If you study the VARIANT data type closely, you'll see that the VARIANT structure itself actually can hold many other data types. Its up to you to figure out what a VARIANT contains by looking at the '.vt' member of the structure. Also, if you're writing in VB, VB can automatically convert from VARIANT to other data types for you. I believe C# can do this also, although I haven't really dabbled in C# yet. If you're writing in C++, you can use the _variant_t class which provides many conversion operators (I use _variant_t all the time in my C++ code). 2) I wouldn't necessarily recommend using a custom data type through the IDispatch interface unless your ready to write "custom marshalling" routines. "Marshaling" is the process of packaging up your function calls and parameters, then passing them across process boundaries, and possibly even across machine boundaries if you are going to have a client on one machine invoke a COM server on another machine (which is another really cool thing to do with COM). Microsoft provides COM components that can performing the marshalling for you based on the information you have in your IDL. Is there a way you can take your custom data type and make it "look" like a standard type? For example, could your custom data type be type cast as a long integer (vt = VT_I4) and placed into a VARIANT for the function call? And then when the server gets the parameter value, it can type cast it again into whatever you need it to be? Scott
                                          G Offline
                                          G Offline
                                          George_George
                                          wrote on last edited by
                                          #57

                                          Thanks Scott, I am always confused about two concepts. Automation compatible data type and VARIANT. Are they the same thing -- means if a data type could be represented by VARIANT, it is automation compatible? I did some study, and find seems VARIANT is not ole automation type? So, I am even confused. It is appreciated if you could clarify the relationship between ole automation data type and VARIANT. http://msdn.microsoft.com/en-us/library/aa367129%28VS.85%29.aspx[^] regards, George

                                          S 1 Reply Last reply
                                          0
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          • Login

                                          • Don't have an account? Register

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • World
                                          • Users
                                          • Groups