Form button not redrawing when form is put over it

lonewolf32

Newcomer
Joined
May 3, 2006
Messages
17
I created a simple new Windows Form project in VS2005 Sp1 (C#), and all the form does is have a button that opens a VB6 COM object, which also has a form. The problem is, when I move the top VB6 form around and over the .NET form, the button on the .NET form disappears and doesn't come back.

I will post a series of screenshots to demonstrate.

Once I close the VB6 form, then the button returns.

Any ideas? I am new to .NET forms programming - hopefully its something simple.

Thanks.
 

Attachments

Just wanted to add a follow-up comment. This only happens when I put up a VB6 form in front of it. If I put up another .NET form this does not occur. But I still have the problem as I do not want to rewrite my VB6 code yet.

Thanks.
 
Threading

As a guess, I would say that the VB6 COM object is launched on the UI thread of the .Net process, meaning the .Net form cannot respond to window messages (such as a paint message). To overcome this, you could try launching the COM object on a different thread.

Visual Basic:
Imports System.Threading


Private Sub ThreadProc(ByVal state As Object)
    'Code to start VB6 COM object
End Sub

Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click
    'Call ThreadProc on a seperate thread (using ThreadPool)
    ThreadPool.QueueUserWorkItem(AddressOf ThreadProc)
End Sub

If the COM object is to be displayed modally (so that the .Net form cannot be used) then you can disable the .Net form while the COM object is shown and then enable it again afterwards.

Good luck :cool:
 
I am trying to implement this threading suggestion. I got it halfway working (the thread starts and the form distortion is gone) - but I need the originating thread to stop working until my VB6 thread is done. I am trying to implement a Mutex, but I am having no success. Here is the code, what am I doing wrong? (Note that I tried both ThreadPool.QueueUserWorkItem, and a simple Thread.Start)

Code:
private static Mutex mut = new Mutex();
private void btnMEU_Click(object sender, EventArgs e)
        {
            // Queue the task.
            //ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc));
            Thread myThread = new Thread(new ThreadStart(ThreadProc));
            myThread.Start();
            
// Allow new thread to start and claim mutex
            Thread.Sleep(1000);
// Now wait for the mutex to be released
            mut.WaitOne();

        }

        // This thread procedure performs the task.
        private static void ThreadProc()
        {
// Claim the mutex so the originating thread has to wait
            mut.WaitOne();
// Do my work

// Release the mutex
            mut.ReleaseMutex();
        }
 
We may have to scratch that theory completely - I just tried bringing up another VB6 COM form, and this time the distortion appears on my COM form! Note the weird black boxes. (see attachment) This form shows up fine when I open it from a VB6 project.
Here is the code that brings up that COM object (it is included as a Reference obviously):
Code:
        private void btnMEU_Click(object sender, EventArgs e)
        {
            ModelExtractorUtility.Launcher meu = new ModelExtractorUtility.Launcher();
            meu.ApplicationID = Singleton.Instance.ApplicationID;
            meu.LogCfgFile = Singleton.Instance.LogCfgFile;
            meu.WorkingDirectory = Singleton.Instance.WorkingDirectory;
            meu.Launch();
            }

Could this still be a threading issue?
 

Attachments

Mutex bad, Invoke good!

Regarding the code which uses a Mutex, this is not the correct way to solve the problem - the original issue with the button not redrawing was because the UI thread (responsible for the drawing) was being tied up by the COM object. Causing it to wait on a Mutex is no better - while the UI thread is waiting it will be unable to handle drawing or other messages.

A much better approach would be to invoke a delegate once the 'work' has been completed. The Form has an Invoke method which will call the specified delegate on the UI thread. So, your code might look something like:

Code:
private delegate void WorkCompletedHandler();

private void btnMEU_Click(object sender, EventArgs e)
{
    //Queue the task.
    ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc));
    //Disable the form
    this.Enabled = false;
}

private void WorkCompleted()
{
    //Peform final processing

    //Enable the form
    this.Enabled = true;
}

// This thread procedure performs the task.
private static void ThreadProc(object status)
{
    //Do my work

    //Invoke WorkCompleted on UI thread to signal work is complete
    this.Invoke(new WorkCompletedHandler(WorkCompleted));
}

Alternatively, you could just use the BackgroundWorker form component, which handles the intricacies of threading for you.

As far as your latest issue is concerned, I suppose it is possible that it is another threading issue, but that seems unlikely. Does the COM form remain responsive to input, despite the black boxes?
 
This method seems to have done the trick. Other then having to remove the "static" key word from the ThreadProc declaration (can't use "this" in static method), it worked just as written.

I tried it in both situations, and they appear to be working now with no draw problems.

Thanks!!!!

Here is the final code.
Code:
        private delegate void WorkCompletedHandler();

        private void WorkCompleted()
        {
            //Peform final processing
            Singleton.Instance.InitLogging();
            Singleton.Instance.LogFlow("Returning from COM app");

            //Enable the form
            this.Enabled = true;
        }

        private void btnMEU_Click(object sender, EventArgs e)
        {
            Singleton.Instance.LogFlow("Starting COM app");
            Singleton.Instance.TermLogging();

            // Queue the task.
            ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc));
            this.Enabled = false;
            }

        private void ThreadProc(object state)
        {
            ModelExtractorUtility.Launcher meu = new ModelExtractorUtility.Launcher();
            meu.ApplicationID = Singleton.Instance.ApplicationID;
            meu.LogCfgFile = Singleton.Instance.LogCfgFile;
            meu.WorkingDirectory = Singleton.Instance.WorkingDirectory;
            meu.Launch();

            this.Invoke(new WorkCompletedHandler(WorkCompleted));
        }
 
Back
Top