visual-studio-2015vstooutlook-addinoutlook-2010findwindow

Outlook 2010 plugin wrong 32770 window


I'm developing a custom address dialog for Outlook 2010, following the sample of Helmut Oberdan published here

http://www.codeproject.com/Articles/21288/Customize-the-built-in-Outlook-Select-Names-dialog

I've migrated the project to VS2015 with framework 4.5 but I'm in trouble with the findwindow function

IntPtr hBuiltInDialog = WinApiProvider.FindWindow("#32770", "");

on some computer (mine) works well and on some other (customer) it doesn't. It seems that the function finds another 32770 window that is not the Outlook's one, I've tryed to enumerate all the 32770 windows but when the InspectorWrapper_Deactivate function fires up, my 32770 window is not present in the list. A strange behavior occurs, if I put a messagebox in the deactivate function it pops up twice and after the second time the right window gets catched and my custom dialog opens.

Here is the InspectorWrapper_Deactivate function

void InspectorWrapper_Deactivate()
{
    _showOwnDialogOnActivate = false;

    // If there is an invisible ghost Window out there - close it
    if (_hWndInvisibleWindow != IntPtr.Zero) WinApiProvider.SendMessage(_hWndInvisibleWindow, WinApiProvider.WM_SYSCOMMAND, WinApiProvider.SC_CLOSE, 0);

    IntPtr hBuiltInDialog = WinApiProvider.FindWindow("#32770", "");
    if (hBuiltInDialog != IntPtr.Zero)
    {
        // ok, found one
        // let's see what childwindows are there
        List<IntPtr> childWindows = WinApiProvider.EnumChildWindows(hBuiltInDialog);
        // Let's get a list of captions for the child windows
        List<string> childWindowNames = WinApiProvider.GetWindowNames(childWindows);

        //MessageBox.Show("Contact");

        // now check some criteria to identify the build in dialog..
        int languageId = Inspector.Application.LanguageSettings.get_LanguageID(Microsoft.Office.Core.MsoAppLanguageID.msoLanguageIDUI);
        switch (languageId)
        {
            case 1031:
                // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                // !!! This part is only valid for German Outlook 2007 Version !!!
                // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                if (!childWindowNames.Contains("Nur N&ame")) return;
                if (!childWindowNames.Contains("&Mehr Spalten")) return;
                if (!childWindowNames.Contains("A&dressbuch")) return;
                // you can even check more criteria
                break;

            case 1033:
                // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                // !!! This part is only valid for english Outlook 2007 Version !!!
                // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                if (!childWindowNames.Contains("&Name only")) return;
                if (!childWindowNames.Contains("Mo&re columns")) return;
                if (!childWindowNames.Contains("A&ddress Book")) return;
                break;

            case 1040:
                // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                // !!! This part is only valid for italian Outlook 2007 Version !!!
                // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                if (!childWindowNames.Contains("Solo n&ome")) return;
                if (!childWindowNames.Contains("Altre &colonne")) return;
                if (!childWindowNames.Contains("R&ubrica")) return;
                break;
            // TODO: place your language here....

            default:
                return;
        }

        // OK - we have the built in Recipient Dialog
        // Create a new invisible window
        _hWndInvisibleWindow = WinApiProvider.CreateWindowEx(0, "Static", "BriaSOFT", 0, 0, 0, 0, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); 

        // use this window as new Parent for the original Dialog
        WinApiProvider.SetParent(hBuiltInDialog, _hWndInvisibleWindow);

        WinApiProvider.SendMessage(hBuiltInDialog, WinApiProvider.WM_SYSCOMMAND, WinApiProvider.SC_CLOSE, 0);
        // When our INspector becomes active again, we should show our own Dialog
        _showOwnDialogOnActivate = true;
    }
}

any suggestion will be really appreciate. Thanks Flavio

Following Dmitry suggestion but still not able to find the 32770 window, because it has empty window name (even if it exists)

    string windowName;
    IntPtr outlookHandle = (IntPtr)0;
    IOleWindow window = Inspector as IOleWindow;
    if (window != null)
    {
        window.GetWindow(out outlookHandle);
        List<IntPtr> subWindows = WinApiProvider.EnumChildWindows(outlookHandle);
        foreach (IntPtr hand in subWindows)
        {
            StringBuilder ClassName = new StringBuilder(256);
            int nRet = WinApiProvider.GetClassName(hand, ClassName, ClassName.Capacity);
            if (nRet != 0)
            {
                if (ClassName.ToString().Contains("#32770"))
                {
                    windowName = WinApiProvider.GetWindowName(hand);
                    if (windowName.Contains("Seleziona nomi"))
                    {
                        hBuiltInDialog = hand;
                        break;
                    }
                }
            }
        }
    }


Solution

  • After days of test and tryes the solution (suggested by Microsoft) has been to insert a separate thread, started from the inspector and auto terminated when the window is found.

    Inside the inspector_deactivate

        if (workerThread.ThreadState == ThreadState.Unstarted)
        {
            // Start the worker thread.
            workerThread.Start();
    
            while (!workerThread.IsAlive) ;
    
            // Put the main thread to sleep for 1 millisecond to
            // allow the worker thread to do some work:
            Thread.Sleep(1);
        }
        else if (!workerThread.IsAlive)
        {
            workerObject = new Worker(Inspector);
            workerThread = new Thread(workerObject.DoWork);
            workerThread.Start();
        }
    

    and inside the thread

       public Worker(Outlook.Inspector insp)
        {
            Inspector = insp;
            _shouldStop = false;
        }
    
        public void DoWork()
        {
            while (!_shouldStop)
            {
                SubstituteWindow();
            }
        }