2016年1月10日日曜日

C#のWPFのTextBoxで「数値入力専用」を実現するサンプルです。

C#のWPFのTextBoxで「数値入力専用」を実現するサンプルです。
改変自由です。 勝手に使ってください。 ただし、試行錯誤のコメントがそのままです。
Visual Studio 2015 で実験しています。

添付ビヘイビアにすることは面倒なのでしていません。その場合は次のサイトがお勧め:
http://d.hatena.ne.jp/hilapon/20101021/1287641423
添付ビヘイビアを使い TextBox で数値以外を入力できなくする。 - (憂国のプログラマ Hatena版 改め) 周回遅れのブルース

添付ビヘイビアにする際に、列挙体をWPFのデザイン時のプロパティに一覧するには TypeConverter を継承すると出来そうでした。
で [AttachedPropertyBrowsableForType(typeof(コンバーターの名前))] を使えばよいかと。
なお、Visual Studio 2013 で EnumConverter を使うとうまくできませんでした。


using System;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace WpfAppCSharp1
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        // ----
        // 以下は、「数値入力専用」を実現するサンプル。
        // ----

        // 数字の種類の定義。
        enum NumericInputTypeDef
        {
            NonNumericType,
            IntegerType,
            NonNegativeIntegerType,
            FloatingPointType,
            NonNegativeFloatingPointType,
        }

        // 数字の種類。
        private NumericInputTypeDef mNumericInputType = NumericInputTypeDef.FloatingPointType;

        // 数値の小数点以下の精度。 0 のとき精度を考慮しない。
        private uint mPrecision = 0;

        // 事前テキスト入力時 PreviewTextInput
        // テキスト入力に伴う変更前後を知ることが出来る。 Selection して Delete のときは反応してくれない。
        // ※なお、削除のみは TextChanged で知ることが出来る。
        // "TextInput" イベントは設定できるが発生しない。 e.Handled = True で入力キャンセルできる。
        private void txtNormalEvent_PreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            //var textBox = sender as TextBox;
            var textBox = e.Source as TextBox;
            if (textBox == null) return;

            var insertText = e.Text;

            var beforeText = textBox.Text;

            var afterText = beforeText;
            // 削除範囲あり。
            if (textBox.SelectionLength != 0)
                afterText = afterText.Remove(textBox.SelectionStart, textBox.SelectionLength);
            // 追加文字あり。
            if (e.Text.Length != 0)
                afterText = afterText.Insert(textBox.SelectionStart, e.Text);

            Int64 parsedInt64 = 0;
            UInt64 parsedUInt64 = 0;
            Double parsedDouble = 0;

            if (afterText.Length >= 1)
            {
                switch(mNumericInputType)
                {
                    case NumericInputTypeDef.NonNumericType:
                        break;
                    case NumericInputTypeDef.IntegerType:
                        if (!Int64.TryParse(afterText, out parsedInt64))
                        {
                            // "" "-" "-1" という入力手順を許可する。
                            if (!(beforeText == "" && afterText == "-"))
                                e.Handled = true;
                        }
                        break;
                    case NumericInputTypeDef.NonNegativeIntegerType:
                        // "-0" を許してしまう。 でも続きを入力できないので実害は無い。
                        if (!UInt64.TryParse(afterText, out parsedUInt64))
                        {
                            e.Handled = true;
                        }
                        break;
                    case NumericInputTypeDef.FloatingPointType:
                        if (!Double.TryParse(afterText, out parsedDouble))
                        {
                            // "" "-" "-1" という入力手順を許可する。
                            if (!(beforeText == "" && afterText == "-"))
                                e.Handled = true;
                        }
                        break;
                    case NumericInputTypeDef.NonNegativeFloatingPointType:
                        // "-0" を許してしまう。 でも続きを入力できないので実害は無い。
                        if (!Double.TryParse(afterText, out parsedDouble))
                        {
                            e.Handled = true;
                        }
                        else
                        {
                            if (parsedDouble < 0)
                            {
                                e.Handled = true;
                            }
                        }
                        break;
                }
            }

            Console.WriteLine("beforeText: [{0}]", beforeText);
            Console.WriteLine("afterText: [{0}]", afterText);
            Console.WriteLine("SelectionText, SelectionStart, SelectionLength: [{0}], [{1}], [{2}]",
                textBox.SelectedText,
                textBox.SelectionStart,
                textBox.SelectionLength
                );
            Console.WriteLine("InsertText: [{0}]", e.Text);
        }

        // テキスト変更時 TextChanged
        // 変更前後の数と位置と種類を知ることが出来るが追加文字列を知ることが出来ない。
        // e.Handled = True では入力キャンセルできないようです。
        // ※なお、追加文字列は PreviewTextInput で知ることが出来る。
        private void txtNormalEvent_TextChanged(object sender, TextChangedEventArgs e)
        {
        }

        // キー押下時 KeyDown
        // Shiftキーなどの面倒を見る必要があるので、使わないことにする。つまり $ でも 4 と勘違いされる。

        // 入るとき GotFocus
        // 入るときにテキストを全選択する。
        private void txtNormalEvent_GotFocus(object sender, RoutedEventArgs e)
        {
            //var textBox = sender as TextBox;
            var textBox = e.Source as TextBox;
            if (textBox == null) return;

            if (textBox.Text.Length != 0)
            {
                textBox.SelectAll();
            }
        }

        // 出るとき LostFocus
        // 出るときに空欄ならば "0" にする。 精度が設定と合っていないのならば直す。
        private void txtNormalEvent_LostFocus(object sender, RoutedEventArgs e)
        {
            //var textBox = sender as TextBox;
            var textBox = e.Source as TextBox;
            if (textBox == null) return;

            var currentText = textBox.Text;

            // 全角空白も半角空白も除外する。
            System.Text.RegularExpressions.RegexOptions regopt = System.Text.RegularExpressions.RegexOptions.Singleline;
            var reg = new System.Text.RegularExpressions.Regex(@"\s+", regopt);
            var textWithoutSpace = reg.Replace(currentText, "");

            // 空白が無いときに長さがゼロならば空欄だから "0" にする。
            if (textWithoutSpace.Length == 0)
            {
                textBox.Text = "0";
            }

            // 小数点以下の精度を考慮する場合は、カットしたり足したりする。
            if (mPrecision != 0)
            {
                Double parsedDouble = 0;

                if (currentText.Length >= 1)
                {
                    switch (mNumericInputType)
                    {
                        case NumericInputTypeDef.NonNumericType:
                            break;
                        case NumericInputTypeDef.IntegerType:
                            break;
                        case NumericInputTypeDef.NonNegativeIntegerType:
                            break;
                        case NumericInputTypeDef.FloatingPointType:
                            // break しないで続ける。
                        case NumericInputTypeDef.NonNegativeFloatingPointType:
                            // "-0" を許してしまう。 でも続きを入力できないので実害は無い。
                            if (!Double.TryParse(currentText, out parsedDouble))
                            {
                                e.Handled = true;
                            }
                            else
                            {
                                var afterText = parsedDouble.ToString("F" + mPrecision + "");
                                if (currentText != afterText)
                                    textBox.Text = afterText;
                            }
                            break;
                    }
                }
            }

        }

    }
}

2015年12月7日月曜日

HttpClient, WebClient, WebRequest での CancellationToken によるキャンセル操作のノウハウの寄せ集め。

// --------------------------------
HttpClient after dotNet4.5

http://stackoverflow.com/questions/9746182/where-is-webclient-downloadstringtaskasyncuri-cancellationtoken-in-vs11
c# - Where is WebClient.DownloadStringTaskAsync(Uri,CancellationToken) in VS11 - Stack Overflow

GetAsync(String, CancellarationToken) があるそうです。

でもなぜか、
    var result = await client.GetStringAsync();
ではなく
    var tskRes = client.GetStringAsync();
    while(!tskRes.Wait(TimeSpan.FromSeconds(0.2))) {
        ctoken.ThrowIfCancellarationRequested();
    }
    result = tskRes.Result;
のコードが記載されています。


// --------------------------------
HttpClient after dotNet4.5

http://stackoverflow.com/questions/30053792/async-await-with-cancellationtoken-doesnt-cancel-the-operation
c# - Async/await with CancellationToken doesn't cancel the operation - Stack Overflow

ここでは HttpClient は CancellarationToken が使えるので簡単だよね、となっているようです。


// --------------------------------
WebClient

http://stackoverflow.com/questions/30053792/async-await-with-cancellationtoken-doesnt-cancel-the-operation
c# - Async/await with CancellationToken doesn't cancel the operation - Stack Overflow

WebClient.CancelAsync メソッドで Cancel できるらしい。

    myToken.Register(myWebclient.CancelAsync);
としておくと token で操作可能らしい。


// --------------------------------
WebRequest

http://stackoverflow.com/questions/30053792/async-await-with-cancellationtoken-doesnt-cancel-the-operation
c# - Async/await with CancellationToken doesn't cancel the operation - Stack Overflow

ストリームをコピーするメソッドに token を受け付けるものがある。
ということのようです。
    var stream = response.GetResponseStream()
    var destStream = new MemoryStream()
    await stream.CopyToAsync(destStream, 4096, cancelToken);
    return Encoding.UTF8.GetString(destStream.ToArray());

http://stackoverflow.com/questions/9746182/where-is-webclient-downloadstringtaskasyncuri-cancellationtoken-in-vs11
c# - Where is WebClient.DownloadStringTaskAsync(Uri,CancellationToken) in VS11 - Stack Overflow

ですが、サーバーから待っているときもキャンセルしたいので、
上記のアイデアは使えるかもです。

つまり
    var response = await req.GetResponseAsync();
ではなく
    tskRes = req.GetResponseAsync();
    while(!tskRes.Wait(TimeSpan.FromSeconds(0.2))) {
        ctoken.ThrowIfCancellarationRequested();
    }
    result = tskRes.Result;
のように。


// --------------------------------
WebClient

.NET Framework/WebClientクラスでタイムアウトを変更する

では、継承してタイムアウトを追加する方法が記載されています。


// --------------------------------


C# で await/async を使ってみた。 何故か常に Task.IsCompleted == true になる。 動いているか、の判定に使えないので、困った。 dotNet4.5 で。

C# で await/async を使ってみた。 何故か常に Task.IsCompleted == true になる。 動いているか、の判定に使えないので、困った。 dotNet4.5 で。

// ----------------------------------------
// MainWindow.xaml.cs

//#define BY_THE_SLEEP
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfAppTestOnDotNet45
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
       

        //
        // Task.IsCompleted が常に true を返すようです。
        // そのため完了しているか否かは volatile 変数などで手動で管理する必要がありそうです。
        //

        private Task taskForCancelTestAsync = null;
        private System.Threading.CancellationTokenSource ctsForCancelTestAsync = null;

        private void btnCancelForCancelTestAsync_Click(object sender, RoutedEventArgs e)
        {
            var tsk = taskForCancelTestAsync;
            var cts = ctsForCancelTestAsync;

            if (tsk == null || cts == null)
            {
                MessageBox.Show("実行されていません。");
                return;
            }
            else if (tsk != null && (tsk.IsCanceled || /* tsk.IsCompleted || */ tsk.IsFaulted))
            {
                // 常に tsk.IsCompleted == true になります。
                // また tsk.Status == TaskStatus.RanToCompletion になっています。
                // よって
                // Cancel 出来るか、とか、Runできるか、といった判定に使えないようです。
                MessageBox.Show("既に完了しています。");
                return;
            }
            else if (cts != null && cts.IsCancellationRequested)
            {
                MessageBox.Show("キャンセル中です。");
                return;
            }
            else
            {
                //MessageBox.Show("実行中です。");
                //return;
            }

            try
            {
                var syncContextUI = System.Threading.Tasks.TaskScheduler.FromCurrentSynchronizationContext();

#if true
                tsk.ContinueWith((curTask) => {
                    MessageBox.Show("キャンセルできました。");
                }, syncContextUI);
                cts.Cancel();
#endif
#if false
                // これは「Cancel 時に実行」という意図があるが、MessageBox.Showが動かない。
                var cts2nd = new System.Threading.CancellationTokenSource();
                var ctoken2nd = cts2nd.Token;
                tsk.ContinueWith((curTask) => {
                    MessageBox.Show("キャンセルできました。[CancelOnly]");
                }, ctoken2nd, TaskContinuationOptions.OnlyOnCanceled, syncContextUI);
                cts.Cancel();
#endif
            }
            catch (TaskCanceledException ex)
            {
                // たぶんキャンセルする側のスレッドで呼ばれる例外。
                //      Sleep のときも Task.Delay のときも呼ばれなかった。
                MessageBox.Show("[btnCancel_Click]Error: TaskCanceledException");
                Console.WriteLine("[btnCancel_Click]TaskCanceledException:" + ex.ToString());
            }
            catch (OperationCanceledException ex)
            {
                // たぶんキャンセルされたスレッドで呼ばれる例外。
                //      Sleep のときも Task.Delay のときも呼ばれなかった。
                MessageBox.Show("[btnCancel_Click]Error: OperationCanceledException");
                Console.WriteLine("[btnCancel_Click]OperationCanceledException:" + ex.ToString());
            }
            catch (AggregateException exg)
            {
                //      Sleep のときも Task.Delay のときも呼ばれなかった。
                MessageBox.Show("[btnCancel_Click]Error: AggregateException");
                Console.WriteLine("[btnCancel_Click]AggregateException:" + exg.ToString());
                foreach (Exception ex in exg.InnerExceptions)
                {
                    Console.WriteLine("\t" + ex.ToString());
                }
            }
            catch (Exception ex)
            {
                //      Sleep のときも Task.Delay のときも呼ばれなかった。
                MessageBox.Show("[btnCancel_Click]Error: OperationCanceledException");
                Console.WriteLine("[btnCancel_Click]Exception:" + ex.ToString());
                throw;
            }

        }

        private void btnRunForCancelTestAsync_Click(object sender, RoutedEventArgs e)
        {
            var tsk = taskForCancelTestAsync;
            var cts = ctsForCancelTestAsync;

            if (tsk == null || cts == null)
            {
                //MessageBox.Show("実行されていません。");
                //return;
            }
            else if (tsk != null && (tsk.IsCanceled || tsk.IsCompleted || tsk.IsFaulted))
            {
                //MessageBox.Show("既に完了しています。");
                //return;
            }
            else if (cts != null && cts.IsCancellationRequested)
            {
                MessageBox.Show("キャンセル中です。");
                return;
            }
            else
            {
                MessageBox.Show("実行中です。");
                return;
            }

            if (tsk != null)
            {
                tsk.Dispose();
                tsk = null;
            }
            if (cts != null)
            {
                cts.Dispose();
                cts = null;
            }

            taskForCancelTestAsync = null;
            ctsForCancelTestAsync = null;

            try
            {

            }
            catch (Exception ex)
            {
                MessageBox.Show("[btnRun_Click]Error: OperationCanceledException");
                Console.WriteLine("[btnRun_Click]Exception:" + ex.ToString());
                throw;
            }
            ctsForCancelTestAsync = new System.Threading.CancellationTokenSource();
            var ctoken = ctsForCancelTestAsync.Token;
#if BY_THE_SLEEP
            taskForCancelTestAsync = System.Threading.Tasks.Task.Factory.StartNew(
                () =>
                {
                    CancelTestForAsync.Run(ctoken);
                }, ctoken);
#else
            taskForCancelTestAsync = System.Threading.Tasks.Task.Factory.StartNew(
                async () =>
                {
                    await CancelTestForAsync.Run(ctoken);
                }, ctoken);
#endif
        }
    }
}

// ----------------------------------------
// CancelTestForAsync.cs

//#define BY_THE_SLEEP
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WpfAppTestOnDotNet45
{
    class CancelTestForAsync
    {
#if BY_THE_SLEEP
        public static void Run(System.Threading.CancellationToken ctoken) // ← Sleep の場合の定義。
#else
        public static async Task Run(System.Threading.CancellationToken ctoken) // ← Delay の場合の定義。
#endif
        {
            Console.WriteLine("[CancelTestForAsync::Run]Start");
            for (int i = 0; i < 20; i++)
            {
                try
                {
#if BY_THE_SLEEP
                    System.Threading.Thread.Sleep(millisecondsTimeout: 20 * 1000);
#else
                    //     Task.Delay(millisecondsDelay: 20 * 1000, cancellationToken: ctoken);
                    // のように await が無い場合は、別スレッドを実行した後、すぐに続行するので意味が無いことに注意。
                    await Task.Delay(millisecondsDelay: 20 * 1000, cancellationToken: ctoken);
#endif
                    if (ctoken.IsCancellationRequested)
                    {
                        // Sleep の場合、ここに来る。 System.Threading.CancellationToken では Cancel 即座のキャンセルが出来ない。
                        Console.WriteLine("[CancelTestForAsync::Run]ctoken.ThrowIfCancellationRequested();");
                        ctoken.ThrowIfCancellationRequested();
                    }
                    Console.WriteLine("[CancelTestForAsync::Run]Delayed");
                }
                catch (TaskCanceledException ex)
                {
                    // たぶんキャンセルする側のスレッドで呼ばれる例外。
                    //      Sleep の場合、想定どおり、ここに来ない。
                    //      Task.Delay の場合、ここに来る。 await の中で Cancel が検知されると、ここに来るということ。
                    Console.WriteLine("[CancelTestForAsync::Run]TaskCanceledException:" + ex.ToString());
                    throw;
                }
                catch (OperationCanceledException ex)
                {
                    // たぶんキャンセルされたスレッドで呼ばれる例外。
                    //      Sleep の場合、想定どおり、ここで発生。 ctoken.ThrowIfCancellationRequested(); で呼ばれる、ということ。
                    Console.WriteLine("[CancelTestForAsync::Run]OperationCanceledException:" + ex.ToString());
                    throw;
                }
                catch (AggregateException exg)
                {
                    // Sleep の場合、想定どおり、ここに来ない。
                    Console.WriteLine("[CancelTestForAsync::Run]AggregateException:" + exg.ToString());
                    foreach (Exception ex in exg.InnerExceptions)
                    {
                        Console.WriteLine("\t" + ex.ToString());
                    }
                    throw;
                }
                catch (Exception ex)
                {
                    // Sleep の場合、想定どおり、ここに来ない。
                    Console.WriteLine("[CancelTestForAsync::Run]Exception:" + ex.ToString());
                    throw;
                }
            }
        }
    }
}

// ----------------------------------------

2015年12月6日日曜日

OfficeReadOnlyOpen.vbs - office read only open written by vb script. for microsoft excel, microsoft powerpoint, microsoft word.

WHAT IS THIS?
office read only open written by vb script. for microsoft excel, microsoft powerpoint, microsoft word.

HOW TO USE?
copy this file to "SendTo" folder, etc.
ex: C:\Users\<YourAccount>\AppData\Roaming\Microsoft\Windows\SendTo


'--------------------------------
Rem
Rem OfficeReadOnlyOpen.vbs
Rem


'--------------------------------
'----------------
'Check Argument
'----------------
'Check argument.
If WScript.Arguments.Count <> 1 Then WScript.Quit

'Get file name.
Dim strFileName
strFileName = WScript.Arguments(0)


'----------------
'Check Extension
'----------------
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")

Dim extName
extName = fso.GetExtensionName(strFileName)

Dim strRegularFileName
If extName <> "lnk" Then
    strRegularFileName = strFileName
Else
    'Get Shortcut TargetPath.
    If Not fso.FileExists(strFileName) Then
        strRegularFileName = strFileName
    Else
        Dim oWshShell
        Set oWshShell = CreateObject("WScript.Shell")
     
        Dim oShellLink
        Set oShellLink = oWshShell.CreateShortcut(strFileName)
     
        strRegularFileName = oShellLink.TargetPath
     
        extName = fso.GetExtensionName(strRegularFileName)
    End If
End If


'----------------
'Execute
'----------------
Dim objOfficeApp
If extName = "ppt" Or extName = "pptx" Then

    Set objOfficeApp = GetOrCreateObject("Powerpoint.Application")
    objOfficeApp.Visible = True
    'Open As ReadOnly.
    Call objOfficeApp.Presentations.Open(strRegularFileName, True)
 
ElseIf extName = "doc" Or extName = "docx" Then
 
    Set objOfficeApp = GetOrCreateObject("Word.Application")
    objOfficeApp.Visible = True
    'Open As ReadOnly.
    Call objOfficeApp.Documents.Open(strRegularFileName, , True)
 
ElseIf extName = "xls" Or extName = "xlsx" Or extName = "xlsm" Or extName = "xlsb" Then

    Set objOfficeApp = GetOrCreateObject("Excel.Application")
    objOfficeApp.Visible = True
    'Open As ReadOnly.
    Call objOfficeApp.Workbooks.Open(strRegularFileName, , True)
 
End If


'----------------
'Ending
'----------------
Set objOfficeApp = Nothing
WScript.Quit



'--------------------------------
Function GetOrCreateObject(ClassName)
    Dim objOfficeApp
    Dim isGetObjectError
 
    '----------------
    ' VBScript version GetObject(, class): return Existing instance. but occur ERROR if no instance is.
    ' WScript.GetObject(ProgID)          : return always NEW instance.
 
    '----------------
    'Get Existing application instance.
    On Error Resume Next
    Set objOfficeApp = GetObject(, ClassName)
    If Err.Number <> 0 Then
        isGetObjectError = True
    ElseIf objOfficeApp Is Nothing Then
        isGetObjectError = True
    End If
    On Error GoTo 0
 
    '----------------
    'Get New application instance.
    If isGetObjectError Then
        Set objOfficeApp = CreateObject(ClassName)
    End If
 
    '----------------
    'return instance.
    Set GetOrCreateObject = objOfficeApp
End Function
'--------------------------------

2015年11月29日日曜日

Sample code like GetOpt for C#

Sample code like GetOpt for C#

---- GetOpt.cs ----

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GetOptForConsole
{
    using GetOptDic = System.Collections.Generic.Dictionary<String, Object>;
    using GetOptList = System.Collections.Specialized.StringCollection;

    /// <summary>
    /// Analyze argument class.
    /// </summary>
    /// <example>
    /// src1 /MAT dir1\dir2\mat.txt src2 /material dir2\dir3\mat.txt /omi abc /dmy def src3 src4
    /// /MAT and /material : set to the same variable.
    /// </example>
    /// <code>
    /// string materialFile;
    /// var opt = new GetOpt();
    /// opt.Add("/MAT", c => materialFile = c);
    /// opt.Add("/material", c => materialFile = c);
    /// opt.Add("/omi", "");
    /// opt.Run(args);
    /// string omi = opt["/omi"];
    /// string mat = opt["/MAT"];    // throw ArgumentException
    ///
    /// string [] newArgs = opt.Args.ToString();
    /// --- OR ---
    /// foreach(string a in opt.Args) {
    ///     ...
    /// }
    /// --- OR ---
    /// if (opt.Args.Count >= 1) source1 = opt.Args[0];
    /// if (opt.Args.Count >= 2) source2 = opt.Args[1];
    /// </code>
    class GetOpt
    {
        /// <summary>
        /// Store option arguments.
        /// </summary>
        private GetOptDic mOptions = new GetOptDic();
        /// <summary>
        /// Store non option arguments.
        /// </summary>
        private GetOptList mArgs = new GetOptList();

        public GetOpt() { }
        public GetOpt(GetOpt iOriginal) { this.mOptions.Concat(iOriginal.mOptions); }

        /// <summary>
        /// Regist option argument (if action).
        /// </summary>
        /// <param name="iKey">Option name. (ex: /MAT)</param>
        /// <param name="iValue">Action. (ex: (Action \lt string \gt )(c => { materialPath = c; }) )</param>
        public void Add(string iKey, Action<string> iValue) { this.mOptions.Add(iKey, iValue); }
        /// <summary>
        /// Regist option argument (if string).
        /// </summary>
        /// <param name="iKey">Option name. (ex: /MAT)</param>
        /// <param name="iValue">Initial value. default is <seealso cref="String.Empty"/> 。</param>
        public void Add(string iKey, string iValue = "") { this.mOptions.Add(iKey, iValue); }
        /// <summary>
        /// Get option value. (if string)
        /// </summary>
        /// <param name="iKey">Option name. (ex: /MAT)</param>
        /// <returns>Option value. </returns>
        /// <exception cref="ArgumentException">Illigal argument. the value is action. </exception>
        public string this[string iKey]
        {
            get
            {
                object val = this.mOptions[iKey];
                if (val is string)
                {
                    // unboxing.
                    return (string)val;
                }
                else
                {
                    throw new ArgumentException(message: "Illigal argument. the value is action.", paramName: "iKey");
                }
            }
        }
        /// <summary>
        /// Get the collection of non option value.
        /// </summary>
        public System.Collections.Specialized.StringCollection Args
        {
            get
            {
                return mArgs;
            }
        }
        /// <summary>
        /// Analyze argument.
        /// </summary>
        /// <param name="args">Arguments. </param>
        public void Run(string[] args)
        {
            string curOption = "";
            foreach (string curArg in args)
            {
                if (curOption != "")
                {
                    if (this.mOptions[curOption] is string)
                    {
                        this.mOptions[curOption] = curArg;
                    }
                    else if (this.mOptions[curOption] is Action<string>)
                    {
                        var action = (Action<string>)this.mOptions[curOption];
                        action(curArg);
                    }
                    curOption = "";
                }
                else if (this.mOptions.ContainsKey(curArg))
                {
                    curOption = curArg;
                }
                else
                {
                    mArgs.Add(curArg);
                }

            }
        }
    }

    class SampleOfGetOpt
    {
        public static void SampleMain()
        {
            var originalArgs = new string[] { @"src1", @"/MAT", @"dir1\dir2\mat.txt", @"src2", @"/material", @"dir2\dir3\mat.txt", @"/omi", @"abc", @"/dmy", @"def", @"src3", @"src4" };

            string materialFile = "";
            var opt = new GetOpt();
            opt.Add("/MAT", c => materialFile = c);
            opt.Add("/material", c => materialFile = c);
            opt.Add("/omi", "");
            opt.Add("/dmy", "");
            opt.Run(originalArgs);

            Console.WriteLine("materialFile=[" + materialFile + "]");

            string omi = opt["/omi"];
            Console.WriteLine("/omi=[" + omi + "]");

            string dmy = opt["/dmy"];
            Console.WriteLine("/dmy=[" + dmy + "]");

            string mat = "";
            try
            {
                mat = opt["/MAT"];    // throw ArgumentException
                Console.WriteLine("/MAT=[" + mat + "]");
            }
            catch (Exception e)
            {
                Console.WriteLine("/MAT=[[" + e.ToString() + "]]");
            }

            foreach (string a in opt.Args)
            {
                Console.WriteLine("opt.Args=[" + a + "]");
            }
        }
    }
}



2013年3月15日金曜日

dynamic link library sample code


/* dynamic link library sample code */
/* It's copy free. */

#include <dlfcn.h> /* dlopen, etc */

typedef void (*func1_t) (int a);
typedef void (*func2_t) (int b);
typedef struct tag_funclist_t {
    func1_t  func1;
    func2_t  func2;
}   funclist_t;

#define DLL_FILE_NAME "libXXXX.so"

long load( void ** opp_handle, func_t * p_funclist )
{
    long ret = 0;
    void * p_handle = NULL;
    const char * p_error = NULL;
    const char * p_symbol = NULL;
    void * p_func = NULL;

    if ( ! opp_handle && ! p_funclist ) {
        ret = 1;
    }

    if ( ! ret ) {
        dlerror();
        p_handle = dlopen( DLL_FILE_NAME, RTLD_NOW );
        p_error = dlerror();  /* thread unsafe */
        if ( ! p_handle ) {
            ret = 1;
            fprintf( stderr, "[load] Could not found " DLL_FILE_NAME " [%s]\n", p_error );
        }
    }

    if ( ! ret && ! p_handle ) {
        if ( ! ret ) {
            p_symbol = "func1";
            p_func = p_funclist->func1 = (func1_t)dlsym( p_handle, p_symbol );
            p_error = dlerror();  /* thread unsafe */
            if ( ! p_func ) ret = 1;
        }
        if ( ! ret ) {
            p_symbol = "func2";
            p_func = p_funclist->func2 = (func2_t)dlsym( p_handle, p_symbol );
            p_error = dlerror();  /* thread unsafe */
            if ( ! p_func ) ret = 1;
        }
        if ( ret ) {
            fprintf( stderr, "[load] Could not found the symbol (%s) in " DLL_FILE_NAME ": %s\n", p_symbol, p_error );
        }
    }

    if ( opp_handle ) {
        *opp_handle = p_handle;
    }
    return ret;

}

long unload( void * p_handle )
{
    return dlcolose( p_handle );
}

int main ( int argc, char **argv )
{
    int ret = 0;
    void * p_handle = NULL;
    funclist_t funclist;
    funclist_t * p_funclist = &funclist;

    if ( ! ret ) {
        ret = load( p_handle, p_funclist );
    }
    if ( ! ret && ! p_funclist ) {
        int x;
        p_funclist->func1(x);
        p_funclist->func2(x);
    }
    if ( ! ret ) {
        ret = unload( p_handle );
    }
    return ret;
}

2013年3月7日木曜日

base64 source code "bin to ascii"


/*----------------------------------------------------------------
 * base64_bin_to_ascii.c
 *
 * This source code is double license under:
 *   The MIT License (X11 License)
 *   Apache License, Version 2.0
 *
 * Copyright (c) 2013-2013 elf17 chobitprogram.blogspot.com All Rights Reserved.
 ----------------------------------------------------------------*/
/*----------------------------------------------------------------
 * The MIT License (MIT)
 * Copyright (c) 2013-2013 elf17 chobitprogram.blogspot.com
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom
 * the Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
 * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
 * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 ----------------------------------------------------------------*/
/*----------------------------------------------------------------
 * Copyright elf17 chobitprogram.blogspot.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ----------------------------------------------------------------*/

/**
 * convert 3 bytes binary to 4 bytes ascii + NULL terminator by base64.
 * @return status
 * @retval -1 : error charactor is found.
 * @retval  0 : success.
 * @retval  1 : detect end of data.
 * @see l64a()
 */
int b64a(const unsigned char * src, int len, unsigned char * dst)
{
    int ret = 0;                        /* return code */
    static const unsigned char b64str[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    unsigned char s[4] = {0};           /* src 8 bits + NULL terminator */
    unsigned char d[5] = {0};           /* dst 6 bits + NULL terminator */
    unsigned char f[4] = {1,1,1,1};     /* dst flag. true if src not exist. */
    int i = 0;                          /* loop counter */
    if ( len == 0 ) {
        dst[0] = 0;                     /* NULL terminator */
        ret = 1;                        /* detect end of data */
    } else {
        if ( len >= 1 ) {       s[0] = src[0]; f[0] = 0;       f[1] = 0;       }
        if ( len >= 2 ) {       s[1] = src[1]; f[1] = 0;       f[2] = 0;       }
        if ( len >= 3 ) {       s[2] = src[2]; f[2] = 0;       f[3] = 0;       }
        d[0] = (( s[0] & 0xfc ) >> 2);
        d[1] = (( s[0] & 0x03 ) << 4) | (( s[1] & 0xf0 ) >> 4 );
        d[2] = (( s[1] & 0x0f ) << 2) | (( s[2] & 0xc0 ) >> 6 );
        d[3] = (( s[2] & 0x3f )     );
        for ( i = 0 ; i < 4 ; i++ ) {
            if ( f[i] != 0 ) {          /* src not exist */
                dst[i] = '=';           /* NULL terminator */
                ret = 1;                /* detect end of data */
                /* no break ... output is always (4+1) bytes. */
            } else if ( d[i] >= 64 ) {  /* error data */
                dst[i] = 0;             /* NULL terminator */
                ret = -1;               /* error data */
                break;
            } else {
                dst[i] = b64str[d[i]];  /* convert to base64 string */
            }
        }
    }
    dst[4] = 0;                         /* NULL terminator */
    return ret;
}

/**
 * convert binary to ascii by base64.
 * @return status
 * @retval -1 : error charactor is found.
 * @retval  0 : success.
 * @see l64a(), b64a()
 */
int base64_bin_to_ascii(const unsigned char * src, int len, unsigned char * dst)
{
    int ret = 0;                        /* return code */
    const unsigned char * s = src;
    unsigned char * d = dst;
    int i = 0;                          /* loop counter */
    for ( i = 0 ; i < len ;  i += 3, s += 3, d += 4 ) {
        ret = b64a( s, (len - i), d );
        if ( ret != 0 ) {
            break;
        }
    }
    /* if error */
    if ( ret < 0 ) {
        dst[0] = 0;
    } else if ( ret > 0 ) {
        ret = 0;
    }
    return ret;
}