我這邊的業務需求是要通過呼叫 WebService 來遠程啟動服務器上的 Winform 程式。
我首先寫了一個 Winform 程式,接著又寫了一個 WebService 程式,在這個 WebService 程式里面通過命令列的方式,啟動那個 Winform 程式,寫好以后,在 Visual Studio 開發環境下,除錯運行都沒有問題,Winform 程式可以被正常啟動,然后部署到IIS上就報錯了,錯誤資訊如下:
當應用程式不是以 UserInteractive 模式運行時顯示模式對話框或表單是無效操作。請指定 ServiceNotification 或 DefaultDesktopOnly 樣式,以顯示服務應用程式發出的通知。
在 System.Windows.Forms.Form.Show(IWin32Window owner)
在 CCWin.CCSkinMain.Fidq2DTrRbjaq7x2UmS(Object , Object )
在 CCWin.CCSkinMain.OnVisibleChanged(EventArgs e)
在 System.Windows.Forms.Control.SetVisibleCore(Boolean value)
在 System.Windows.Forms.Form.SetVisibleCore(Boolean value)
在 System.Windows.Forms.Control.set_Visible(Boolean value)
在 System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
在 System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
在 System.Windows.Forms.Application.Run(Form mainForm)
Program.cs 檔案中的“Application.Run(new FrmMain());”這行代碼報錯,導致 Winform 程式啟動不了,無法實作業務需求,請教大家問題究竟出在哪里,應該如何解決?
補充說明:Program.cs 檔案中沒有 MessageBox.Show() 之類的代碼
uj5u.com熱心網友回復:
發布在IIS中的服務包括表單界面,去掉表單相關的操作應該就行,IIS上最好不要運行需要人工互動的內容除了你說的MessageBox.Show(),還有沒有其他與表單相關的?
IIS應該不跑winform程式,winform程式是桌面應用程式。改成其他,比如控制臺應用?
uj5u.com熱心網友回復:
程式中是不能出現表單的相關代碼,比如MessageBox、OpenFileDialog等相關代碼。從這個角度出發,可以解決問題。uj5u.com熱心網友回復:
試試給你的winform創建個快捷方式,然后webservice去打開這個快捷方式。uj5u.com熱心網友回復:
winform放在服務端?
uj5u.com熱心網友回復:
分兩個專案,專案A為WinForm程式,專案B為WebService程式。在WebService中使用Process.Start("專案A生成的exe")uj5u.com熱心網友回復:
建議或同意這種做法的構架師會被打屁股的。
想象機房里的服務器,平時螢屏,鍵盤滑鼠都不連的,Winform跟誰互動?
退一步假設有可以有UI。如果多個用戶遠程登錄,Winform要給誰看?要跟那個用戶互動?
你最好的做法就是重新評估和討論你們的業務。
uj5u.com熱心網友回復:
總是感覺有點奇怪。為什么不是一個網頁。
而是弄一個winform。
那如果有10個人呼叫webservice。是不是就啟動了10個winform?
而且我覺得權限方面應該也存在問題。
uj5u.com熱心網友回復:
在服務器,應該創建windows服務,而不是winform讓webservice啟動服務
uj5u.com熱心網友回復:
那10個人通過webservice來訪問,就開10個exe ? 那100個人。。。。。uj5u.com熱心網友回復:
asp.net下啟動服務的例子
ProcessStartInfo _processStartInfo = new ProcessStartInfo(@"c:/windows/system32/cmd.exe", "/c net start 服務名稱");
_processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
Process.Start(_processStartInfo);
專案從winform到服務的轉換,比較容易
如何創建Windows服務,請參閱https://www.cnblogs.com/sorex/archive/2012/05/16/2502001.html
uj5u.com熱心網友回復:
大家好,我是樓主,非常感謝大家的幫助和指導,我再補充說明幾句:Winform 程式是用來做實時監控的,需要有界面來顯示監控結果,所以不能改成Windows服務
這個專案是公司內部專案,服務器放在公司內部機房,只能通過內網來訪問,外網訪問不了,所以實際訪問量不會很大
Winform 程式放在服務器的D盤
WebService 部署在IIS上,程式也放在服務器的D盤,和 Winform 程式是不同的檔案夾
在 Visual Studio 中,Winform 程式和 WebService 程式是同一個解決方案下的兩個不同的專案,在VS環境下運行都是好的,可以通過呼叫 WebService 來啟動 Winform 程式,部署到IIS上就不行了,exe程式起不來
查看系統日志,錯誤資訊如下:
當應用程式不是以 UserInteractive 模式運行時顯示模式對話框或表單是無效操作。請指定 ServiceNotification 或 DefaultDesktopOnly 樣式,以顯示服務應用程式發出的通知。
為了避免 MessageBox、OpenFileDialog 之類的問題,我曾經嘗試建過一個全新的Winform專案,里面只有一個空表單,然后部署到IIS上,還是不行
總之,在VS環境下都可以順利啟動,部署到IIS上就不行
系統日志顯示,
在VS環境下運行,SystemInformation.UserInteractive的值為True,
部署到IIS上運行,SystemInformation.UserInteractive的值為False
但 SystemInformation.UserInteractive 是只讀的,改不了
現在問題已經清楚了,但不知道該如何解決?
uj5u.com熱心網友回復:
當從服務行程或從 Web 應用程式呼叫時,SystemInformation.UserInteractive的屬性會變成 false,這個是規則,改不了的。既然要放在服務器上做實時監控,那可以做個webform程式,如果是在是有什么是必須要winform處理而網頁處理不了的,那可以在服務器上做一個windows服務實作winform的功能,然后與webform去互動就好了uj5u.com熱心網友回復:
SystemInformation.UserInteractive 只讀,此屬性僅在 Windows NT 3.51 或更高版本、Windows 2000、Windows XP 和 Windows Server 2003 系列上受支持。
跟系統有關嗎?
uj5u.com熱心網友回復:
我是樓主,我本機作業系統是 Windows 7 SP1 企業版,服務器的作業系統是 Windows Server 2008 R2 SP1 企業版
uj5u.com熱心網友回復:
在Windows XP、Windows Server 2003 或早期Windows 系統時代,當第一個用戶登錄系統后服務和應用程式是在同一個Session 中運行的。從Vista 開始Session 0 中只包含系統服務,其他應用程式則通過分離的Session 運行。所以如果運行環境是Vista或者更新,直接使用系統服務來監測form程式不可行。
對于簡單的互動,服務可以通過WTSSendMessage 函式,在用戶Session 上顯示訊息視窗。對于一些復雜的UI 互動,必須呼叫CreateProcessAsUser 或其他方法(WCF、.NET遠程處理等)進行跨Session 通信,在桌面用戶上創建一個應用程式界面。
具體的可以搜“穿透Session0隔離”。
比較簡單的方法:
1.使用服務監測服務,也就是13樓所述,lz把自己的作業行程改造成系統服務。
2.設定指定用戶自動登錄,使用form行程來管理自己的form程式。
https://bbs.csdn.net/topics/392117510?list=1127180
uj5u.com熱心網友回復:
WebService從字面意思看就知道只能處理網頁服務;要打開winform你需要WCF程式,然后部署成windows服務;uj5u.com熱心網友回復:
CreateProcessAsUser,C#寫的windows服務彈框提示訊息或者啟動子行程
https://www.cnblogs.com/datacool/p/CreateProcessAsUser_Win_api.html
uj5u.com熱心網友回復:
行的通了。你需要中間加個服務或者控制臺。
WebService->增加的服務->跨Session呼叫實時監控Winform程式
中間層只是啟動winform程式,是否啟動完后,即自行關閉。只是啟動winform程式的話,是否能換成控制臺程式?
uj5u.com熱心網友回復:
你的意思是不是說,先通過 WebService 啟動一個 Windows服務,然后再通過這個 Windows服務來啟動 Winform 程式?
uj5u.com熱心網友回復:
我覺得你最好先說清楚,你要監控什么?然后我這里說幾個作業系統的概要:
1、作業系統不同用戶的程式是不能互相訪問的。
2、作業系統除去System層的服務,每個用戶啟動的軟體都是不一樣的軟體。
我也能想到你的“監控視窗” 就和MSSQL的監控器一樣,是一個常駐任務欄,有視窗的程式,監控一些服務運行狀態、并且可以操作和改變一些資料。
但是MSSQL的做法是建立一個服務監控和控制需要操作的資料和行程,然后每個用戶登錄后自動載入一個視窗程式,視窗程式和服務通訊獲取服務基本資訊的。
uj5u.com熱心網友回復:
是的。微軟的bug。直線走不通了。跳板一下,17樓的網址有現成的服務代碼。要不,你的winform改成服務,日志打出監控?兩者,你會選第1個吧。

uj5u.com熱心網友回復:
這個應該是業務邏輯上的錯誤,必鏡環境不一樣,最野蠻的辦法你新建一個winform,里面沒有任何業務,看能不能正常啟動。如果能啟動就是你的業務代碼,,然后在winform程式的啟動運行的代碼里寫一些日志來跟蹤代碼運行情況,然后看日志運行了些啥,uj5u.com熱心網友回復:
我是搞Java的不懂C#,給你提個建議,做一個能啟動winform的程式,然后監控一個檔案比如c:/temp/start.flg
webservice請求來了后,寫檔案c:/temp/start.flg
winform的程式啟動成功后,洗掉這個臨時檔案。
uj5u.com熱心網友回復:
這個設計太爛了。你應該改設計,而不應該解決問題。1、監控用windows服務程式就行了,不需要ui,監控持續運行。
2、啟用監控不需要使用啟用winform這種方式,修改一個配置就行了,足以開啟/關閉服務程式的監控
3、要查看ui,另外寫個winform,和服務程式使用行程訊息互動,傳輸監控資料
uj5u.com熱心網友回復:
這個設計太爛了。你應該改設計,而不應該解決問題
uj5u.com熱心網友回復:
老哥,可以在服務器寫個bat腳本,由bat來喚起winform,程式只負責呼叫執行bat腳本,可以嘗試下uj5u.com熱心網友回復:
做個看門狗程式,socket客戶端放服務器,你遠程控制客戶端啟動你的winform
uj5u.com熱心網友回復:
典型的設計失誤。關于服務于桌面互動比較復雜,幾句話說不清楚:
1、WebService 畢竟是個服務,一般無法與桌面互動,因為桌面互動必須先登錄才行,而服務器基本上不需要登錄;
2、原則上服務器上就不應該跑桌面應用(配置、管理模塊例外,例如 SQLServer、IIS 是服務,但對應的管理器是桌面程式)
3、如果需要在界面上顯示服務里的業務資料,那也是客戶端的事情(不論是 C/S 還是 B/S 架構)
如果一定要在服務里啟動桌面程式,也不是不行,但有諸多限制:
1、服務器不能是核心安裝(只有命令列),必須帶有桌面環境
2、必須先在服務器上登錄到桌面,建立一個會話
3、在你的服務里使用這個登錄的帳戶名稱、密碼來啟動一個桌面程式(因為服務的啟動帳號一般是 system,而桌面互動帳號肯定不是 system )
uj5u.com熱心網友回復:
你在webservice里面啟動exe程式,是不允許的uj5u.com熱心網友回復:
Winform 程式是用來做實時監控的,需要有界面來顯示監控結果,所以不能改成Windows服務
實時監控的話應該是得接出來一個大屏用于顯示吧
uj5u.com熱心網友回復:
IIS指向webservice目錄需要執行權限的,檢查uj5u.com熱心網友回復:
應該是授權問題,遠程是不可以隨便啟動服務器的本地應用的,特別如果應用不在服務器的目錄下uj5u.com熱心網友回復:
哥們,他們說的都對,IIS行程是啟動不了WinForm程式的,我之前也撞過這個墻。簡單的辦法就是把你的WinForm程式設定為開機啟動得了,一行代碼都不用改,除此之外我當時也沒有想到有效的解決辦法,其他設計模式改變,業務模式拆分啥的,咱也不想去改動,沒得那個時間。
uj5u.com熱心網友回復:
哥們,他們說的都對,IIS行程是啟動不了WinForm程式的,我之前也撞過這個墻。
簡單的辦法就是把你的WinForm程式設定為開機啟動得了,一行代碼都不用改,除此之外我當時也沒有想到有效的解決辦法,其他設計模式改變,業務模式拆分啥的,咱也不想去改動,沒得那個時間。
贊一個!


uj5u.com熱心網友回復:
哥們,他們說的都對,IIS行程是啟動不了WinForm程式的,我之前也撞過這個墻。簡單的辦法就是把你的WinForm程式設定為開機啟動得了,一行代碼都不用改,除此之外我當時也沒有想到有效的解決辦法,其他設計模式改變,業務模式拆分啥的,咱也不想去改動,沒得那個時間。
贊一個!
uj5u.com熱心網友回復:
點贊的那些你這個log如果是需要24小時記錄,然后你注銷所有用戶服務器運行的時候你就該頭疼又來發帖了。uj5u.com熱心網友回復:
用個服務檢測winform程式,時間間隔可以為30秒。如果沒有啟動,則啟動。還防止了winform程式例外關閉的情況。處理問題,簡單實效,歷來主張
uj5u.com熱心網友回復:
怎么幫你忙?uj5u.com熱心網友回復:
建議在 局域網 中測驗一下試試,也可能 遠程需要開啟相關的埠號uj5u.com熱心網友回復:
既然 Winform 程式是用來做實時監控的,那就一直處于打開狀態,再去考慮你的業務邏輯uj5u.com熱心網友回復:
大款兒啊




uj5u.com熱心網友回復:
沒太搞明白這邏輯,服務器端的一個監控顯示視窗,需要客戶端的發起?那這個監控視窗還需要人為關倍訓自行關閉?其實你沒必要把它們整在一起,各自干各自的作業,有互動的地方也就是資料。
一個負責寫資料,一個負責讀資料,遇到要求內的資料,做以提示就好。
或者是沒太明白你這個專案的真正意義,以上僅為個人看法,如有雷同、實屬巧合!
uj5u.com熱心網友回復:
直接遠程登錄服務器的時候再打開Winform 程式不行嗎,反正要看的時候肯定要登錄服務器的不是嗎?uj5u.com熱心網友回復:
不知道,不好意思uj5u.com熱心網友回復:
那10個人通過webservice來訪問,就開10個exe ? 那100個人。。。。。uj5u.com熱心網友回復:
aa
uj5u.com熱心網友回復:
不錯能用謝謝uj5u.com熱心網友回復:
Winform 程式是用來做實時監控的,需要有界面來顯示監控結果,所以不能改成Windows服務==>
沒見過這種的,在服務器里顯示結果?
不知道你的真正業務需求是什么,我猜想,你可以改成C/S架構的,不要分什么客戶端,服務端,就是分布式處理
想要監控資料,主動請求對方,對方發資料自己接收就行;或者發送發者在適當時候主動廣播資料給要看監控資料的一端
用wcf或者socket
服務器里弄個winform,那么,想看監控資料的一端,要登陸到服務器嗎?
還是怎么看
用資料存盤中轉,也是不建議的
用一個服務寫資料到存盤(如資料庫或者文本),再用web頁面讀取,這樣會更復雜
uj5u.com熱心網友回復:
沒錯,我是圍觀的
uj5u.com熱心網友回復:
學習一下吧。。。uj5u.com熱心網友回復:
在服務器,應創建windows服務uj5u.com熱心網友回復:
搞不定就重啟看看



uj5u.com熱心網友回復:
CreateProcessAsUseruj5u.com熱心網友回復:
https://www.cnblogs.com/yechangzhong-826217795/p/8303867.htmluj5u.com熱心網友回復:
這個可能和權限有關系,IIS服務在不登錄的情況可以運行,但是你的winform 不能運行。開發環境下,實際上已經有了登錄,所以能跑起來。
uj5u.com熱心網友回復:
我是搞Java的不懂C#,給你提個建議,
做一個能啟動winform的程式,然后監控一個檔案比如c:/temp/start.flg
webservice請求來了后,寫檔案c:/temp/start.flg
winform的程式啟動成功后,洗掉這個臨時檔案。
uj5u.com熱心網友回復:
相關的事需要有經驗的系統管理員指導:主要問題是程式運行模式不正確,如果不是運行在用戶互動模式下、顯示模式對話框或表單是無效操作;需要指定ServiceNotification或者DefaultDesktopOnly樣式。uj5u.com熱心網友回復:
服務中 啟動外部的exe程式 需要借助 一個動態庫 ,不然你是看不到exe界面的。參考:Cjwdev.WindowsApi.dllvar appStartpath = @"D:\Project\third.exe";
int _currentAquariusProcessID;
/*appStartpath設定為全路徑地址*/
IntPtr userTokenHandle = IntPtr.Zero;
ApiDefinitions.WTSQueryUserToken(ApiDefinitions.WTSGetActiveConsoleSessionId(), ref userTokenHandle);
ApiDefinitions.PROCESS_INFORMATION procinfo = new ApiDefinitions.PROCESS_INFORMATION();
ApiDefinitions.STARTUPINFO startinfo = new ApiDefinitions.STARTUPINFO();
startinfo.cb = (uint)System.Runtime.InteropServices.Marshal.SizeOf(startinfo);
try
{
ApiDefinitions.CreateProcessAsUser(userTokenHandle, appStartpath, "", IntPtr.Zero, IntPtr.Zero, false, 0, IntPtr.Zero, null, ref startinfo, out procinfo);
if (userTokenHandle != IntPtr.Zero)
ApiDefinitions.CloseHandle(userTokenHandle);
_currentAquariusProcessID = (int)procinfo.dwProcessId;
return true;
}
catch (Exception ex)
{
return false;
}
uj5u.com熱心網友回復:
效果怎么樣?uj5u.com熱心網友回復:
iis里,.net信任級別,改成high試一下uj5u.com熱心網友回復:
換我的話,會先啟動一個程式,判斷數居庫或檔案,webserver更改資料或檔案,這個程式再啟動另一個程式,正常桌面程式才能直接啟動桌面程式。uj5u.com熱心網友回復:
學習中。。。。轉載請註明出處,本文鏈接:https://www.uj5u.com/net/80460.html
標籤:C#
