cancel
Showing results for 
Search instead for 
Did you mean: 

Using modal windows forms in B1 9.0

former_member445524
Participant
0 Kudos

Hello all,

Our code to show a Windows dialog to open files (OpenFileDialog) in B1 has stopped working as of B1 version 9.0.

To bind the dialog to the B1 window, we obtain the latter using WinAPI's GetForegroundWindow(), and pass it as the owner window to OpenFileDialog.ShowDialog(owner).

It works well in B1 2004 to 8.8, but in 9.0 the ShowDialog() function returns immediately without showing the window. The existing threads on SCN recommend ether this method (using the B1 window as owner) or ugly workarounds, but the ScreenPainter addon has a correct open file dialog even in B1 9.0. Do you know how to contanct its developers with this question? So simple an operation should be no secret...

Accepted Solutions (0)

Answers (4)

Answers (4)

Former Member

Try this code

#region class WindowWrapper : for OpenFileDialog

    public class WindowWrapper : System.Windows.Forms.IWin32Window

    {

        private IntPtr _hwnd;

        // Property

        public virtual IntPtr Handle

        {

            get { return _hwnd; }

        }

        // Constructor

        public WindowWrapper(IntPtr handle)

        {

            _hwnd = handle;

        }

    }

    #endregion WindowWrapper

    #region class GetFileNameClass : for OpenFileDialog

    public class GetFileNameClass

    {

        [System.Runtime.InteropServices.DllImport("user32.dll")]

        private static extern IntPtr GetForegroundWindow();

        System.Windows.Forms.OpenFileDialog _oFileDialog;

        // Properties

        public string FileName

        {

            get { return _oFileDialog.FileName; }

            set { _oFileDialog.FileName = value; }

        }

        public string Filter

        {

            get { return _oFileDialog.Filter; }

            set { _oFileDialog.Filter = value; }

        }

        public string InitialDirectory

        {

            get { return _oFileDialog.InitialDirectory; }

            set { _oFileDialog.InitialDirectory = value; }

        }

        // Constructor

        public GetFileNameClass()

        {

            _oFileDialog = new System.Windows.Forms.OpenFileDialog();

        }

        // Methods

        public void GetFileName()

        {

            IntPtr ptr = GetForegroundWindow();

            WindowWrapper oWindow = new WindowWrapper(ptr);

            if (_oFileDialog.ShowDialog(oWindow) != System.Windows.Forms.DialogResult.OK)

            {

                _oFileDialog.FileName = string.Empty;

            }

            oWindow = null;

        } // End of GetFileName

    }

    #endregion class GetFileNameClass : for OpenFileDialog

public static string AddOnOpenFileDialogBox(string initialDirectory)

        {

            GetFileNameClass oGetFileName = new GetFileNameClass();

            oGetFileName.Filter = "All files (*.*)|*.*";

            oGetFileName.InitialDirectory = initialDirectory;

            //oGetFileName.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal);

            System.Threading.Thread threadGetFile = new System.Threading.Thread(new System.Threading.ThreadStart(oGetFileName.GetFileName));

            threadGetFile.SetApartmentState(System.Threading.ApartmentState.STA);

            string strValue = "";

            try

            {

                threadGetFile.Start();

                //Wait for thread to get started

                while (!threadGetFile.IsAlive) ;

                //Wait a sec more

                System.Threading.Thread.Sleep(1);

                //Wait for thread to end

                threadGetFile.Join();

                //Use file name as you will here

                strValue = oGetFileName.FileName;

            }

            catch (Exception ex)

            {

                System.Windows.Forms.MessageBox.Show(ex.Message);

            }

            threadGetFile = null;

            oGetFileName = null;

            return strValue;

        }

hopefully, it is useful for you.

former_member445524
Participant
0 Kudos

Edy and Chan Kyu Kim, your suggestions didn't help, but SAP have acknowledged this problem as a bug in B1 x64 and in SAP note 1960726 have announced its removal in PL09.  I have not tested it yet though.

edy_simon
Active Contributor
0 Kudos

Hi Anton,
I just encountered this problem on 1 of my client's PC running windows 7 64 bit.

In my case, the thread started and the main thread did not wait for the dialog thread.

Thus whatever file the user select did not get into my variable.

I don't know if this can help you.

Can you try to put a thread.sleep(500) in your code below ?

static string ShowDialog()

  { OpenFileDialog ofd = new OpenFileDialog();

  Thread dlgThread = new Thread( showDialog );

  dlgThread.SetApartmentState( ApartmentState.STA );

  dlgThread.Start(ofd);

            System.Threading.Thread.Sleep(500);                //<--------- HERE

  dlgThread.Join();

  return ofd.FileName;

  }

I know it is does not make any sense, but just try and see if it works for you..

Regards

Edy

edy_simon
Active Contributor
0 Kudos

Hi Anton,

I ran another test.

It looks like the problem is caused by calling the ShowDialog() method after the SBO messagebox object. Not sure why, maybe you can log a support ?

If i move this ShowDialog calling to any other event, it works.

Here I modify your code to add a menu under the 'Module' tool strip menu, and call the ShowDialog on after the menu pressed.

Move the uiApp declaration to bein the global of the  'Program' class.


class Program

{

        public static B1App uiApp;

Add a menu and the event declaration


{

                Console.WriteLine("Prompting user to start the test. Please, so go to B1 press OK.");

                //uiApp.MessageBox("Press OK to test the OpenFileDialog.", 1, "OK", "", "");

                uiApp.MenuEvent += uiApp_MenuEvent;

                if(!uiApp.Menus.Exists("mnuTest") )             

                    uiApp.Menus.Item("43520").SubMenus.Add("mnuTest", "Test File Dialog", BoMenuType.mt_STRING, 99);

}

Here is the menu handler


        static void uiApp_MenuEvent(ref MenuEvent pVal, out bool BubbleEvent)

        {

            BubbleEvent = true;

            string fileName = "";

            if (pVal.BeforeAction)

               return;

            switch (pVal.MenuUID)

            {

                case "mnuTest":

                    fileName = ShowDialog();

                    uiApp.StatusBar.SetText(fileName, BoMessageTime.bmt_Short, BoStatusBarMessageType.smt_Success);

                    break;

            }

        }

Regards

Edy

former_member445524
Participant
0 Kudos

Hello, Edy.

I couldn't reproduce your results. I have modified my project to show the dialog upon a click on a menu and have removed the preceeding call to MessageBox(), but the test still fails. The new version is here:

http://s000.tinyupload.com/?file_id=06996446429830285441

edy_simon
Active Contributor
0 Kudos

Hi Anton,

not sure if it makes any difference,

but i updated your sapbouicom reference to the 64bit version,

change the target platform to x64.

change the target framework to .net 4.0

And recompile.

Can you try if any result?

regards,

edy

former_member445524
Participant
0 Kudos

Hello, Edy.

Do you mean that after those actions you listed my solution started to work on B1 x64?  You said you "updated [my] sapbouicom reference to the 64bit version". How did you do that? I think that only one SAPbouiCOM is available in the COM tab of the "Add reference" window, and the exact version is chosen at run-time depending on whether the B1 client is x64 or x86.

edy_simon
Active Contributor
0 Kudos

Hi Anton,

I mean, I did that on your first sample.

On your second sample, It ran out of the box for me in 64 bit SBO.

I did not change anything.

My Configuration was :

Windows 8 64 bit.

VS2012

SBO9 PL8 32bit + 64 bit installed.

SBO9 64bit is running for the testing.

On your other question,

There will be always one SAPbouiCOM + SAPbobsCOM on your COM reference list.

But you can always click browse and manually select the dll.

The 32 bit boui should be in the folder C:\Program Files (x86)\SAP\SAP Business One

The 64 bit should be in the folder C:\Program Files\SAP\SAP Business One

Regards
Edy

former_member445524
Participant
0 Kudos

Thank you very much for testing, Edy.  My configuration is:

Windows 2008 R2 SP1 64 bit

B1 9.0 PL 08 x64

I don't know what may be causing the problem on my side and will write to B1 support.

As for the SAPbouiCOM reference, the 32-bit version doesn't even connect the the 64-bit client, so that can't be the culprit.

Former Member
0 Kudos

Are you using window forms on SAP Add-on? If no, you can check C:\Program Files (x86)\SAP\SAP Business One SDK\Samples\COM UI\VB.NET\12.ModalForm

former_member445524
Participant
0 Kudos

Hello, Brian.

That simple SDK sample does nothing but block all events execept those on the form. It has nothing to do with a true modal form that is emulated, for example, here:

In my case, I want to show a modal System.Windows.Forms.OpenFileDialog using its ShowDialog() method. It used to work with B1 prior to 9.0.

Former Member
0 Kudos

Hmm. I think I have a project that can browse a xlsx file and upload to a document. I've used like this.

  Dim oBrowse As New System.Threading.Thread(AddressOf BrowseFile)

                                    oBrowse.SetApartmentState(Threading.ApartmentState.STA)

                                    oBrowse.Start()

                                    oBrowse.Join()

Private Sub BrowseFile()

        Try

            Dim oOpenFile As New frmOpen 'VB.NET FORM

            oOpenFile.Show()

            oOpenFile.Hide()

            oOpenFile.TopMost = True

            oOpenFile.OpenFile.Title = "Open Excel File"

            If oOpenFile.OpenFile.ShowDialog Then

                oFilePath = oOpenFile.OpenFile.FileName

          

            End If

        Catch ex As Exception

            SAP_APP.SetMessage(ex, SAPbouiCOM.BoStatusBarMessageType.smt_Error)

        End Try

    End Sub

former_member445524
Participant
0 Kudos

Bryan, you use the parameterless overload of ShowDialog(), which does not block B1's main window. I know this works, but it is but a hack. In B1 versions 2004 to 8.8 ShowDialog(owner) used to work well and as expected—blocking B1's window.

edy_simon
Active Contributor
0 Kudos

HI Anton,

as the showdialog(owner) is .net, there should not any reason why it stop working.

in fact, i am still using it in 9.0.

do you mind sharing your code so we can take a look together?

regards,

Edy.

former_member445524
Participant
0 Kudos

Edy, here's a minimal working example:

http://pastebin.com/4wBgipBv

edy_simon
Active Contributor
0 Kudos

Hi Anton,

Have you tried your code in other machine ?

It is running perfectly on my PC.

Windows 8.

SBO 9 PL7

VS2005/VS2012

Regards

Edy

former_member445524
Participant
0 Kudos

Thank you very much, Edy.  The problem is present in B1 9.0. PL 05, but is absent in B1 9.0 PL 08.  It must have been fixed somewhere in between.

former_member445524
Participant
0 Kudos

Edy, did you test it with 64- or 32-bit version of the B1 client? It doesn't seem to work on x64...

edy_simon
Active Contributor
0 Kudos

Hi Anton,

I tried your code under 32 bit B1 Client.

But I have a similar code running in SBO 9 PL 6 64 bit; Windows 8; Visual Studio 2012.


Regards
Edy

former_member445524
Participant
0 Kudos

Edy, my code does not work with the 64-bit client PL05 and PL08. I think that you use the parameterless overload of the ShowDialog() method, while I use ShowDialog(owner), passing it the handle of the B1 main window.

edy_simon
Active Contributor
0 Kudos

Hi Anton,

i am using the method with owner parameter.

regards,

Edy.

former_member445524
Participant
0 Kudos

Hello, Edy

Could you please test my project with both x64 and x86 versions of B1 9.0? Here it is:

http://tinyurl.com/lbhr8ww

edy_simon
Active Contributor
0 Kudos

Hi Anton,

You are right as it is not running under x64. SBO 9 PL 8.

My SBO just crashed right after the dialog opened.

As my schdedule is a bit tight,  I will try to play around it with when I have time and post it here.

Regards

Edy

edy_simon
Active Contributor
0 Kudos

Hi Anton,

My quick test on my customization using x64 runs without problem.

Wonder where the difference is....

Will post it here once I found out.

Regards

Edy

Former Member
0 Kudos

hi

Windows7 64bit

SAP B1 9.0 PL06 32bit

Download and test results file runs without problem.

former_member445524
Participant
0 Kudos

Thank you, Edy and Chan Kyu Kim, for your feedback. Chan Kyu KIm: note that I have no problems with running that code on the 32-bit client, and only on the 64-bit client it doesn't work for me.

Former Member
0 Kudos

Hmm.
I think the problem client 64bit
Crystal Reports export to 32bit client
I the same thread is used.

Thread oThread = new Thread (new ParameterizedThreadStart (ReportViewer));
oThread.SetApartmentState (ApartmentState.STA);
oThread.Start (pForm);
oThread.Join ();

I can not see the 64bit client, it is inconvenient to the test.
Sorry