Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / Interop / November 2005

Tip: Looking for answers? Try searching our database.

ActiveX in a formless app or service

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
fdeckerNOSPAMM@aol.com - 10 Nov 2005 20:22 GMT
I see thousands of posts on this one and no answers that help us in our
situation.  I could also use some help if not in solving the problem,
then in education on what .NET is doing with AXImport and TLBImport
utilities.

Environment: VB.NET
Control: ActiveX written in Delphi 7 (but any OCX should be the same)
Problem: Trying to create controls with events dynamically at runtime
with no form.
             Need to find a way to make this work as a service

Path 1 -------------------------------------

Regular MFC projects using the component work fine.  Also, if I just
add the reference to the control at design time and dynamically create
the control at runtime, the service works perfectly... but only for one
event.  If I try to add more than one event handler to the project, I
get the 0x80040202 error.  This has something to do with event sinks.
What is different about the import created that uses no
AxInterop.myOCX, but does use Interop.myOCX and Interop.StdVCL that
causes a component that works in every other environment to not work
when instantiated this way?  What is the solution to this path to the
problem?  I believe I have to change the ckSingle param to ckMulti in
this function (though I don't know it is NOT being done correctly since
a Delphi wizard creates the ActiveX):

if FControlFactory.EventTypeInfo <> nil then
   FConnectionPoints.CreateConnectionPoint(FControlFactory.EventIID,
     ckSingle, EventConnect);

But I think I would then have to iterate through all the events and
create sinks for each one.  Why did .NET mess with this?  Would I need
2 versions of the control so it would work with VB6 and everything
else, or implement some other way to know whether to use single or
multiple event sinks?  Or will this change not affect how it works in
regular VB6 and other environments?  What is involved in trying to fix
the problem using this path?  Here is the code in VB.NET

Private WithEvents myOCX As myControls.myOCX

my OCX = new myControls.MyOCX

Path 2  ----------------------------------

If I create an AxInterop assembly and add that also as a reference,
then I run into a problem with the ActiveX needing a form.  If I add a
reference to system.windows.forms to the solution explorer I can get
past one error that AxInterop needs it.  I now have to slightly change
the code adding AX in front of everything:

Private WithEvents myOCX as AxmyControl.AxmyOCX

What is different with this assembly?  Why are there two ways (with and
without the AX) and what does this do?  And more importantly, when I do
this, I cannot instantiate the object now because I get an error
stating it has to run in a single threaded apartment.  Most of the
1000+ messages about this end in "add Stathread to main()".  I have
tried to put <StaThread()> _ in front of my Main routine and in front
of Start, and tried instantiating my control everywhere I can think of
but the error will not go away.  Here is the code:

<STAThread()> _ (tried this here, in front of Main() instead and both
places)
   Protected Overrides Sub OnStart(ByVal args() As String)
       myOCX = New AxmyControls.AxMyOCX
       myOCX.Enabled = True

There are too many variables.  The startup object is "service1" instead
of "main", but changing that has no effect.  How can I get this path to
work?  Why isn't it setting the STA thread so I can get past this
error?

Path 3

Trying to dynamically create a form, put the ActiveX on it, and run it
that way.  I can't figure out how to do it.  I've tried:

   Private WithEvents myForm As System.Windows.Forms.Form

   <STAThread()> _   (tried this here, in front of Main() instead and
both places)
   Protected Overrides Sub OnStart(ByVal args() As String)
       myForm = New System.Windows.Forms.Form
       System.Windows.Forms.Application.Run(myForm)
       ...

     Private Sub myForm_Load(ByVal sender As Object, ByVal e As
         myOCX = New AxmyControls.AxmyOCX
         myForm.Controls.Add(myOCX)

This time the service loads and gets to Form_Load, but then times out
and won't load the service.  It seems to stop where I am creating the
control with no error.  I can't find out why starting the service timed
out, but I know it can't get past instantiating the OCX.  Thanks for
the help.  The Microsoft Certified Partner site is down for a week and
we can't get access to what we need to get support on there or in the
managed groups.

Fred
Robert Jordan - 10 Nov 2005 21:31 GMT
> [...] I cannot instantiate the object now because I get an error
> stating it has to run in a single threaded apartment.  Most of the
[quoted text clipped - 13 lines]
> work?  Why isn't it setting the STA thread so I can get past this
> error?

This threading problem has been beaten to death:

- you cannot (1) create the COM object in the Main of the
  service and access this object from one of the OnXyz
  methods, because these methods are called from another
  thread than the main thread. STA COM objects have
  a strong thread affinity.

  (1) if you manage to get this working, the certain
  STA COM object has a registered marshaller. However,
  every call of its methods will be very slow.

- you cannot create the COM object from one of
  the OnXyz methods unless you consume the object in
  OnXyz and don't need its reference after the call
  terminates.
  To make this run, you need to set the STA state of
  the thread with

    Thread.CurrentThread.ApartmentState =
      ApartmentState.STA

  from within the OnXyz method, of course.

If you need to create a STA COM object from within
OnStart _and_ if you need to keep its reference
after OnStart terminates, you have to start a
new thread from OnStart and create the COM object
from this new thread.

Rob
fdeckerNOSPAMM@aol.com - 11 Nov 2005 23:39 GMT
Rob,

> This threading problem has been beaten to death:

Maybe so, but 90% of the people just put <STAThread> _ in front of main
and it solves there problem.  As I said, if I use the files created by
TLBImp.exe I can dynamically create the controls just fine, however
only 1 event will work.  Attempting to add more event handlers to the
control causes the error I mentioned.  No one seems to be able to say
in code how to make this work.

If I add the reference to the AXImp.exe created file, then that wrapper
gives me all the events, but it won't work in a MTA.  So I either need
to figure out how to get the first option working by just getting
access to the other events somehow, or I need to put it into a thread.
However, all of the examples I can find, show a very simple process in
1 subroutine that they spawn into a thread.  I need to run and entire
APPLICATION in a thread if I am going to try this method.

> - you cannot create the COM object from one of
>    the OnXyz methods unless you consume the object in
[quoted text clipped - 7 lines]
>
>    from within the OnXyz method, of course.

Ok, so where does this code go?  Can it go in the OnStart Method?  Or
do I have OnStart call my own procedure?  In any case I have tried two
other ways of making the thread STA and can't figure out how to do it.
Where does the code go?

OnStart()
  Thread.CurrentThread.ApartmentState = ApartmentState.STA   ?

I had:

<STAThread> _
OnStart

I also tried to put that code in Main and everywhere else I could think
of, it did't work, I get the same threading error.

As for trying to create things in a new thread, please forgive in
advance my ignorance on threading.  But I have multiple controls that
have events, properties and methods.  So I instantiate the main control
and set it's properties.  I execute one of it's methods to connect to a
device.  When it connects, the connected event fires.  There is code in
the connected event that sends data over the line.  If a disconnect
occurs for any reason, the disconnected event fires.  Where does all
this code go?  Does just creating the component in a thread
automatically make all it's event handlers and code operate in that
thread?

   Protected Overrides Sub OnStart(ByVal args() As String)
      Dim t As Thread
           t = New Thread(AddressOf Me.myProcess)
           t.Start()
   end sub

  Private Sub myProcess()
      myOCX = New AxmyObject.myOCX
      myOCX.Enabled = True
      myOCX.ConnectToDevice()
  end sub

  Private Sub Connected()
     myOCX.SendData()
     ... lots more code
  end sub

  Private Sub Disconnected()
    ... do some more stuff
  end sub

Fred
Willy Denoyette [MVP] - 12 Nov 2005 22:31 GMT
1. STAThread attribute is not needed on Main in a Windows Service, you
service code should run in a thread spawned from OnStart, this thread needs
to be initialized for STA before starting the thread:
   t.ApartmentState = ApartmentState.STA
   t.Start()
2. You should not set a reference to the AXImp.exe generated stuff, this is
only needed when you want to host the control in a control container (like a
Windows Form), that container needs to run in an STA thread (all AX controls
need an STA thread to run on).
3. When you want to use an AX control from a Windows Service, you need to
set a reference to the tlbimp.exe generated Interop assembly, but keep in
mind that hosting AX controls (especially Full Controls are problematic)  in
Windows Services is not a supported scenario, so use it at your own risk.

Willy.

> Rob,
>
[quoted text clipped - 76 lines]
>
> Fred
fdeckerNOSPAMM@aol.com - 14 Nov 2005 19:34 GMT
I really appreciate the help.  I think I am getting close.  Ok, here is
my dilemna, there is a difference in the way .NET handles events and
all else before it.  I believe that .NET must have an event sink for
each event and normal ActiveX implementations such as VB.NET have only
one event sink, the form.  Somehow it allows multiple events to fire
using one sink.  I believe the AxImport wrapper must simulate this and
translates the one sink to multiple sinks.  This is my first of two
problems.

1. If I try to reference the component without using Ax as in "Dim
withevents myOCX.myControl", no matter where I put it or how I use it,
I get the 0x80040202 error as soon as I try to put more than one event
handler in the code for that component.  The program will work
perfectly right out of Start() if I want it to if I could live with
only one event handler.

2. So I therefore try to Dim WithEvents AxmyOCX.AxmyControl.  Now I use
the Ax wrapper.  Now I get no errors, but I also get no events. :)  So
I try to create a form too and put the controls on a form.  I must be
missing some key piece like loading the form or starting a message
pump.  I also have to use the
((System.ComponentModel.ISupportInitialize)(myOCX)).BeginInit() and
EndInit commands or I get an error.  Here is my code, it must be a mess
by now I've tried so many different things:

Private WithEvents myOCX As AxMyControls.AxMyOCX

Private Sub OnStart()
      Dim t As Thread
       t = New Thread(AddressOf Me.myStart)
       t.ApartmentState = ApartmentState.STA
       t.Start()
End Sub

Private Sub myStart()
       Try
           myForm = New System.Windows.Forms.Form
           System.Windows.Forms.Application.Run(myForm)
           myOCX = New AxMyControls.AxMyOCX
           CType(myOCX,
System.ComponentModel.ISupportInitialize).BeginInit()
               myForm.Controls.Add(myOCX)
           CType(myOCX,
System.ComponentModel.ISupportInitialize).EndInit()
           AddHandler myOCX.OnEvent1, AddressOf myOCX_OnEvent2
           AddHandler myOCX.OnEvent2, AddressOf myOCX_OnEvent2

           myOCX.Enabled = True
       Catch e As Exception
           ' error code here
       End Try

Thanks... Fred

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.