Announcement

Collapse
No announcement yet.

VB Multi-Threaded COM Component Example in the Source Code Forum

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

  • VB Multi-Threaded COM Component Example in the Source Code Forum

    Hey all

    This is the discussion for the VB Multi-Threaded COM Component Example in the Source Code Forum

    Questions or help making it better, please add it here

    Thanks
    Sr. Software Development Engineer and Sr. Information Security Analyst,
    CEH, Digital Forensic Examiner

  • #2
    Hi Thomas,

    I have a question. Maybe a silly one. Why do you need to do CoInitializeEx ?

    Cheers
    Steven
    So here we are, this is the end.
    But all that dies, is born again.
    - From The Ashes (In This Moment)

    Comment


    • #3
      >Why do you need to do CoInitializeEx?

      Because it has to be done to use COM and it costs (almost) nothing to 'do it again.' (I think the compiler does it automatically whether you want/need it or not.)

      What I don't know is if the compiler automatically does it on new threads of execution.. and it must be done on each thread in which COM calls are used.......
      CoInitializeEx must be called at least once, and is usually called only once, for each thread that uses the COM library. Multiple calls to CoInitializeEx by the same thread are allowed as long as they pass the same concurrency flag, but subsequent valid calls return S_FALSE. To close the COM library gracefully on a thread, each successful call to CoInitialize or CoInitializeEx, including any call that returns S_FALSE, must be balanced by a corresponding call to CoUninitialize.
      But the compiler handles a lot of these messy details, so even this documentation may not apply in all cases.
      Michael Mattias
      Tal Systems (retired)
      Port Washington WI USA
      [email protected]
      http://www.talsystems.com

      Comment


      • #4
        So far this thing works pretty well, the only issue I have is that the call from the window back into an "Event Marshaler" (IE. Doit()) I do not like. Is there anyway for me to call into a hidden method?
        Sr. Software Development Engineer and Sr. Information Security Analyst,
        CEH, Digital Forensic Examiner

        Comment


        • #5
          Is this a VB.NET thing????

          I have tried like crazy to get it to work in VB6, but I am missing how to add it to the project.
          Engineer's Motto: If it aint broke take it apart and fix it

          "If at 1st you don't succeed... call it version 1.0"

          "Half of Programming is coding"....."The other 90% is DEBUGGING"

          "Document my code????" .... "WHYYY??? do you think they call it CODE? "

          Comment


          • #6
            No.. not a .net thing...

            To compile, compile as usual with pb
            run pbtyp <filename>
            run regsvr32 <filename>

            Then you need to add a reference to it.. this is done by clicking Projects/Add Reference in the VB IDE

            then.. In your form code..
            Private withevents MyItem as CAPPLICATION

            at this point it should show up in the object drop down list
            Sr. Software Development Engineer and Sr. Information Security Analyst,
            CEH, Digital Forensic Examiner

            Comment


            • #7
              ok this is what I have done (and trying NOT get aggravated (but obviously I am a wee bit) so maybe you guys can show me where I went wrong.
              1. Compile the example
              2. Register the DLL
              3. Add a Reference to the DLL

              (Note the below only works if the TLB that is created is included in your resource file from what I find)

              From there is should be
              1. Declare a variable to be my object to the DLL
              2. Set the variable as a new object (Intellisence does not work, so I am hunting and pecking here, although I can see it in the toolbox window as to classes and variables that are shown)


              Now you see why I can not get things working...its the 1st initial things that make the later not work
              Engineer's Motto: If it aint broke take it apart and fix it

              "If at 1st you don't succeed... call it version 1.0"

              "Half of Programming is coding"....."The other 90% is DEBUGGING"

              "Document my code????" .... "WHYYY??? do you think they call it CODE? "

              Comment


              • #8
                Sounds like your not embedding the TypeLib in the dll or your not declaring it with events

                Create a <filename>.rc

                Run Pbtyp <filename>.bas

                this will embed the typelib


                Usage
                '--------------------------------------------
                Private withevents myobject as <thisobject>
                Sub Form_Load()

                set myobject = CreateObject("<thisobject>")



                End Sub
                '--------------------------------------------

                What exactly is the error you are getting?
                Last edited by Thomas Tierney; 17 Oct 2008, 11:56 AM. Reason: add a line
                Sr. Software Development Engineer and Sr. Information Security Analyst,
                CEH, Digital Forensic Examiner

                Comment


                • #9
                  Now that I am back on programming with objects, the error I get is that VB has encountered a problem and must close, and an invalid memory location error.
                  This happens both with the exe compiled and in the IDE.

                  I did some deeper digging about the CoInitializeEx which lead me to finding that rather than the hardcoded 0 the function is defined as
                  Code:
                  DECLARE FUNCTION CoInitializeEx LIB "ole32.dll" ALIAS "CoInitializeEx" (pvReserved AS ANY, BYVAL dwCoInit AS DWORD) AS LONG
                  Where MSDN says pvReserved must be NULL
                  and dwCoInit is described as
                  dwCoInit
                  [in] Flags specifying the concurrency model and initialization options for the thread. Values for this parameter are taken from the COINIT enumeration. Any combination of values from the COINIT enumeration can be used, except that the COINIT_APARTMENTTHREADED and COINIT_MULTITHREADED flags cannot both be set.
                  Then in the Win32Api.inc I found the values for COINIT are
                  Code:
                  ' COM initialization flags; passed to CoInitialize. COINIT enum.
                  %COINIT_APARTMENTTHREADED  = &H2   ' Apartment model
                  #IF %DEF(%WIN32_DCOM) ' DCOM
                    %COINIT_MULTITHREADED     = &H0   ' OLE calls objects on any thread.
                    %COINIT_DISABLE_OLE1DDE   = &H4   ' Don't use DDE for Ole1 support.
                    %COINIT_SPEED_OVER_MEMORY = &H8   ' Trade memory for speed.
                    ' Flags for Synchronization API and Classes. COWAIT_FLAGS enum.
                    %COWAIT_WAITALL   = 1
                    %COWAIT_ALERTABLE = 2
                  #ENDIF ' DCOM
                  But I can not find where %WIN32_DCOM is defined, nor what its value should be??? so that I can use %COINIT_MULTITHREADED, but also causes a conflict in my eyes that you can not have %COINIT_APARTMENTTHREADED and %COINIT_MULTITHREADED

                  So I am TOTALLY lost and no idea how figure out what the problem is until I can find documentation as to definitions and what they do????
                  Last edited by Cliff Nichols; 28 Oct 2008, 10:39 AM. Reason: code mistake
                  Engineer's Motto: If it aint broke take it apart and fix it

                  "If at 1st you don't succeed... call it version 1.0"

                  "Half of Programming is coding"....."The other 90% is DEBUGGING"

                  "Document my code????" .... "WHYYY??? do you think they call it CODE? "

                  Comment


                  • #10
                    But I can not find where %WIN32_DCOM is defined
                    Nowhere. You have to define it in your application.

                    nor what its value should be???
                    Any value, e.g. %WIN32_DCOM = 1.
                    Forum: http://www.jose.it-berater.org/smfforum/index.php

                    Comment


                    • #11
                      Thanx Jose,
                      At least that explains some of the difficulty.

                      One thing I am finding is if I comment out the CoUnInitialize then no crash (until closing of course), but with the CoUnInitialize, thats when I crash?

                      The docs say each CoInitializeEx MUST be paired with a CoUnInitialize....so I am confused why this is where I get the crash? (I even threw my errorhandler.inc at it to try and log the error, but too late, its crashed anyways)

                      Has anyone gotten it to work? I have even tried to do the same thing but no threads and my own code gets the same problem.
                      Engineer's Motto: If it aint broke take it apart and fix it

                      "If at 1st you don't succeed... call it version 1.0"

                      "Half of Programming is coding"....."The other 90% is DEBUGGING"

                      "Document my code????" .... "WHYYY??? do you think they call it CODE? "

                      Comment


                      • #12
                        Scratch that....digging deeper I find that CoInitializeEx is coming back with an error of an invalid parameter (no matter what I send to it??)

                        Code:
                            LOCAL Result AS LONG
                            LOCAL lResult AS LONG
                            LOCAL lReserved AS LONG
                            LOCAL ErrorBuff AS ASCIIZ * %MAX_PATH
                            lResult = CoinitializeEx( lReserved, %COINIT_APARTMENTTHREADED)     '<--- Returns Invalid Parameter Error
                        '    lResult = GetLastError     '<--- Returns no error
                             FormatMessage %FORMAT_MESSAGE_FROM_SYSTEM, BYVAL %NULL, lResult, %NULL, ErrorBuff, SIZEOF(ErrorBuff), BYVAL %NULL     'Format the message
                        
                            MSGBOX STR$(lResult) + $CR + ErrorBuff
                        Engineer's Motto: If it aint broke take it apart and fix it

                        "If at 1st you don't succeed... call it version 1.0"

                        "Half of Programming is coding"....."The other 90% is DEBUGGING"

                        "Document my code????" .... "WHYYY??? do you think they call it CODE? "

                        Comment


                        • #13
                          Being a COM DLL, PB does the calls to CoInitialize and CoUninitialize under the hood, so further calls to CoInitialize or CoInitializeEx will fail. If you want to call CoInitializeEx, you will need to call CoUninitialize first, but I wonder why you want to do this.
                          Forum: http://www.jose.it-berater.org/smfforum/index.php

                          Comment


                          • #14
                            Example from Pb Docs

                            Ok I took a step back because I just could not figure things out.
                            From the help files the example shows
                            ComServer
                            Code:
                            #COMPILE DLL "ComServer.dll"
                            #COM TLIB ON
                            #RESOURCE "ComServer.pbr"                           'Include TLB in resource
                            #INCLUDE "Win32API.inc"
                            
                            $EvIFaceGuid = GUID$("{00000098-0000-0000-0000-000000000002}")
                            $MyClassGuid = GUID$("{00000098-0000-0000-0000-000000000003}")
                            $MyIFaceGuid = GUID$("{00000098-0000-0000-0000-000000000004}")
                            
                            INTERFACE STATUS $EvIFaceGuid AS EVENT
                              INHERIT IUNKNOWN
                              METHOD Done
                            END INTERFACE
                            
                            CLASS MyClass $MyClassGuid AS COM
                              INTERFACE MyMath $MyIFaceGuid
                                INHERIT IUNKNOWN
                            '     inherit Dual
                            '     INHERIT Dispatch
                                METHOD DoMath '<1>
                                  MSGBOX "Calculating..."   ' Do some math calculations here
                                  RAISEEVENT Status.Done()
                                END METHOD
                              END INTERFACE
                            
                              EVENT SOURCE STATUS
                            
                            END CLASS
                            ComServer.rc
                            Code:
                            #include "resource.h"                             //<--- Typical Resource Call
                            1 typelib "ComServer.tlb"       //<--- Unsure about this yet, but researching
                            PB ComClient
                            Code:
                            #COMPILE EXE "ComClient.exe"
                            
                            $EvClassGuid = GUID$("{00000098-0000-0000-0000-000000000001}")
                            $EvIFaceGuid = GUID$("{00000098-0000-0000-0000-000000000002}")
                            $MyIFaceGuid = GUID$("{00000098-0000-0000-0000-000000000004}")
                            
                            CLASS EvClass $EvClassGuid AS EVENT
                              INTERFACE STATUS $EvIFaceGuid AS EVENT
                                INHERIT IUNKNOWN
                                METHOD Done
                                  MSGBOX "Done!"
                                END METHOD
                              END INTERFACE
                            END CLASS
                            
                            INTERFACE MyMath $MyIFaceGuid
                              INHERIT IUNKNOWN
                              METHOD DoMath
                            END INTERFACE
                            
                            FUNCTION PBMAIN()
                              DIM oMath AS MyMath
                              DIM oStatus AS STATUS
                            
                              LET oMath = NEWCOM "MyClass"
                              LET oStatus = CLASS "EvClass"
                            
                              EVENTS FROM oMath CALL oStatus
                              oMath.DoMath
                              EVENTS END oStatus
                            END FUNCTION
                            Which works fine

                            VB ComClient
                            Code:
                            Dim WithEvents MyEvent As MyClass
                            Dim MyClass As MyClass
                            
                            Private Sub Command1_Click()
                                MyClass.DOMATH
                            End Sub
                            
                            Private Sub Form_Load()
                                Set MyClass = CreateObject("MyClass")
                            End Sub
                            
                            Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
                                Set MyClass = Nothing
                            
                            End Sub
                            
                            Private Sub MyEvent_DONE()
                                MsgBox "Hello"
                            End Sub
                            Which does not work.

                            To replicate the VB side you will need to do the following
                            1. Have VB to test with
                            2. Place a copy of ComServer.dll in your VB Project folder
                            3. Register the ComServer.dll using Regsvr32
                            4. Add a reference to the ComServer.dll in the VB IDE
                            5. Save the project and close the IDE
                            6. Open the project again from Windows Explorer (This is so the IDE does not think the current folder is the M$ default)
                            7. Run the project
                            You will see the messagebox from PB, but will never see the messagebox from VB from the event that is supposed to fire, but does not.

                            I have no clue what to do to get the event to fire????
                            Engineer's Motto: If it aint broke take it apart and fix it

                            "If at 1st you don't succeed... call it version 1.0"

                            "Half of Programming is coding"....."The other 90% is DEBUGGING"

                            "Document my code????" .... "WHYYY??? do you think they call it CODE? "

                            Comment


                            • #15
                              And why do you use INHERIT IUNKNOWN instead of INHERIT IDISPATCH, both in the events class and MyClass class, if VB uses Automation, not direct interface calls?
                              Forum: http://www.jose.it-berater.org/smfforum/index.php

                              Comment


                              • #16
                                I FINALLLLY found an avenue I can persue. but like Jose pointed out
                                Being a COM DLL, PB does the calls to CoInitialize and CoUninitialize under the hood, so further calls to CoInitialize or CoInitializeEx will fail. If you want to call CoInitializeEx, you will need to call CoUninitialize first
                                In this case (at least at first) it would have been better if they did not, then I would be forced to do it myself (but I see why it was done this way)

                                Is there a way to get the reference count as to matched pairs of CoInitialize and CoUnInitialize? or even unmatched count of what the computer says is open number of the reference count?

                                I am sooooo close that I can taste it....but just stumped by another M$ wall because I figured out how to defeat the last troll at the last M$ wall just to go 5 feet and see a new wall built
                                Engineer's Motto: If it aint broke take it apart and fix it

                                "If at 1st you don't succeed... call it version 1.0"

                                "Half of Programming is coding"....."The other 90% is DEBUGGING"

                                "Document my code????" .... "WHYYY??? do you think they call it CODE? "

                                Comment

                                Working...
                                X