2019年7月18日 星期四

[C#] 控制項跨執行緒作業無效解決方法(How to: Make Thread-Safe Calls to Windows Forms Controls without delegates)

通常在開發winForm程式時,最容易碰到執行緒(thread)問題,而控制項(controls)的跨續問題也十分讓人頭痛,而通常出現的錯誤訊息,莫過於「跨執行緒作業無效: 存取控制項 ... 時所使用的執行緒與建立控制項的執行緒不同」。
通常在開發winForm程式時,最容易碰到執行緒(thread)問題,而控制項(controls)的跨續問題也十分讓人頭痛,而通常出現的錯誤訊息,莫過於「跨執行緒作業無效: 存取控制項 ... 時所使用的執行緒與建立控制項的執行緒不同」。
因為控制項(control)主要是存在UI Thread(通常是Main Thread)內,所以在非相同執行緒下要更新UI就會產生跨執行緒的錯誤。而一般常見的解法是用delegate搭配Invoke,缺點是不夠彈性,並且有時可能會不如預期的還是會發生跨執行序錯誤。google關鍵字「C# dalegate invoke」會找到很多類似例子。
然後我們從MSDN中 How to: Make Thread-Safe Calls to Windows Forms Controls 這篇文章中可以看到很多相關寫法,其中強調是thread-safe寫法的關鍵字在Controls.InvokeRequired 
MSDN上對這個值的說明「這個值會指示是否由於呼叫端是在建立控制項之執行緒以外的執行緒,因此在進行控制項的方法呼叫時,應呼叫叫用 (Invoke) 方法。
而為了更有效便利的使用InvokeInvokeRequired去執行跨執行緒控制項操作,我通常會把這個方法撰寫class的擴充方法,並且加入MethodInvoker 委派/lambda的應用。
使用方法與程式碼如下
public class main
{
    //參考用controls
    TextBox tb = new TextBox();

    void Func()
    {
        //使用lambda
        tb.InvokeIfRequired(() =>
        {
            tb.Text = "hello";
        });

        //使用Action
        tb.InvokeIfRequired(helloAction);
    }

    void helloAction()
    {
        tb.Text = "hello";
    }
}

//擴充方法
public static class Extension
{
    //非同步委派更新UI
    public static void InvokeIfRequired(
        this Control control, MethodInvoker action)
    {
        if (control.InvokeRequired)//在非當前執行緒內 使用委派
        {
            control.Invoke(action);
        }
        else
        {
            action();
        }
    }
}

MSDN參考資料:

from : https://dotblogs.com.tw/shinli/2015/04/16/151076

2019年7月16日 星期二

Dos Batch Files - Error Handling

I generally find the conditional command concatenation operators much more convenient than ERRORLEVEL.
yourCommand && (
  echo yourCommand was successful
) || (
  echo yourCommand failed
)
There is one complication you should be aware of. The error branch will fire if the last command in the success branch raises an error.
yourCommand && (
  someCommandThatMayFail
) || (
  echo This will fire if yourCommand or someCommandThatMayFail raises an error
)
The fix is to insert a harmless command that is guaranteed to succeed at the end of the success branch. I like to use (call ), which does nothing except set the ERRORLEVEL to 0. There is a corollary (call) that does nothing except set the ERRORLEVEL to 1.
yourCommand && (
  someCommandThatMayFail
  (call )
) || (
  echo This can only fire if yourCommand raises an error
)

from : https://stackoverflow.com/questions/1164049/batch-files-error-handling

2019年7月15日 星期一

Create a Remote Process using WMI in C#

//
//WMI section
//    
ManagemenConnectionOptions connOptions = new ConnectionOptions();
connOptions.Impersonation = ImpersonationLevel.Impersonate;
connOptions.EnablePrivileges = true;
tScope manScope = new ManagementScope
	(String.Format(@"\\{0}\ROOT\CIMV2", remoteMachine), connOptions);
manScope.Connect();
ObjectGetOptions objectGetOptions = new ObjectGetOptions();
ManagementPath managementPath = new ManagementPath("Win32_Process");
ManagementClass processClass = new ManagementClass
	(manScope, managementPath, objectGetOptions);
ManagementBaseObject inParams = processClass.GetMethodParameters("Create");
inParams["CommandLine"] = sBatFile; 
ManagementBaseObject outParams = processClass.InvokeMethod("Create", inParams, null);
Console.WriteLine("Creation of the process returned: " + outParams["returnValue"]);
Console.WriteLine("Process ID: " + outParams["processId"]); 

from : https://www.codeproject.com/Articles/31113/Create-a-Remote-Process-using-WMI-in-C

Reading a registry value to a batch variable, handling spaces in value

Ah this is one of the annoying details about the for /f command. In order to read all the characters including the spaces with the * the previous token needs to be declared. tokens=2,* The functional reason is stated in the documentation.
If the last character in the tokens= string is an asterisk (*), an additional variable is allocated and receives the remaining text on the line after the last token that is parsed.
FOR /F "usebackq tokens=2,* skip=2" %%L IN (
    `reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1\WinSDKTools" /v InstallationFolder`
) DO SET sdkpath=%%M

from : https://stackoverflow.com/questions/22352793/reading-a-registry-value-to-a-batch-variable-handling-spaces-in-value

Copy all files and directories recursively

You can just be recursive. I just put this together - I might not have analysed your variables perfectly but it will give you an idea.
 private void btn_submit_Click(object sender, EventArgs e)
{
    copy_stuff(txt_src.Text, txt_dest.Text);
}

private void copy_stuff(string srcFolder, string destFolder)
{
    foreach (string zzz in Directory.GetFiles(srcFolder, "*.zzz", SearchOption.AllDirectories))
    {
        string modulePath = Directory.GetParent(zzz).FullName;
        string moduleName = Directory.GetParent(zzz).Name;
        Directory.CreateDirectory(destFolder + "\\" + moduleName);
        foreach (string subFolders in Directory.GetDirectories(modulePath, "*", SearchOption.AllDirectories))
        {
            string dest = subFolders.Replace(modulePath, destFolder + "\\" + moduleName);
            Directory.CreateDirectory(dest);
            copy_stuff(subfolders, dest);
        }
        foreach (string allFiles in Directory.GetFiles(modulePath, "*.*", SearchOption.AllDirectories))
        {
            File.Copy(allFiles, allFiles.Replace(modulePath, destFolder + "\\" + moduleName), true);
        }
    }
}

from : https://stackoverflow.com/questions/15577291/copy-all-files-and-directories-recursively

2019年7月12日 星期五

Start or Stop Services on Remote Machine

Sample code to control the remote machine/system services. Below code shows how to Start or Stop the remote computer service.

Note : To run this code user must have the rights to Start/Stop the service of the remote computer.

Namespace: 
       using System.Management;


Code: 

Start service of the Remote Machine:

              try
                {

                    #region Code to start the service
               
                    string serviceName = "Service1";
                    string IP="Remote machine IP";
                    string username ="UserID";
                    string password ="Pass";

                    ConnectionOptions connectoptions = new ConnectionOptions();
                    //connectoptions.Impersonation = ImpersonationLevel.Impersonate; 
                    connectoptions.Username = username;
                    connectoptions.Password = pass;

                    //IP Address of the remote machine
                  
                    ManagementScope scope = new ManagementScope(@"\\" + IP + @"\root\cimv2");
                    scope.Options = connectoptions;

                    //WMI query to be executed on the remote machine
                    SelectQuery query = new SelectQuery("select * from Win32_Service where name = '" + serviceName + "'");

                    using (ManagementObjectSearcher searcher = new
                                ManagementObjectSearcher(scope, query))
                    {
                        ManagementObjectCollection collection = searcher.Get();
                        foreach (ManagementObject service in collection)
                        {
                            if (service["Started"].Equals(false))
                            {
                                //Start the service
                                service.InvokeMethod("StartService", null);                              
                            }

                        }
                    }
                   
           #endregion

                }
                catch ()
                {
                  
                }


Similar way you can stop the service of Remote Machine:

                       if (service["Started"].Equals(true))
                        {
                            //Stop the service
                            service.InvokeMethod("StopService", null);                            
                        }

from : http://learn-vsdotnet.blogspot.com/2013/03/start-or-stop-services-on-remote-machine.html