on 11-28-2013 1:22 PM
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...
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.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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:
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.
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
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.
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
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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.
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
Edy, here's a minimal working example:
Hello, Edy
Could you please test my project with both x64 and x86 versions of B1 9.0? Here it is:
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
User | Count |
---|---|
95 | |
11 | |
10 | |
6 | |
5 | |
5 | |
4 | |
3 | |
3 | |
3 |
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.