已回答 停靠的应用程序无法启动SSRS报告

5银狐

会员
已加入
2020年4月30日
留言内容
5
编程经验
10+
嗨,我有一个C#Windows应用程序(app1),其菜单栏的面板上带有按钮。之所以这样做,是因为还可以从另一个应用程序(菜单1)启动该应用程序,该应用程序会将app1停靠在选项卡控件中。 (停靠应用程序时,普通的工具栏或菜单栏将变得无响应。(已记录的错误))。 app1中的菜单按钮之一将启动带有报告列表的上下文菜单。通过单独运行App1,我可以启动任何报告,这些报告将显示在默认浏览器中。但是,在menu1停靠app1并启动报告之后,什么都没有发生,直到关闭app1,此后该报告将显示并停靠在menu1的选项卡控件中。

我想知道是否有人知道"serial"行为,是否有什么可以解决的?有没有办法"break"app1流程和报告流程之间的链接?可以在正在运行的进程上更改父进程吗?我将非常感谢那些非常聪明的人的任何想法。

PS:最新的VS,操作系统= Windows 10,使用.NET Framework 4。
 

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,919
地点
英国
编程经验
10+
欢迎来到论坛。

您说的这个有记录的错误是什么? :- (已记录的错误)

我不是很了解您的逻辑。您不能让应用程序在应用程序内部运行...我假设您是在谈论表单,而不是在谈论应用程序,在这种情况下,您需要非常详细地说明自己创建的功能以及正在描述和尝试使用的功能,并确切说明您要实现的功能以及原因。为了我们帮助您。您需要绘制完整清晰的图片,以供我们理解。如果您将调试代码并查看其确切卡在哪里,或尝试确定代码为何停止执行,并且可以使用调试器执行此操作,则也将很有帮助。这就是它的目的。您可以在我的签名中找到调试教程。

如果您设法确定导致您遇到问题的相关代码,请发布该代码,以便我们进行分析并尝试确定任何可能的缺陷。如果您的应用程序被锁定。可能是由于您正在UI线程上进行工作,这导致它没有响应。这只是我在黑暗中盲目地刺,因为您的问题可能是某些方法未在其自己的线程上执行的结果。
我这样做是因为该应用程序也可以从其他应用程序启动(菜单1)
什么?请解释。什么是menu1,您是如何创建的?

menu1不太可能是一个应用程序。可能是一个单独表单上的控件。为什么要允许外部应用程序充当启动其他应用程序的菜单。我只是继续写你写的东西,这似乎是一个非常有缺陷的设计。
 

5银狐

会员
已加入
2020年4月30日
留言内容
5
编程经验
10+
是的,您可以让应用程序在其他应用程序中运行。从第一个应用程序启动第二个应用程序,找到第二个应用程序主窗体,并将其停靠在第一个应用程序的控件中。因此,在我的情况下,第一个应用程序是C#菜单应用程序,第二个应用程序也是C#应用程序。 (我可以启动记事本作为第二个应用程序,这将起作用)。什么都没有挂。

我不知道如何更好地解释它,但让我再试一次:
我有2个应用程序:一个C#Windows应用程序(树视图菜单应用程序),我们称之为MENU。第二个应用程序是带有按钮和网格的C#Windows应用程序,某些按钮可以启动SSRS报告,我们将其称为APP。

如果我直接启动APP并单击“报告”按钮,它将以单独的过程启动SSRS报告,并按预期在浏览器中显示。
如果我启动MENU并选择APP,它将启动APP并将其停靠在MENU选项卡控件中的新选项卡中。如果现在单击“报告”按钮,它将作为第三过程启动SSRS报告,但是直到关闭APP才能看到它。它必须与更改APP的主要形式有关以允许对接。我只是希望其他人可以做类似的事情,并且可以指导我克服这个陷阱。

至于停靠应用程序时出现的菜单栏错误:我已经没有URL了,但这是事实,并且可以轻松复制。
 

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,919
地点
英国
编程经验
10+
是的,您可以让应用程序在其他应用程序中运行。从第一个应用程序启动第二个应用程序,找到第二个应用程序主窗体,并将其停靠在第一个应用程序的控件中。因此,在我的情况下,第一个应用程序是C#菜单应用程序,第二个应用程序也是C#应用程序。 (我可以启动记事本作为第二个应用程序,这将起作用)。什么都没有挂。
不,您不能...从技术上讲,可以通过提供要使用的应用程序的句柄并将其传递给控件来实现。但是,实际上不建议这样做,除非我仍然对您有误解,否则不建议这样做。因此实际上并不是您不能做的那么多,但实际上不建议这样做。我不确定为什么要以两种不同的形式运行它们时,为什么要让两个单独的Windows应用程序在彼此外部运行。这要求您使用pinvoke并开始在API上戳。你做了这样的事吗? :
C#:
        [DllImport("user32.dll")]
        static extern IntPtr 家长(IntPtr hWndsub, IntPtr hWndPrime);
        private void button1_Click(object sender, EventArgs e)
        {
            Process new_process = Process.Start("write.exe");
            Thread.Sleep(1000);
            家长(new_process.MainWindowHandle, tabControl1.Handle);
        }
我只能想象如果这是您的情况,您很可能在一家公司工作,这是其设置的一部分。因为这是公司公司的愚蠢行为。对您或您可能为之工作的人没有冒犯。只是我多年来在公司工作的经历,它使我想起了他们有时是如何做的。通常是出于荒谬的原因。与其编辑某些内容并扩展到主要应用程序功能,不如说它们需要您使用句柄。通常,其他工作流程不会中断或需要更换。如果是这样,我感到您很痛苦。

如果以上内容与您正在执行的操作更接近,我们将需要查看如何调用另一个窗口并在将其放置在控件中时对其进行控制。我无法理解为什么您会使用一些可以通过使用单个表单进行简化的东西来朝这个方向发展。但是,如果这是您需要的指导,我会为您提供帮助。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,490
地点
弗吉尼亚州切萨皮克
编程经验
10+
在上面的示例中,您是在启动记事本吗?您是说关闭应用程序时,记事本也会关闭吗?

我认为您需要向我们展示您的代码,因为在正常的Windows应用程序中,您无法启动另一个应用程序并成为该其他应用程序的父窗口,并且所有这些窗口都停靠在您的应用程序内部。为此,它涉及一些Win32 API黑客,如果您跨越32位和64位边界,或者介于升高的安全上下文和不升高的安全上下文之间,则涉及更多的黑客。

是的,您可以从现有应用程序中启动另一个应用程序。 Windows完全支持该功能,并且Windows Explorer,CMD窗口,PowerShell,计划任务管理器和其他工具的工作方式也完全受此支持。但是它们也遵循正常的Windows约定,并且不要使子应用程序窗口成为父应用程序的一部分。 Windows违反其自己的UI规则时,会有一些例外。例如,当您在小样本/缩略图窗口中预览屏幕保护程序时,Windows实际上会启动另一个应用程序-屏幕保护程序-然后告诉该应用程序使用特定的窗口句柄进行绘制以进行预览。
 

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,919
地点
英国
编程经验
10+
在上面的示例中,您是在启动记事本吗?您是说关闭应用程序时,记事本也会关闭吗?
顺便说一句,这是正常的和预期的行为。通过执行我发布的上述API代码,您在主应用程序中打开的窗口会将您打开的进程置于您的应用程序名称下,作为主应用程序的子进程。

Screenshot_123.jpg
 

5银狐

会员
已加入
2020年4月30日
留言内容
5
编程经验
10+
顺便说一句,这是正常的和预期的行为。通过执行我发布的上述API代码,您在主应用程序中打开的窗口会将您打开的进程置于您的应用程序名称下,作为主应用程序的子进程。

查看附件913

好吧,我们需要一个可以启动任何应用程序的中央菜单系统。问题实际上是相反的。我们需要启动第三方应用程序。我们还使用它来克服终端服务器上的缓存问题。我们只有10%的员工使用了终端服务,但是现在,在锁定期间,有99%的员工使用了终端服务。我们不会将程序部署到PC上,而是部署到网络共享上。现在在终端服务器上,这会引起问题,因为如果用户打开了程序,则其他每个打开该程序的用户都将打开缓存的版本。因此,除非所有人都关闭该程序,否则除非该程序位于终端服务器的本地驱动器上,否则将获取最新版本。因此,我们现在部署到网络共享和终端服务器的本地驱动器。此菜单检测它是否正在终端服务器上运行,然后将在本地驱动器上执行程序。这也有助于部署新程序或删除程序。还有其他一些原因,例如文化因素,我不会厌烦您。

哦,是的,按照您的示例,这就是我正在做的事情,如果您关闭菜单,则该菜单打开的所有程序都会关闭,并且我检查您是否两次都不打开同一应用程序。就像在Skydivers示例中一样,我的问题是子程序启动另一个子程序时。在关闭第二个子程序显示的子程序之前,第二个子程序是不可见的。那么,如果第二个孩子是我自己的C#程序之一,我该如何启动它并显示它呢?

好,给您那个背景,这是执行程序的菜单内的代码。 MIP只是记住菜单项属性的一种结构。如果需要,将RealExecPath更改为执行路径到本地服务器。还有其他混乱情况,例如强迫Chrome和Firefox在新窗口中打开等。信息太多,信息太少?
C#:
       private void Execute()
        {
            MIP mip = (MIP)selectedNode.Tag;
            if (mip.HasExecRights)
            {
                string tabName = "";
                if (mip.ExecPath.Length > 0)
                {
                    string execPath = RealExecPath(mip.ExecPath);
                    Process process = null;
                    //We can execute, but is it running?
                    bool IsProcessRunning = false;
                    DataRow runningRow = GetRunningRow(execPath);
                    if (runningRow != null)
                    {
                        //It thinks it is already running - double check
                        string processName = runningRow["Processname"].ToString();
                        process = mip.RunningProcess;
                        process = GetProcessByName(processName);
                        if (process != null)
                        {
                            IsProcessRunning = true;
                        }
                        if (IsProcessRunning)
                        {
                            //Place focus on running process
                            tabName = runningRow["TabName"].ToString();
                            tab.SelectedTab = tab.TabPages[tabName];
                        }
                    }
                    if (!IsProcessRunning)
                    {
                        IntPtr appWin = IntPtr.Zero;
                        string chromeProfileNo = "";
                        try
                        {
                            //Start the process

                            ProcessStartInfo startInfo = new ProcessStartInfo();
                            if (execPath.StartsWith("http"))
                            {
                                switch (iriUtilities.DefaultBrowser())
                                {
                                    case "ChromeHTML":
                                        if (iriUtilities.IsChromeSSRSExtension())
                                        {
                                            int cnt = 0;
                                            foreach (DataRow row in RunningProcesses.Rows)
                                            {
                                                if (row["ExecPath"].ToString().StartsWith("http"))
                                                {
                                                    cnt++;
                                                }
                                            }
                                            chromeProfileNo = cnt.ToString();
                                            string profileFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData).Replace("Roaming", "Local");
                                            profileFolder += @"\Google\chrome\UserData" + chromeProfileNo + @"\";
                                            if (!Directory.Exists(profileFolder))
                                            {
                                                Directory.CreateDirectory(profileFolder);
                                            }
                                            string chromePath = iriUtilities.ChromePath() + "\\chrome.exe";
                                            startInfo.FileName = chromePath;
                                            startInfo.Arguments = execPath + " --user-data-dir=" + profileFolder;
                                        }
                                        else
                                        {
                                            iriUtilities.DisplayChromeMessage();
                                        }
                                        打破;
                                    case "FireFox":
                                        string fireFoxPath = iriUtilities.FireFoxPath() + "\\forefox.exe";
                                        startInfo.FileName = fireFoxPath;
                                        startInfo.Arguments = execPath + " -new-window";
                                        打破;
                                    default:
                                        startInfo.FileName = execPath;
                                        打破;
                                }
                            }
                            else
                            {
                                startInfo.FileName = execPath;
                            }
                            startInfo.WindowStyle = ProcessWindowStyle.Minimized;
                            process = new Process();
                            process.StartInfo = startInfo;
                            bool started = false;
                            try
                            {
                                started = process.Start();
                            }
                            catch
                            {
                                //Because some apps cannot start minimized
                                process.Close();
                                startInfo.WindowStyle = ProcessWindowStyle.Normal;
                                process = new Process();
                                process.StartInfo = startInfo;
                                started = process.Start();
                            }
                            Thread.Sleep(500);
                            while (process == null || process.MainWindowHandle == IntPtr.Zero || process.Id <= 0)
                            {
                                process.WaitForInputIdle();         //To check if process has started
                                Thread.Sleep(500);
                                Application.DoEvents();
                            }
                            try
                            {
                                Process p = Process.GetProcessById(process.Id);         //To double check if process has started
                                while (p == null)
                                {
                                    Thread.Sleep(500);
                                    p = Process.GetProcessById(process.Id);         //To double check if process has started
                                }
                            }
                            catch (InvalidOperationException)
                            {
                                started = false;
                            }
                            if (started)
                            {
                                mip.Running = true;
                                mip.RunningProcess = process;

                                //Create a new tab and dock process in it
                                int cnt = RunningProcesses.Rows.Count + 1;
                                tabName = "TabPage" + cnt.ToString();
                                tab.TabPages.Add(tabName, selectedNode.Text);
                                Thread.Sleep(500);
                                TabPage tabPage = null; ;
                                while (tabPage == null || tabPage.RecreatingHandle)
                                {
                                    Application.DoEvents();
                                    Thread.Sleep(500);
                                    tabPage = tab.TabPages[tabName];
                                }
                                Application.DoEvents();
                                //Find main window
                                while (appWin == null || appWin == IntPtr.Zero)
                                {
                                    Thread.Sleep(300);
                                    appWin = process.MainWindowHandle;
                                }
                                process.EnableRaisingEvents = true;
                                Thread.Sleep(300);
                                process.Exited += new EventHandler(Process_Exited);
                                Thread.Sleep(300);
                                startInfo.WindowStyle = ProcessWindowStyle.Maximized;
                                Thread.Sleep(300);

                                //Place process into tabPage
                                家长(appWin, tabPage.Handle);
                                SetWindowLong(appWin, GWL_STYLE, WS_VISIBLE & ~WS_CAPTION & ~WS_BORDER & ~WS_CHILD);
                                int wh = tabPage.Height;
                                MoveWindow(appWin, 0, 0, tabPage.Width, wh, true);

                                //Make new tab the focus
                                tab.SelectedTab = tab.TabPages[tabName];
                                //Add new process to RunningProcess
                                RunningProcesses.Rows.Add(GetDataRow(execPath, process.ProcessName, tabName, selectedNode.Name, chromeProfileNo, process.Id.ToString()));
                            }
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show(ex.Message);
                        }
                    }
                }
            }
        }
 
由主持人最后编辑:

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,490
地点
弗吉尼亚州切萨皮克
编程经验
10+
我的天啊!该代码充满了窗口句柄操纵技巧。

And even worse there are multiple calls to Application.DoEvents(). How do you know that you are not accidentally re-entering your program when you call Application.DoEvents() and causing a deadlock, and hence the grandchild processes that are being launched are freezing?

为了确保我理解正确,您具有此主菜单应用程序(menu1)。用户可以选择启动完全由您控制的自定义C#应用程序(app1)。此外,该子自定义C#应用程序(app1)可以启动另一个自定义C#应用程序(SSRS应用程序)-孙子。在子应用程序(app1)终止之前,该孙子不可见或处于冻结状态。
C#:
menu application (menu1)
+---- custom C#  application 1  (child application: app1)
      +---- custom C#  application 2 (grandchild application: SSRS app)
 

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,919
地点
英国
编程经验
10+
但是它们也遵循正常的Windows约定,并且不要使子应用程序窗口成为父应用程序的一部分。
通常他们不会。除了您刚才编写的内容之外,如果您使用我上面编写的API调用,它也会执行此操作,这恰好与 @ 5银狐。正如我在上一个屏幕快照中所展示的,这是一个问题,它们是通过滥用Windows API调用而开发的,该API设置了独立的窗口,从而使它们成为调用API应用程序的子级-设置了该句柄。这就是API的功能。因此,当然任何使用 家长 当以这种方式使用时,API将成为调用代码的子进程。不过,请注意。我认为那不是锁定其他应用程序的原因。我相信您可能已经在下面引用我的回复的地方确定了原因。
哦,是的,按照您的示例,这就是我正在做的事情,如果您关闭菜单,则该菜单打开的所有程序都会关闭,并且我检查您是否两次都不打开同一应用程序。
与同一应用程序打开两次无关。的 家长 API随后在您的调用代码下运行它。只需使用Windows任务管理器即可看到。您的 家长 如我已经演示的那样,当您设置tabcontrol的句柄时,call将在调用代码下将启动的进程作为子进程运行。查看这些文件 家长函数(winuser.h)-Win32应用 并注意以下行:
应用程序可以使用 家长 用于设置弹出窗口的父窗口的功能, 重叠或子窗口。
因此,请提醒我,为什么要使用此API,以及为什么在将控件的句柄设置为第二个或第三个应用程序时将其更改为调用代码的子代,所以认为使用此API是一个好主意?
我真的很困惑。使用一个具有多个表单的应用程序或改用表单模型确实会更好。
And even worse there are multiple calls to Application.DoEvents().
在此说明;并且关于 Application.DoEvents,请注意Microsoft的以下引号:
当您的代码处理事件时,您的应用程序不会响应。例如, 如果将另一个窗口拖到顶部,则该窗口不会重新绘制。
这可能是导致您的"hangs"。请参阅以下备注: Application.DoEvents方法(System.Windows.Forms) 在这里总结。 --

我认为您需要进行大量的调试和代码清理。您可能还会使用其他API来尝试帮助处理使用时位于主窗口顶部的其他窗口 Application.DoEvents。不确定它们到底是什么,我不太确定。我真诚地建议您更改方法。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,490
地点
弗吉尼亚州切萨皮克
编程经验
10+
我同意那个!

或者,如果必须使用主菜单应用程序,则将其他子应用程序加载为加载项。利用MEF的优势,您不必推出自己的外接程序体系结构。
 

5银狐

会员
已加入
2020年4月30日
留言内容
5
编程经验
10+
I second that!

或者,如果必须使用主菜单应用程序,则将其他子应用程序加载为加载项。利用MEF的优势,您不必推出自己的外接程序体系结构。
在我的情况下,这不是一个选择,因为某些应用程序是第三方应用程序。只有我遇到问题的应用程序才是我可以更改的C#应用​​程序。

会记录您对DoEvents的评论,但在某些情况下它是相关的,例如:当您启动第三方应用程序并希望其显示在其主窗口中时,DoEvents可以帮助给第三方应用程序腾出时间。就是说,它根本不影响我的应用程序,因为在删除所有DoEvent时,它的行为始终如一,但是我将其删除。

有人(对于我来说,我一生都找不到参考)说,您无法从停靠的应用程序中启动应用程序。确实如此,我将子C#应用程序更改为不启动任何子孙。感谢您的指点,尽管这不是我一直在寻找的解决方案,但现在可以使用。

PS:我已经在使用DevExpress的另一家公司看到了这一点,他们的问题为零。 DevExpress控件可以正常工作。太糟糕了,我负担不起他们。 :(
 

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,919
地点
英国
编程经验
10+
总是很乐意提供帮助。抱歉,它没有按您的计划。
 
最佳 底部