2017年12月20日 星期三

C# WPF DataGrid DataGridTextColumn Cell Event

DataGrid加載事件

只要在DataGridTextColumn裡面加入DataGridTextColumn.EditingElementStyle就可以在裡面放入事件了
方法如下





-->


參考來源:Cell value changed event(?) in DataGrid

2017年11月7日 星期二

C# 加載網路硬碟的Dll失敗

我有一個網路硬碟,磁區符號是Z槽。

在Z槽下面,放了一個assembly,名為test.dll。然後,我在VS2010中建立了一個.NET 4.0的工程,程序中有下面一段代碼:

執行代碼,拋出FileLoadException異常:Could not load file or assembly 'file:///Y:\bb\nvo_cas.dll' or one of its dependencies. Operation is not supported. (Exception from HRESULT: 0x80131515)。

【辦法一】

根據提示,找到了MSDN的一篇文章。文章給出的解決辦法是:在App.config中加入下面的xml片段:

      
      ......  
        
          
          
        
      ......  
      


【辦法二】

Assembly類有一個靜態函數UnsafeLoadFrom,這個函數在加載一個assembly的時候,不會進行一些安全檢查。

string dll = @"Z:\test.dll";  
Assembly a = Assembly.UnsafeLoadFrom(dll);  


【辦法三】

Assembly的load方法有很多的重載,可以使用其中的一個參數為byte[]的load函數。代碼如下:

string dll = @"Z:\test.dll"; ;  
byte[] assemblyBuffer = File.ReadAllBytes(dll);  
Assembly a = Assembly.Load(assemblyBuffer);  


轉載自:【解决问题】加载网络映射盘中的assembly失败

2017年9月28日 星期四

C# ObservableCollection 此類型的 CollectionView 不支援從 與發送器執行續不同的執行緒變更其SourceCollection

今天撰寫OPC Server遇到一個問題是 我的OPCServerSource已經跟UI的TreeView綁定了 可是我又透過OPC Client去取得Browser的Server的資料 再要將Server資料匯入到OPCServerSource時,出現如圖下的錯誤。



解決的方法是在要匯入的地方加入Application.Current.Dispatcher.BeginInvoke((Action)delegate () {};這行,就可以解決問題了

private void ServerBrowserItemsUI(List serverList)
{
  Application.Current.Dispatcher.BeginInvoke((Action)delegate ()
  {
    serverList.ToList().ForEach(args =>
    {
    OPCServerSource.Add(new Model.OPCServer() { ProgName = args.progID, ProgID = args.clsid.ToString(), Url = new System.Windows.Media.Imaging.BitmapImage(new Uri(@"/OPCDASettingWPFLib;component/Common/Images/lightIcon_green_20.png", UriKind.RelativeOrAbsolute)) });
    });
  });
}

2017年9月17日 星期日

混合模式組件是針對版本 v2.0.50727 的執行階段建置的,無法在沒有其他組態資訊的情況下載入 4.0 執行階段中。

小編今天撰寫OPC Server時,套用的Third Party是.NET Framework 2.0的版本 而公司採用的是.NET Framework 4.0的版本,所以出現了以下的錯誤。



根據網路上解決的方法是在App.Config裡面加入『useLegacyV2RuntimeActivationPolicy="true"』這行即可。



     
        
    



2017年9月14日 星期四

C# DateTime To SQL Server DateTime

C# Function

        public bool WriteAlarmEvent(IOPCDAClientLib.AlarmRecord alarm)
        {
            bool result = false;
            using (_cmd = new SqlCommand("AlarmRecordAdd", _connect))
            {
                _cmd.CommandType = System.Data.CommandType.StoredProcedure;
                _cmd.Parameters.Add("@TagName", System.Data.SqlDbType.NVarChar, 200);
                _cmd.Parameters.Add("@AlarmState", System.Data.SqlDbType.NVarChar, 100);
                _cmd.Parameters.Add("@Description", System.Data.SqlDbType.NVarChar);
                _cmd.Parameters.Add("@Value", System.Data.SqlDbType.NVarChar, 100);
                _cmd.Parameters.Add("@EventStampDate", System.Data.SqlDbType.Date);
                _cmd.Parameters.Add("@EventStampTime", System.Data.SqlDbType.Time);
                _cmd.Parameters.Add("@Provider", System.Data.SqlDbType.NVarChar, 100);
                _cmd.Parameters.Add("@Area", System.Data.SqlDbType.NVarChar, 100);
                _cmd.Parameters.Add("@Type", System.Data.SqlDbType.NVarChar, 100);
                _cmd.Parameters.Add("@Priority", System.Data.SqlDbType.Int,1);
                _cmd.Parameters.Add("@MilliSec", System.Data.SqlDbType.Int,1);
                _cmd.Parameters.Add("@Category", System.Data.SqlDbType.NVarChar, 100);
                _cmd.Parameters.Add("@CheckValue", System.Data.SqlDbType.NVarChar, 100);
                _cmd.Parameters.Add("@Operator", System.Data.SqlDbType.NVarChar, 100);
                _cmd.Parameters.Add("@DomainName", System.Data.SqlDbType.NVarChar, 100);
                _cmd.Parameters.Add("@UserFullName", System.Data.SqlDbType.NVarChar, 100);
                _cmd.Parameters.Add("@OperatorNode", System.Data.SqlDbType.NVarChar, 100);
                _cmd.Parameters.Add("@AlarmId", System.Data.SqlDbType.Int);

                _cmd.Parameters["@TagName"].Value = alarm.TagName ?? "";
                _cmd.Parameters["@AlarmState"].Value = alarm.AlarmState ?? "";
                _cmd.Parameters["@Description"].Value = alarm.Description ?? "";
                _cmd.Parameters["@Value"].Value = alarm.Value ?? "";
                _cmd.Parameters["@EventStampDate"].Value = DateTime.Now.ToString("yyyy/MM/dd");
                _cmd.Parameters["@EventStampTime"].Value = DateTime.Now.ToString("HH:mm:ss.fff");
                _cmd.Parameters["@Provider"].Value = alarm.Provider ?? "";
                _cmd.Parameters["@Area"].Value = alarm.Area ?? "";
                _cmd.Parameters["@Type"].Value = alarm.Type ?? "";
                _cmd.Parameters["@Priority"].Value = alarm.Priority;
                _cmd.Parameters["@MilliSec"].Value = 0;
                _cmd.Parameters["@Category"].Value = alarm.Category ?? "";
                _cmd.Parameters["@CheckValue"].Value = alarm.CheckValue;
                _cmd.Parameters["@Operator"].Value = alarm.Operator ?? "";
                _cmd.Parameters["@DomainName"].Value = alarm.DomainName ?? "";
                _cmd.Parameters["@UserFullName"].Value = alarm.UserFullName ?? "";
                _cmd.Parameters["@OperatorNode"].Value = alarm.OperatorNode ?? "";
                _cmd.Parameters["@AlarmId"].Value = alarm.AlarmId;
                _connect.Open();
                try
                {
                    if(ConnectStatus())
                    {
                        _cmd.ExecuteNonQuery();
                        _connect.Close();
                        result = true;
                    }
                    else
                    {
                        result = false;
                    }

                }
                catch(Exception ex)
                {
                    result = false;
                    throw ex;
                }
                finally
                {
                    _connect.Close();
                }
            }
            return result;
        }


SQL Stored Prodceduce
ALTER PROCEDURE [dbo].[AlarmRecordAdd]
    @TagName nvarchar(200), @AlarmState nvarchar(100), @Description nvarchar(MAX),
    @Value nvarchar(100), @EventStampDate datetime, @EventStampTime datetime,
    @Provider nvarchar(100), @Area nvarchar(100), @Type nvarchar(100), @Priority int,
    @MilliSec int, @Category nvarchar(100), @CheckValue nvarchar(100), @Operator nvarchar(100),
    @DomainName nvarchar(100), @UserFullName nvarchar(100), @OperatorNode nvarchar(100),
    @AlarmId int
AS
 
DECLARE @EventTimeStamp datetime
DECLARE @EventDate char(10)
DECLARE @EventTime char(12)
 
BEGIN
    IF @EventStampDate IS NOT NULL AND @EventStampTime IS NOT NULL
    BEGIN
        SET @EventDate = CONVERT(varchar(10), @EventStampDate, 111)
        SET @EventTime = CONVERT(varchar(12), @EventStampTime, 114)
        SET @EventTimeStamp = CONVERT(datetime, @EventDate + ' ' + @EventTime, 121)
        SET @MilliSec = DATEPART(MS,@EventTimeStamp)
    END
    ELSE
    BEGIN
        SET @EventTimeStamp = '1900-01-01 07:07:07'
    END
    
    IF NOT EXISTS(SELECT TOP 1 EventStamp FROM AlarmRecord WHERE EventStamp = @EventTimeStamp AND TagName = @TagName AND AlarmState = @AlarmState )
    BEGIN
        INSERT INTO AlarmRecord(TagName, AlarmState, [Description], [Value], EventStamp,EventStampUTC, Provider, Area,
        [Type], Priority, MilliSec, Category, CheckValue, Operator, DomainName, UserFullName, OperatorNode,
        AlarmId, WriteTimestamp)
        VALUES(@TagName, @AlarmState, @Description, @Value, @EventTimeStamp,@EventTimeStamp, @Provider, @Area, @Type, @Priority,
        @MilliSec, @Category, @CheckValue, @Operator, @DomainName, @UserFullName, @OperatorNode, @AlarmId, GETDATE())
    END
    
    SELECT 0
END


執行結果



若要加入毫秒,則 DateTime.Now.ToString("HH:mm:ss.fff"); 要加在ss後面

2017年8月21日 星期一

C# window Service實現調用UI的應用程式

首先,建立一個ApplicationLoader類別,程式碼如下

using System;
using System.Collections.Generic;
using System.Text;
using System.Security;
using System.Diagnostics;
using System.Runtime.InteropServices;


namespace WS_Monitor_Task_CSharp
{


     /// 
     /// Class that allows running applications with full admin rights. In
     /// addition the application launched will bypass the Vista UAC prompt.
     /// 
    public  class ApplicationLoader
    {


        #region Structrures

        [StructLayout(LayoutKind.Sequential)]
        public struct SECURITY_ATTRIBUTES
        {
            public int Length;
            public IntPtr lpSecurityDescriptor;
            public bool bInheritHandle;
        }


        [StructLayout(LayoutKind.Sequential)]
        public struct STARTUPINFO
        { 
            public int cb;
            public String lpReserved;         
            public String lpDesktop;
            public String lpTitle;
            public uint dwX;        
            public uint dwY;
            public uint dwXSize;
            public uint dwYSize ;             
            public uint dwXCountChars;
            public uint dwYCountChars;
            public uint dwFillAttribute;             
            public uint dwFlags;
            public short wShowWindow;
            public short cbReserved2;              
            public IntPtr lpReserved2;
            public IntPtr hStdInput;
            public IntPtr hStdOutput;
            public IntPtr hStdError;
        
        }


         [StructLayout(LayoutKind.Sequential)]
          public struct PROCESS_INFORMATION
          {
              public IntPtr hProcess;
              public IntPtr hThread;
              public uint dwProcessId;
              public uint dwThreadId;
          }

          #endregion

        
          #region Enumberation
          enum TOKEN_TYPE : int
          {
              TokenPrimary = 1,
              TokenImpersonation = 2
          }

          enum SECURITY_IMPERSONATION_LEVEL : int
          {
              SecurityAnonymous = 0,
              SecurityIdentification = 1,
              SecurityImpersonation = 2,
              SecurityDelegation = 3,
          }

          #endregion




          #region Constants

          public const int TOKEN_DUPLICATE = 0x0002;
          public const uint MAXIMUM_ALLOWED = 0x2000000;
          public const int CREATE_NEW_CONSOLE = 0x00000010;

          public const int IDLE_PRIORITY_CLASS = 0x40;
          public const int NORMAL_PRIORITY_CLASS = 0x20;
          public const int HIGH_PRIORITY_CLASS = 0x80;
          public const int REALTIME_PRIORITY_CLASS = 0x100;

          #endregion



          #region Win32 API Imports

          [DllImport("kernel32.dll", SetLastError = true)]
          private static extern bool CloseHandle(IntPtr hSnapshot);

          [DllImport("kernel32.dll")]
          static extern uint WTSGetActiveConsoleSessionId();

          [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
          public extern static bool CreateProcessAsUser(IntPtr hToken, String lpApplicationName, String lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes,
             ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle, int dwCreationFlags, IntPtr lpEnvironment,
            String lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);

          [DllImport("kernel32.dll")]
          static extern bool ProcessIdToSessionId(uint dwProcessId, ref uint pSessionId);

          [DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
          public extern static bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess,
              ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType,
               int ImpersonationLevel, ref IntPtr DuplicateTokenHandle);

          [DllImport("kernel32.dll")]
          static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);

          [DllImport("advapi32", SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
          static extern bool OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, ref IntPtr TokenHandle);

          #endregion




          /// 
          /// Launches the given application with full admin rights, and in addition bypasses the Vista UAC prompt
          /// 
          /// The name of the application to launch
          /// Process information regarding the launched application that gets returned to the caller
          /// 
          public static bool StartProcessAndBypassUAC(String applicationName, out PROCESS_INFORMATION procInfo)
          {
              uint winlogonPid = 0;
              IntPtr hUserTokenDup = IntPtr.Zero, 
                  hPToken = IntPtr.Zero, 
                  hProcess = IntPtr.Zero;
              procInfo = new PROCESS_INFORMATION();

              // obtain the currently active session id; every logged on user in the system has a unique session id
              TSControl.WTS_SESSION_INFO[] pSessionInfo = TSControl.SessionEnumeration();
              uint dwSessionId = 100;
              for (int i = 0; i < pSessionInfo.Length; i++)
              {
                  if (pSessionInfo[i].SessionID != 0)
                  {
                      try
                      {
                          int count = 0;
                          IntPtr buffer = IntPtr.Zero;
                          StringBuilder sb = new StringBuilder();

                          bool bsuccess = TSControl.WTSQuerySessionInformation(
                             IntPtr.Zero, pSessionInfo[i].SessionID,
                             TSControl.WTSInfoClass.WTSUserName, out sb, out count);

                          if (bsuccess)
                          {
                              if (sb.ToString().Trim() == "dmpadmin")
                              {
                                  dwSessionId = (uint)pSessionInfo[i].SessionID;
                              }
                          }
                      }
                      catch (Exception ex)
                      {
                          LoaderService.WriteLog(ex.Message.ToString(),"Monitor");
                      }
                  }
              }


              // obtain the process id of the winlogon process that is running within the currently active session
              Process[] processes = Process.GetProcessesByName("explorer");
              foreach (Process p in processes)
              {
                  if ((uint)p.SessionId == dwSessionId)
                  {
                      winlogonPid = (uint)p.Id;
                  }
              }

              LoaderService.WriteLog(winlogonPid.ToString(), "Monitor");

              // obtain a handle to the winlogon process
              hProcess = OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid);

              // obtain a handle to the access token of the winlogon process
              if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE, ref hPToken))
              {
                  CloseHandle(hProcess);
                  return false;
              }

              // Security attibute structure used in DuplicateTokenEx and CreateProcessAsUser
              // I would prefer to not have to use a security attribute variable and to just 
              // simply pass null and inherit (by default) the security attributes
              // of the existing token. However, in C# structures are value types and therefore
              // cannot be assigned the null value.
              SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
              sa.Length = Marshal.SizeOf(sa);

              // copy the access token of the winlogon process; the newly created token will be a primary token
              if (!DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa, (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int)TOKEN_TYPE.TokenPrimary, ref hUserTokenDup))
              {
                  CloseHandle(hProcess);
                  CloseHandle(hPToken);
                  return false;
              }

              // By default CreateProcessAsUser creates a process on a non-interactive window station, meaning
              // the window station has a desktop that is invisible and the process is incapable of receiving
              // user input. To remedy this we set the lpDesktop parameter to indicate we want to enable user 
              // interaction with the new process.
              STARTUPINFO si = new STARTUPINFO();
              si.cb = (int)Marshal.SizeOf(si);
              si.lpDesktop = @"winsta0\default"; // interactive window station parameter; basically this indicates that the process created can display a GUI on the desktop

              // flags that specify the priority and creation method of the process
              int dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;

              // create a new process in the current user's logon session
              bool result = CreateProcessAsUser(hUserTokenDup,        // client's access token
                                              null,                   // file to execute
                                              applicationName,        // command line
                                               ref sa,                 // pointer to process SECURITY_ATTRIBUTES
                                               ref sa,                 // pointer to thread SECURITY_ATTRIBUTES
                                               false,                  // handles are not inheritable
                                               dwCreationFlags,        // creation flags
                                               IntPtr.Zero,            // pointer to new environment block 
                                               null,                   // name of current directory 
                                               ref si,                 // pointer to STARTUPINFO structure
                                               out procInfo            // receives information about new process
                                               );

              // invalidate the handles
              CloseHandle(hProcess);
              CloseHandle(hPToken);
              CloseHandle(hUserTokenDup);
              LoaderService.WriteLog("launch Task","Monitor");

              return result; // return the result
          }

      }
}


建立完成後,在建立一個TSControl類別
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace WS_Monitor_Task_CSharp
{
    public class TSControl
    {
        /**/
        ///  
        /// Terminal Services API Functions,The WTSEnumerateSessions function retrieves a list of sessions on a specified terminal server, 
        ///  
        /// [in] Handle to a terminal server. Specify a handle opened by the WTSOpenServer function, or specify WTS_CURRENT_SERVER_HANDLE to indicate the terminal server on which your application is running 
        /// Reserved; must be zero 
        /// [in] Specifies the version of the enumeration request. Must be 1.  
        /// [out] Pointer to a variable that receives a pointer to an array of WTS_SESSION_INFO structures. Each structure in the array contains information about a session on the specified terminal server. To free the returned buffer, call the WTSFreeMemory function. 
        /// To be able to enumerate a session, you need to have the Query Information permission. 
        /// [out] Pointer to the variable that receives the number of WTS_SESSION_INFO structures returned in the ppSessionInfo buffer.  
        /// If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero 
        [DllImport("wtsapi32", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool WTSEnumerateSessions(int hServer, int Reserved, int Version, ref long ppSessionInfo, ref int pCount);

        /**/
        ///  
        /// Terminal Services API Functions,The WTSFreeMemory function frees memory allocated by a Terminal Services function. 
        ///  
        /// [in] Pointer to the memory to free 
        [DllImport("wtsapi32.dll")]
        public static extern void WTSFreeMemory(System.IntPtr pMemory);

        /**/
        ///  
        /// Terminal Services API Functions,The WTSLogoffSession function logs off a specified Terminal Services session. 
        ///  
        /// [in] Handle to a terminal server. Specify a handle opened by the WTSOpenServer function, or specify WTS_CURRENT_SERVER_HANDLE to indicate the terminal server on which your application is running.  
        /// [in] A Terminal Services session identifier. To indicate the current session, specify WTS_CURRENT_SESSION. You can use the WTSEnumerateSessions function to retrieve the identifiers of all sessions on a specified terminal server. 
        /// To be able to log off another user's session, you need to have the Reset permission  
        /// [in] Indicates whether the operation is synchronous. 
        /// If bWait is TRUE, the function returns when the session is logged off. 
        /// If bWait is FALSE, the function returns immediately. 
        /// If the function succeeds, the return value is a nonzero value. 
        /// If the function fails, the return value is zero. 
        [DllImport("wtsapi32.dll")]
        public static extern bool WTSLogoffSession(int hServer, long SessionId, bool bWait);


        [DllImport("Wtsapi32.dll")]
        public static extern bool WTSQuerySessionInformation(
            System.IntPtr hServer, 
            int sessionId, 
            WTSInfoClass wtsInfoClass,
            out StringBuilder ppBuffer, 
            out int pBytesReturned
            );

        public enum WTSInfoClass
        {
            WTSInitialProgram,
            WTSApplicationName,
            WTSWorkingDirectory,
            WTSOEMId,
            WTSSessionId,
            WTSUserName,
            WTSWinStationName,
            WTSDomainName,
            WTSConnectState,
            WTSClientBuildNumber,
            WTSClientName,
            WTSClientDirectory,
            WTSClientProductId,
            WTSClientHardwareId,
            WTSClientAddress,
            WTSClientDisplay,
            WTSClientProtocolType
        }

        /**/
        ///  
        /// The WTS_CONNECTSTATE_CLASS enumeration type contains INT values that indicate the connection state of a Terminal Services session. 
        ///  
        public enum WTS_CONNECTSTATE_CLASS
        {
            WTSActive,
            WTSConnected,
            WTSConnectQuery,
            WTSShadow,
            WTSDisconnected,
            WTSIdle,
            WTSListen,
            WTSReset,
            WTSDown,
            WTSInit,
        }


        /**/
        ///  
        /// The WTS_SESSION_INFO structure contains information about a client session on a terminal server. 
        /// if the WTS_SESSION_INFO.SessionID==0, it means that the SESSION is the local logon user's session. 
        ///  
        public struct WTS_SESSION_INFO
        {
            public int SessionID;
            [MarshalAs(UnmanagedType.LPTStr)]
            public string pWinStationName;
            public WTS_CONNECTSTATE_CLASS state;
        }

        /**/
        ///  
        /// The SessionEnumeration function retrieves a list of 
        ///WTS_SESSION_INFO on a current terminal server. 
        ///  
        /// a list of WTS_SESSION_INFO on a current terminal server 
        public static WTS_SESSION_INFO[] SessionEnumeration()
        {
            //Set handle of terminal server as the current terminal server 
            int hServer = 0;
            bool RetVal;
            long lpBuffer = 0;
            int Count = 0;
            long p;
            WTS_SESSION_INFO Session_Info = new WTS_SESSION_INFO();
            WTS_SESSION_INFO[] arrSessionInfo;
            RetVal = WTSEnumerateSessions(hServer, 0, 1, ref lpBuffer, ref Count);
            arrSessionInfo = new WTS_SESSION_INFO[0];
            if (RetVal)
            {
                arrSessionInfo = new WTS_SESSION_INFO[Count];
                int i;
                p = lpBuffer;
                for (i = 0; i < Count; i++)
                {
                    arrSessionInfo[i] =
                        (WTS_SESSION_INFO)Marshal.PtrToStructure(new IntPtr(p),
                        Session_Info.GetType());
                    p += Marshal.SizeOf(Session_Info.GetType());
                }
                WTSFreeMemory(new IntPtr(lpBuffer));
            }
            else
            {
                //Insert Error Reaction Here 
            }
            return arrSessionInfo;
        }

        public TSControl()
        {
            // 
            // TODO: 在此处添加构造函数逻辑 
            // 

        }


    }
}


"dmpadmin"字串改成你自己PC的用戶.

if (sb.ToString().Trim() == "dmpadmin")


參考資料

C# window Service实现调用有UI的应用程序(关于win xp以后的window系统)

取得Window UserName

Windows Service取得Window UserName的方法

[DllImport("Wtsapi32.dll")]
private static extern bool WTSQuerySessionInformation(IntPtr hServer, int sessionId, WtsInfoClass wtsInfoClass, out IntPtr ppBuffer, out int pBytesReturned);
[DllImport("Wtsapi32.dll")]
private static extern void WTSFreeMemory(IntPtr pointer);
 
private enum WtsInfoClass
{
    WTSUserName = 5, 
    WTSDomainName = 7,
}
 
private static string GetUsername(int sessionId, bool prependDomain = true)
{
    IntPtr buffer;
    int strLen;
    string username = "SYSTEM";
    if (WTSQuerySessionInformation(IntPtr.Zero, sessionId, WtsInfoClass.WTSUserName, out buffer, out strLen) && strLen > 1)
    {
        username = Marshal.PtrToStringAnsi(buffer);
        WTSFreeMemory(buffer);
        if (prependDomain)
        {
            if (WTSQuerySessionInformation(IntPtr.Zero, sessionId, WtsInfoClass.WTSDomainName, out buffer, out strLen) && strLen > 1)
            {
                username = Marshal.PtrToStringAnsi(buffer) + "\\" + username;
                WTSFreeMemory(buffer);
            }
        }
    }
    return username;
}


UI部分可以透過WMI取得

using System;
namespace WindowsServiceTest
{
    class Program
    {
        static void Main(string[] args)
        {
            System.Management.SelectQuery sQuery = new System.Management.SelectQuery(string.Format("select name, startname from Win32_Service")); // where name = '{0}'", "MCShield.exe"));
            using (System.Management.ManagementObjectSearcher mgmtSearcher  = new System.Management.ManagementObjectSearcher(sQuery))
            {
                foreach (System.Management.ManagementObject service in mgmtSearcher.Get())
                {
                    string servicelogondetails =
                        string.Format("Name: {0} ,  Logon : {1} ", service["Name"].ToString(), service["startname"]).ToString();
                    Console.WriteLine(servicelogondetails);
                }
            }
            Console.ReadLine();
        }
    }
}


參考資料

C# - How To Get Logged In User's Username and Track Activities from Windows Service

How do I retrieve the username that a Windows service is running under?

2017年7月27日 星期四

C# 找到 呼叫的Function的完整名稱

請參考以下的程式碼
MethodBase method = stackTrace.GetFrame(1).GetMethod();
string methodName = method.Name;
string className = method.ReflectedType.Name;
Console.WriteLine(className + "." + methodName);


How to find FULL name of calling method C#

C# WPF Textbox只能輸入數字

在引用的View.Xaml畫面裡面加入這行,做事件綁定。

這樣就可以做到只能輸入數字了。
DelayStartTimeTextBox.PreviewTextInput += StaticResourceModel.PreviewTextInput;
    public static class StaticResourceModel
    {
        public static void PreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            e.Handled = new System.Text.RegularExpressions.Regex("[^0-9]+").IsMatch(e.Text);
        }
    }

C# 泛型List加入到ObservableCollection

怕以後忘記,先寫起來。

首先先New一個ObservableCollection跟List。

並且在ObservableCollection的()內加入到你要放的List。

這樣就可以把List的資料轉移到ObservableCollection。


public ObservableCollection MyString = new ObservableCollection(new List());

C# ICommand 執行多個 Function 或加入參數

在 obj => 加入大括號,如下程式碼。

public ICommand ResetProgramCommand { get { if (_resetProgramCommand == null) { _resetProgramCommand = new RelayCommand(obj => {_event.ResetProgramEvent() , _event.UpdateProgramEvent()}, null); } return _resetProgramCommand; } }


如果是加入參數就變成以下這樣
string value = string.empty;
string result = "Success";

public ICommand ResetProgramCommand { get { if (_resetProgramCommand == null) { _resetProgramCommand = new RelayCommand(obj => {_event.ResetProgramEvent(),value = result;}, null); } return _resetProgramCommand; } }

C# 如何匯入外部DLL及如何傳值運作

今天被主管問到一個問題,.NET的參考元件順序是什麼? 一時答不出來,也沒有這樣的觀念,所以找了一些資料。

.NET參考元件的順序

1.GAC (C:\Windows\assembly)

2.執行exe檔底下同目錄的DLL檔

3.環境變數內的路徑,去尋找該DLL檔

讓我對.NET的參考元件順序有更深的認識

[.NET] 組件安裝與配置 / Assembly Install and Configuration

C# 如何匯入外部DLL及如何傳值運作

2017年7月24日 星期一

xml for linq 讀取

如果我有以下的XML檔案格式,但是想要取得LanguageInfo的參數,可以用以下的xml for linq的程式碼取得
 











首先宣告XDocument的物件,並給它檔案路徑去讀取,然後再new一個ObservableCollection的string泛型,透過linq的語法去取得attribute的參數,並轉成list在轉型放入到ObservableCollection。
XDocument allLanguage = XDocument.Load($@"{Properties.Settings.Default.ConfigPath}");

name = = new ObservableCollection((from data in allLanguage.Descendants("TaskManager").Descendants("Language") select data).Elements("LanguageInfo").Select(args => args.Attribute("name").Value).ToList());

value = new ObservableCollection((from data in allLanguage.Descendants("TaskManager").Descendants("Language") select data).Elements("LanguageInfo").Select(args => args.Attribute("value").Value).ToList());

如果是要放到一個類別裡面也可以這樣宣告

foreach(XElement element in (from data in allLanguage.Descendants("TaskManager").Descendants("Language") select data).Elements("LanguageInfo"))
{
StaticResourceModel.ComboBoxValue.Add(new ComboBoxValue() {Name= element.Attribute("name").Value , Value = element.Attribute("value").Value});
}

2017年6月20日 星期二

SQL Server 利用Linked server 連結到 MySQL Server

In this article let’s discuss the step by step procedure to create a linked server to MySQL from SQL Server. First, download the MySQL drivers from the location below. Choose the 32 bit or 64 bit versions as per SQL Server and Windows Server platform requirements. http://dev.mysql.com/downloads/connector/odbc/ Next, install the driver using .msi package

Select typical as option



Click on install, and this will install MySQL drivers onto the Windows Server. This needs to be run from the Windows machine that runs your SQL Server instance.



Once the driver is installed we need to make an ODBC entry for the MySQL server. To do this, go to run and type “odbcad32.exe” and hit enter. It will pop up below screen.



Click on Add. It will pop up below screen. Select “MySQL ODBC 5.3 Unicode Driver” and click on Finish.



Once we click on Finish, the below screen will pop up.



Enter the valid MYSQL server details in MySQL Connector/ODBC Data Source Configuration dialog box.



Click on Test, to validate the connection. If we are connecting to MySQL for the first time from this Windows server, we get error message as below.



To validate the host, run below command on the MySQL server. Make sure you are connected to the MySQL server as root or an equivalent user. GRANT ALL ON *.* to fooUser@''; Now click on Test, and the connection will be successfully established.



Click on details to set up a few more parameters. For better performance, I recommend using the below options.





Once the ODBC entry is set, configure MSDASQL in SSMS (SQL Server Management Studio).



Make sure the following four options are checked: Nested queries Level zero only Allow inprocess Supports ‘Like’ Operator For more info visit this link: http://technet.microsoft.com/en-us/library/ms191462%28v=sql.105%29.aspx



Now create the linked server in Management Studio.



Enter the ODBC record details we created in above steps. Make sure we selected "Microsoft OLEDB Provider for ODBC Drivers" as the Provider



Enter the security details for the server. Click on OK. It will create the linked server.

Test the linked server by right clicking and selecting test connection.



To verify the linked server through SQL statements, run below in query window of Management Studio: SELECT TOP 10 * FROM MYSQL...test_table
參考來源:http://www.sqlservercentral.com/articles/Linked+Server/115955/

2017年5月15日 星期一

C#委託的介紹(delegate、Action、Func、predicate)

委託是一個類,它定義了方法的類型,使得可以將方法當作另一個方法的參數來進行傳遞。事件是一種特殊的委託。 1.委託的聲明 (1). delegate delegate我們常用到的一種聲明 Delegate至少0個參數,至多32個參數,可以無傳回值,也可以指定傳回值類型。 例:public delegate int MethodtDelegate(int x, int y);表示有兩個參數,並返回int型。 (2). Action Action是無傳回值的泛型委派。 Action 表示無參,無傳回值的委託 Action 表示有傳入參數int,string無傳回值的委託 Action 表示有傳入參數int,string,bool無傳回值的委託 Action 表示有傳入4個int型參數,無傳回值的委託 Action至少0個參數,至多16個參數,無傳回值。 例:

public void Test(Action action,T p)
{
action(p);
}

(3). Func Func是有傳回值的泛型委派 Func 表示無參,傳回值為int的委託 Func 表示傳入參數為object, string 傳回值為int的委託 Func 表示傳入參數為object, string 傳回值為int的委託 Func 表示傳入參數為T1,T2,,T3(泛型)傳回值為int的委託 Func至少0個參數,至多16個參數,根據傳回值泛型返回。必須有傳回值,不可void 例:
 
public int Test(Funcfunc,T1 a,T2 b)
{
return func(a, b);
}

(4) .predicate predicate 是返回bool型的泛型委派 predicate 表示傳入參數為int 返回bool的委託 Predicate有且只有一個參數,傳回值固定為bool 例:public delegate bool Predicate (T obj) 2.委託的使用 (1).Delegate的使用

public delegate int MethodDelegate(int x, int y);
private static MethodDelegate method;
static void Main(string[] args)
{
method = new MethodDelegate(Add);
Console.WriteLine(method(10,20));
Console.ReadKey();
}

 
private static int Add(int x, int y)
{
return x + y;
}

(2).Action的使用

static void Main(string[] args)
{
Test(Action,"Hello World!");
Test(Action, 1000);
Test(p => { Console.WriteLine("{0}", p); }, "Hello World");//使用Lambda運算式定義委託
Console.ReadKey();
}
public static void Test(Action action, T p)
{
action(p);
}
private static void Action(string s)
{
Console.WriteLine(s);
}
private static void Action(int s)
{
Console.WriteLine(s);
}

可以使用 Action 委託以參數形式傳遞方法,而不用顯式聲明自訂的委託。 封裝的方法必須與此委託定義的方法簽名相對應。 也就是說,封裝的方法必須具有四個均通過值傳遞給它的參數,並且不能傳回值。 (在 C# 中,該方法必須返回 void)通常,這種方法用於執行某個操作。 (3).Func的使用

static void Main(string[] args)
{
Console.WriteLine(Test(Fun,100,200));
Console.ReadKey();
}
public static int Test(Func func, T1 a, T2 b)
{
return func(a, b);
}
private static int Fun(int a, int b)
{
return a + b;
}

(4). predicate的使用 泛型委派:表示定義一組條件並確定指定物件是否符合這些條件的方法。此委託由 Array 和 List 類的幾種方法使用,用於在集合中搜索元素。

static void Main(string[] args)
{
Point[] points = { new Point(100, 200),
new Point(150, 250), new Point(250, 375),
new Point(275, 395), new Point(295, 450) };
Point first = Array.Find(points, ProductGT10);
Console.WriteLine("Found: X = {0}, Y = {1}", first.X, first.Y);
Console.ReadKey();
}
private static bool ProductGT10(Point p)
{
if (p.X * p.Y > 100000)
{
return true;
}
else
{
return false;
}
}

使用帶有 Array.Find 方法的 Predicate 委託搜索 Point 結構的陣列。如果 X 和 Y 欄位的乘積大於 100,000,此委託表示的方法 ProductGT10 將返回 true。Find 方法為數組的每個元素調用此委託,在符合測試條件的第一個點處停止。 3.委託的清空 (1).在類中申明清空委託方法,依次迴圈去除委託引用。 方法如下:

public MethodDelegate OnDelegate;
public void ClearDelegate()
{
while (this.OnDelegate != null)
{
this.OnDelegate -= this.OnDelegate;
}
}

(2).如果在類中沒有申明清空委託的方法,我們可以利用GetInvocationList查詢出委託引用,然後進行去除。 方法如下:

public MethodDelegate OnDelegate;
static void Main(string[] args)
{
Program test = new Program();

 
if (test.OnDelegate != null)
{
System.Delegate[] dels = test.OnDelegate.GetInvocationList();
for (int i = 0; i < dels.Length; i++)
{
test.OnDelegate -= dels[i] as MethodDelegate;
}
}
}

4.委託的特點 委託類似于 C++ 函數指標,但它們是型別安全的。 委託允許將方法作為參數進行傳遞。 委託可用於定義回檔方法。 委託可以連結在一起;例如,可以對一個事件調用多個方法。 方法不必與委託簽名完全符合。 5.總結: Delegate至少0個參數,至多32個參數,可以無傳回值,也可以指定傳回值類型 Func可以接受0個至16個傳入參數,必須具有傳回值 Action可以接受0個至16個傳入參數,無傳回值 Predicate只能接受一個傳入參數,傳回值為bool類型 來源:http://fecbob.pixnet.net/blog/post/41199941-c%23%E5%A7%94%E8%A8%97%E7%9A%84%E4%BB%8B%E7%B4%B9%28delegate%E3%80%81action%E3%80%81func%E3%80%81predicate%29 詳細參考:HTTP://www.fengfly.com/plus/view-209140-1.html HTTP://www.cnblogs.com/foolishfox/archive/2010/09/16/1827964.html