さて、無駄話発展してきたBasicで書かれた素因数分解プログラムのC#への移植について進めてゆきましょう。

 

まずはオリジナルのプログラム)をストレートにC#に変えてゆきます。

:前回からの抜粋「このプログラムは、100~330行迄、数値をコンマ付き書式(”#,0”)で文字列として入力させるように指示し、前後の空白をトリムし、今度は折角入力させた','を削除して数値化するという前処理をして、340~430行までで素因数分解式の表示を行っています。

 

/////////////
//素因数分解
/////////////

using System;
using System.Diagnostics;    //Stopwatch使用の為

class PrimeFactor
{
    static void Main()
    {
        //コンソールへの入力指示
        Console.WriteLine("素因数分解します。");
        Console.WriteLine("任意の整数を入力して下さい。");
        Console.WriteLine("例えば、12,319と入力してEnterします。");
        Console.WriteLine("あるいは、99,400,891とか6,041,375,340とか、");
        Console.WriteLine("123,456,789,013、123,456,789,011(素数)、761,838,257,287(素数)など入力してEnterします。");

        //変数nyulの入力
        string nyul = Console.ReadLine();
        //入力データnyulの両端の空白を除去
        nyul = nyul.Trim();
        //入力データnyulから、カンマを削除した数値に変換
        nyul = nyul.Replace(",", "");
        int n = 0;
        Int32.TryParse(nyul, out n);

        //Stopwatchクラス生成
        Stopwatch sw = new Stopwatch();
        //開始
        sw.Start();
        Console.Write("{0} = ", String.Format("{0:#,0}", n));    //String.Format()による3桁毎のカンマ書式
        //素因数分解用変数
        int a;
        do
        {
            a = 2;
            while(a <= Math.Sqrt(n))
            {
              if(n % a == 0)
                {
                    Console.Write(" {0} * ", String.Format("{0:#,0}", a));
                    n /= a;
                    break;
                } 
                a += (a > 2) ? 2 : 1;    
//aが2なら+1、3以上なら+2する
            }
        } while(a <= Math.Sqrt(n));    //IF A > SQR(N) THEN *EXITの代替
        Console.WriteLine("{0}", String.Format("{0:#,0}", n));
        //終了
        sw.Stop();
        //所要時間表示
        TimeSpan ts = sw.Elapsed;
        Console.WriteLine("処理時間は、{0}分{1}秒{2}ミリ秒でした", ts.Minutes, ts.Seconds, ts.Milliseconds);
        //DOS窓を維持
        Console.ReadKey();
    }

Basic プログラムの処理内容毎に色分けし、それに対応するC#プログラムも色分けしていますので何をしているのかが分かると思います。

先ず、改行付き文字列出力はConsole.WriteLine、入力はConsole.ReadLine、文字列の前後窮迫文字除去はTrimメソッド、',' 文字の除去はReplaceメソッド、最後に文字列の整数変換はInt32.TryParse(手抜きでエラー処理省略)を使っています。

次に肝心の素因数分解の部分についてですが、

 

(1)最初に除数として使用する変数aを宣言します。

(2)一番外側のループとして、除数aを2に初期化する「対象値nの平方根(Math.Sqrt(n))迄」を条件とするdo~whileループ「必ず1回は実行される」を作ります。

(3)次にこのループの中に同じ条件の除数aを2に初期化しないループを作り、

(4-1)対象値naで除した剰余が0(C++だと"!(n % a)"と書きたくなりますね)、即ち 除算が出来れば "(除数) *" と出力し、対象値naで除してbreakで内側ループを抜け、新しい対象値nで同じ処理を続けます。

(4-2)対象値naで除算が出来なければ除数aを1または2増やします。(if文を使っても書けますが、ここでは「(条件式)? (trueの場合の値):(falseの場合の値)」を使っています。)

(5)aが増えてゆき、外側のループから抜け出した際にn(素数となる)を表示します。

 

という処理を行っています。一応パフォーマンスを調べるためにタイムを計っています。

 

実は、この処理を見ていて「再帰」でも処理できるよね、ということで、↑の赤字部分を外部関数PrintFactor(n);に置き換えてみました。PrintFactor関数の処理は同じコードとforループも試しましたが、サンプルの"987,654,321,987"で2マイクロ秒、↑のプログラムより1マイクロ秒遅かったです。再帰呼び出しによるスタック処理が多くなるためでしょうか?

 

    //xがiで割り切れるれるか否かを調べ、割り切れる限り因数を出力し、最後にiで除されたxを出力
    //なお、素数はiで除算されないのでそのままとなる

    static void PrintFactor(double x)
    {

        double i = 2;
        do
        {
            
//因数iで割り切れれば、除算後のxで同様の処理を行う
            if(x % i == 0)
            {
                Console.Write("{0:#,0} * ", i);
                //Console.Write("{0} * ", String.Format("{0:#,0}", i));    //これと同じ
                x /= i;
                PrintFactor(x);
                return;
            }
            i += (i > 2) ? 2 : 1;    
//aが2なら+1、3以上なら+2する
        } while(i <= Math.Sqrt(x));    //xの因数の最大値まで調べる
        //(iで除算可能であれば除算後の)素数xを表示
        Console.WriteLine("{0:#,0}", x);
    }
}

 

お口汚しでした。

 

前回はwebで見つけたBasicのサンプルプログラムから、「素因数分解」にかかわるものを4つ参照し、Active Basic 4.23で動くように修正しました。

 

今回はC#に移植するものを決めるうえで、それらのコードの内容を見てみましょう。

 

1.素因数分解(1) 

このプログラムは、100~330行迄、数値をコンマ付き書式(”#,0”)で文字列として入力させるように指示し、前後の空白をトリムし、今度は折角入力させた','を削除して数値化するという前処理をして、340~430行までで素因数分解式の表示を行っています。

 

340 STARTT=VAL(LEFT$(TIME$,2))*3600+VAL(MID$(TIME$,4,2))*60+VAL(RIGHT$(TIME$,2))
350 PRINT N;"=";
360   A=2
370   IF A>SQR(N) THEN 430
380   IF N-INT(N/A)*A=0 THEN 410
390   IF A>2 THEN A=A+2 :GOTO 370
400   A=A+1 :GOTO 370
410 PRINT A; "*" ;
420 N=N/A : GOTO 360
430 PRI

 

実際の素因数分解は360~420で、対象値Nの因数をチェックするAの最大値をNの平方根とし(370行-注)、Aが最大値に満たないならば、「NをAで除算した剰余(N MOD A = N - (INT)(N / A))」をチェックし、0(割り切れる)ならばAは因数となり(380行)、因数Aと乗算演算子(*)を表示させて、対象地Nを因数Aで除算して同じ処理を繰り返します(410~420行)。割り切れない場合(Nは奇数)には、Aが2の場合には3(A=A+1)にし、3以降は2づつ増やし(2の倍数==偶数は2でチェック済だから)、同じチェックを続けて、最後に(除算できれば除算されて)素数となったNを表示(430行)します。

注:Nの平方根以上チェックしても、Nの平方根以下のチェックと重複するだけなので...

ここで注意していただきたいのは、ループが素数の場合の370←→390(または400)と、非素数の場合の360→380→410・420→360とで交差していることです。

 

2.素因数分解(2) 

これは実に簡潔にコーディングされていますが、「N=素因数x素因数x...」という出力になっていないのとインデントによるループ構造が分かりづらいので前回書き換えた方を見てください。これもGOTO+最大値チェックのループをFOR~NEXTのループとしているだけで、素因数チェックのアルゴリズムは基本的には↑の(1)と変わりません。ただし、FOR~NEXTのループなので「3以降は2づつ増やし」手はいませんね。

 

3.素因数分解(3)

これはActive Basic的なプログラミングで素因数チェック部分は独立した関数に纏められています。でその関数の内容を見ると、まず「(素数の)2の倍数を総てチェックし(注)」、「その後(↓)3以降の奇数(d += 2)を、対象値xを調査値(d)で整数除算した値(q)が調査値(d)より大きい((q >= d) == (x \ d >= d) == (x >= d ^ 2) == (SQR(x) >= d))限り、チェックする」処理を行っています。これは一見異なるアルゴリズムのように見えて、実は最初の偶数チェックを併せると最初のアルゴリズムと同じになることが分かります。(「3以降は2づつ増やし」も同じですね。)

    d = 3
    q = x \ d
    While q >= d
        If x Mod d = 0 Then
            Print d; "* ";
            x = q
        Else
            d += 2
        End If
        q = x \ d
    Wend
注:確かに対象値が2の場合、自身が素数の2はチェックする必要がありませんね。

 

4.素因数分解(4)

これはDO UNTIL(条件式)~LOOP(注)を使っていますが、基本的なアルゴリズムは上記例と変わりません。(修正版では最初の例の"DO UNTIL n=1"にしていますが、「改良版」で"DO UNTIL f>SQR(n)"にしており、更に上記(3)と同じように偶数、奇数処理に分離したものも載せています。いずれにせよ同様のアルゴリズムです。

注:Active BasicにもDo~Loop While | Until(条件式)がありますが、シンタックスエラーが出て正しく動作しないので修正版ではWhile~Wendを使いました。

 

以上のように、皆さんそれぞれの工夫がありますが、基本的なアルゴリズムは同様なので、処理的にUIが丁寧な(1)のサンプルをもとにC#に移植してみることにします。

 

相変わらず「大儀あるプログラミングネタ」が尽きていて、暇つぶしを考えていた所、昔ウィンドウズプログラミングの端緒を掴んだ「大恩あるActive BasicのサンプルをC#に移植して遊んでみようか?」という遊び心が生じました。

 

早速webを漁ってみた所、

素因数分解(1) ・・・UI表示といい、変数名といい、冗漫性といい、生真面目な方のコードですね。

素因数分解(2) ・・・「なーんだ簡単じゃんか」と言わせるような簡潔な(しかし説明っ気ゼロの)コードですね。

素因数分解(3) ・・・これは唯一Active Basicっぽいコードです。

素因数分解(4) ・・・これも簡潔なコードですが、DO~LOOP UNTIL、DO~LOOP WHILEを持つBasicですね。

等のサンプルが見つかりました。素因数分解(3)以外は「総て大文字」「文字変数名の末尾に$」「代入にLET」を使う等、N88BASIC等の古いMicrosoft Basicの風情がありますね。

 

でも、これらは本当に動くのでしょうか?

 

現在の私のPC環境で使えるBasicは、次の通りであり、

(1)64bit Windows 11マシン・・・MSCompAssで使うVB.NET(vbc.exe)のみであり、↑のような古いBasicプログラムは完全書き換えが必要用です。

(2)32bit Windows 10マシン・・・未だにActive Basicを持っていますが、インタープリターの2.62や不完全な5は使っていないので、コンパイラーの4.23のみインストールしています。

上記4プログラムをActiveBasic4.23で実際に動かしてみようとコンパイルしてみました。

しかし、

いずれのコードも、次の理由からオリジナルの状態ではコンパイルできません。

(1)Active Basicの予約語は"最初大文字、以下小文字"(例:"PRINT"→"Print"、"INPUT"→"Input")で、大文字小文字区別があり、ほとんどすべての予約語を書き換える必要がある。

(2)昔のBASICは変数の宣言や型の指定が不要でしたが、Active BasicはDim (変数名) As (型名)が必須です。

(3)昔のBASICのLINE INPUT(文字列の入力)等一部の命令語がActive Basicにはなかったり、INKEY$がInkey$()だったり関数名が微妙に変わっている。

 

ということで、まずはサンプルコードをActiveBasicで動くように(及び同じような出力となるように)修正してみました。

 

【素因数分解(1)】

#prompt
Dim NYUL As String, NYUR As String, SUU As Double, N As Double, A As Double, STARTT As Double, ENDTIME As Double, MINUTE As Double
100 ' 素因数分解
110 Print "素因数分解します。"
120 Print "任意の整数を入力して下さい。"
'130 Print "例えば、12,319と入力してEnterします。"
130 Print "例えば、12319と入力してEnterします。"
'140 Print "あるいは、99,400,891とか6,041,375,340とか、"
140 Print "あるいは、99400,891とか6041375340とか、"
'150 Print "123,456,789,013、123,456,789,011(素数)、761,838,257,287(素数)など入力してEnterします。"
150 Print "123456789013、123456789011(素数)、761838257287(素数)など入力してEnterします。"
'160 NYUL=""
170 Input NYUL 'Line Input NYUR
180 '入力データの両端の空白を除去
190 IF Left$(NYUR,1)=" " THEN 
200 NYUR=Right$(NYUR,LEN(NYUR)-1) : GOTO 190
210 END IF
220 IF Right$(NYUR,1)=" " THEN 
230 NYUR=Left$(NYUR,LEN(NYUR)-1) : GOTO 220
240 END IF
250 '***入力データから「,」を削除した数値に変換
'260 SUU=InStr(1,NYUR,",")
'270 IF SUU=0 THEN GOTO 310
'280 NYUL=NYUL & Left$(NYUR,SUU-1)
'290 NYUR=Right$(NYUR,LEN(NYUR)-SUU)
'300 GOTO 260
'310 NYUL=NYUL & NYUR
320 N=Val(NYUL)
330 '***「,」削除の終了
340 STARTT=Val(Left$(Time$(),2))*3600+Val(Mid$(Time$(),4,2))*60+Val(Right$(Time$(),2))
350 Print N;"=";
360         A=2
370         IF A>Sqr(N) THEN 420
380         IF N-Int(N/A)*A=0 THEN 400
390         A=A+1 :GOTO 370
400 Print A; "*" ;
410 N=N/A : GOTO 360
420 Print N
430 ENDTIME = Val(Left$(Time$(),2))*3600+Val(Mid$(Time$(),4,2))*60+Val(Right$(Time$(),2))
440 MINUTE=(ENDTIME-STARTT)\60
450 Print USING"処理時間は、####分 ##秒でした。";MINUTE,(ENDTIME-STARTT)-MINUTE*60
460 Print "Hit any key ..."
While(Inkey$() = "")
Wend
END
 

【素因数分解(2)】

#prompt
Dim a As Double, m As Double, n As Double
100 '!!素因数分解!!
110 Input "素因数分解したい数を入力:", a
Print a; " = ";
120 Let m = Int(Sqr(a))
130 For n = 2 TO m
140     If a - n * Int(a / n) = 0 Then
150         Print n; " * ";
160         Let a = a / n
170         Goto 120
180     End If
190 NEXT n
200 Print a
205 While(Inkey$() = "") : Wend
210 End
 

【素因数分解(3)】

'#strict
#prompt

'Sub Factorize(x As Long)
Sub Factorize(x As Double)
    Print x; " = ";
    While x >= 4 And (x Mod 2) = 0
        Print "2 * ";
        x /= 2
    Wend
'    Dim d As Long, q As Long
    Dim d As Double, q As Double
    d = 3
    q = x \ d
    While q >= d
        If x Mod d = 0 Then
            Print d; "* ";
            x = q
        Else
            d += 2
        End If
        q = x \ d
    Wend
    Print x
End Sub

'Dim x As Long
Dim x As Double
Input x
Factorize(x)

While(Inkey$() = "") : Wend
End

 

【素因数分解(4)】

#prompt
Dim n As Double, f As Double
100 Input "素因数分解する数を入力してください:", n
Print n;" = ";
110 Let f = 2
'120 DO UNTIL n = 1
'120 Do
While n > 1
'130     Do While Mod(n, f) = 0
130     While n mod f = 0
140         Print f;" * ";
150            Let n = n / f
'160     Loop
160     Wend
170     Let f = f + 1
'180 Loop Until n = 1
'180 Loop While n > 1
Wend
Print "1"
While(Inkey$() = "") :Wend
190 End
 

これらはこのままActive Basic(注)で動きます。興味のある方は動かしてみてください。

注:ActiveBasic Ver4.23.00 - 3.29MB(解凍後 7.14MB)

 

次回はこのようなBasicプログラムをC#に移植してみます。移植はプログラミングの楽しみでもあり、学習にも効果があるので是非試していただきたいと思います。

 

昨日はQB64と出会ったので、その話をしましたが、サンプルプログラムは今一つ刺さらないので、今度は昔のファイルを漁ってみました。

 

すると、(どんなものか確認までにDLした)Dev-C++(もうシステムは消してしまいましたが...何か?)にOpenGLとDirect3Dのサンプルがあり、BCC102でもそのままコンパイル出来るか否か確認してみました。

 

OpenGLの方は、一応コンパイル前にインクルードファイル(gl.h)をチェックしてコンパイルし、見事に難なく成功しました。所がDirect3Dの方は、こちらも一応コンパイル前にインクルードファイル(d3d9.hとd3dx9.h)がBCC102(...BCC102\include\windows\sdk\gl) にあることをチェックし、コンパイルしましたが、プログラムに3つある演算系のD3DXMatrix~関数が見つからない、というエラーが出てコンパイルできません。

 

この為、再度BCC102のlibフォールダーを精査、ツールを使ってD3DX...libらしき関数にD3DXMatrix~関数がないかチェックし、webでd3dx9.libを落とし、コンパイルすると「OMFじゃない」というエラーで(よせばよいのに)COFF2OMFで変換して試したり...結局コンパイルできません。

 

本日「要すればD3DXMatrix~関数があるDLLを入手して、implibツールでlibファイルを作ればよい」と思い、チェックしたら、d3dx9.dllはすでにレガシー(現在の私のWin 11マシンはDirectX 12)であり、昔のDirectX 9パッケージは入手しましたが、「そこまでやることか?」という現実にはっと気が付き、矢張りやめる(OpenGLが動くだけで良しとする)ことにしました。(注)

注:Direct3DやOpenGLが使えるようになってもそれで何か作ろうとは考えていないので...軟弱?

 

まぁ、ネタがないとはいえ、本当に暇つぶしの領域であがいています。

 

ps. ついでですが、ご本家MicrosoftのDirect Xですが、C#で利用するのはちょっとめんどいみたいです。また、C#でOpenGLを使うにはOpenTKというDLLを入手して

using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;

等として使うらしいです。

またまた無駄話のお時間です。

 

私が初めてIBM PC互換機を手に入れたのは、1991年に米国駐在したときに遡ります。当時は確かIntel チップが80286から80386(廉価版の80386Xを含む)に移行する時期で、16bitから32bit化が進むときでした。(当時のクロックスピードが33MH、メモリーが1MB以下、ディスプレーは640 x 480 VGA、HDDが数10MBだったと記憶しています。)

 

同時にこの時初めてWindows(Windows 3.0-16bit版)に触れるのですが、この時のWindowsはOSのラッパーであり、OS自体はMS-DOS 5.0(注1)というもので、Windows 3.0はグラフィカルユーザーインターフェース(GUI)+ツール(File Manager、カレンダー、電卓等)でしかなかったので、初めはDOS 5と"MS-DOS Shell"があればWindowsを使うメリットはあまりありませんでした。(注2)

注1:以下DOS 5。フロッピーディスクで配布されていた。

注2:Windowsが1MBのメモリーを大分食うのでかえってアプリの負担が大きくなる。

 

こんなPC"原始時代"でも楽しかったのは、DOS 5におまけでついてくる開発ツールのQBasicでした。このBasicの統合開発環境(IDE-今からいうとIDEというのはおこがましい感じですが...)はDOSベースでしたがGUIも備えており、エディターによるコーディング、実行(確かインタープリターだったと思う...)、デバッギングもこなせました。これを使って当時の米国現地法人スタッフの為に簡単な業務アプリを作ったことを記憶しています。

 

そんなQBasicでしたが、昔のBasicではなく、構造化プログラミングや局所変数による再帰呼び出しもできる面白いプログラミング言語でした。

 

本日webでウロウロしていたら、偶然QB64というプログラミング言語がフリーで提供されていることを発見しました。インターフェースは当時のままですが、GUIでのウィンドウプログラミングツールなどもあるようで、Basic フリークの方ならば1MB程度のものなのでDLして遊んでみるのもよいかと。(かくいう私はメインのPCのSSDが512GBしかないのと、色々と言語を浮気しても始まらないので一旦ローダーを落とすも、インストールはやめることにしました。)

 

私の本来の目的は(QB64でノスタルジアに浸ることではなく)、このサイトでのサンプルプログラムを眺めることです。多くは1990年代のクソゲーソフトですが、何かレトロでそれも楽しいものです。何か移植してみようかな?

 

前回の最終回でVisual Studioが作成した*.csファイルの名前空間(using なんちゃら)で多くの名前空間をコメントアウトしました()が、為念その内容を確認したのでシェアします。矢張りリソースやXAML言語処理関連ですね。

注:以下の通り。

using System;
using System.Collections.Generic;

//using System.Diagnostics;
using System.Drawing;
//using System.Linq;
using System.Reflection;        //Assemblyを使う為
using System.Text;

//using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;

//using System.Windows.Automation;
//using System.Windows.Controls;
//using System.Windows.Controls.Primitives;
//using System.Windows.Data;
//using System.Windows.Documents;
//using System.Windows.Ink;
//using System.Windows.Input;
//using System.Windows.Markup;
//using System.Windows.Media;
//using System.Windows.Media.Animation;
//using System.Windows.Media.Effects;
//using System.Windows.Media.Imaging;
//using System.Windows.Media.Media3D;
//using System.Windows.Media.TextFormatting;
//using System.Windows.Navigation;
//using System.Windows.Shapes;
//using System.Windows.Shell;
//音声認識エンジン

using System.Speech.Recognition;

 

【コメントアウトした名前空間のMicrosoft Learn URL】

 

System.Diagnostics https://learn.microsoft.com/ja-jp/dotnet/api/system.diagnostics?view=net-7.0
System.Linq https://learn.microsoft.com/ja-jp/dotnet/api/system.linq?view=net-7.0
System.Threading https://learn.microsoft.com/ja-jp/dotnet/api/system.threading?view=net-7.0
System.Threading.Tasks https://learn.microsoft.com/ja-jp/dotnet/api/system.threading.tasks.task?view=net-8.0
System.Windows.Automation https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.automation.automation?view=windowsdesktop-7.0
System.Windows.Controls https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.controls?view=windowsdesktop-8.0
System.Windows.Controls.Primitives https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.controls.primitives?view=windowsdesktop-8.0
System.Windows.Data https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.data?view=windowsdesktop-8.0
System.Windows.Documents https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.documents?view=windowsdesktop-7.0
System.Windows.Ink https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.ink?view=windowsdesktop-7.0
System.Windows.Input https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.input?view=net-7.0
System.Windows.Markup https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.markup?view=net-7.0
System.Windows.Media https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.media?view=windowsdesktop-7.0
System.Windows.Media.Animation https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.media.animation?view=windowsdesktop-7.0
System.Windows.Media.Effects https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.media.effects?view=windowsdesktop-7.0
System.Windows.Media.Imaging https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.media.imaging?view=windowsdesktop-7.0
System.Windows.Media.Media3D https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.media.media3d?view=windowsdesktop-7.0
System.Windows.Media.TextFormatting https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.media.textformatting?view=windowsdesktop-7.0
System.Windows.Navigation https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.navigation.navigationservice?view=windowsdesktop-7.0
System.Windows.Shapes https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.shapes?view=netframework-4.8
System.Windows.Shell https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.shell?view=windowsdesktop-7.0
System.Speech.Recognition https://learn.microsoft.com/ja-jp/dotnet/api/system.speech.recognition.speechrecognitionengine?view=netframework-4.8

 

今回はVisual Studio(VS)が作成したファイルをMSCompAss用に手作業で修正してみます。

なお、今回のサンプルが簡単だったのでこのようなことが出来ますが、多くのリソースやコントロール、込み入ったフォームや複雑な処理がある場合は手作業ファイルでは開発が難しいことをあらかじめ断っておきます。

 

今回の「翻訳」のプロセスは、

(1)先ず、「VSが作成し、管理する複数のファイルが何を作っているのか?」を理解する→前回までにやりましたね。

(2)「VSが作成したファイルで利用できるものは再利用する」→今回のコードをご覧ください。

(3)必要な再修正を行う。(後述)

という形で行います。

 

(1)「VSが作成し、管理する複数のファイルが何を作っているのか?」

一つのフォームに位置決めのグリッドを配置し、テキストボックスを入れ、スクロールバーをつけたフォームにしています。これは余りオリジナルにこだわらず、フォームにスクロールバー付きのテキストボックスを配置するだけにします。なお、ついでにアンカーも打っておきましょう。

 

(2)「VSが作成したファイルで利用できるものは再利用する」

先ず使用するDLLを使う宣言を行う"using"ステートメントは総て採用しましたが、中には使わないのに宣言しているものもありそうです。(注)それはコメントアウトして不具合が生じるか否かをチェックしました。

また、肝心の音声認識についてはMainWindow.xaml.csのファイルに必要な処理が描かれているのでそれを使いました。

注:ソリューションやプロジェクトの管理処理やXML用のものもあります。

 

(3)必要な再修正

上記(2)をチェックしながらコンパイルし、実行しましたが、すぐにエラーになります。

がっかりしましたが、めげずにエラーメッセージを読むと「必要なデータが無く,...」などと書かれており、「あ"~、音声入力用のマイクがないんだ!」ということで、USBのカメラ・マイクをつなぐと無事稼働。なので、try~catchを入れてエラー処理を追加しました。なお、改行コードはオリジナルでは'\n'でしたが、私は敢えて"\r\n"にしています。最後に音声認識用のSpeechRecognitionEngineクラスのインスタンスはアンマネージドのようで最後にDispose()することをお忘れなく。

 

どうでしょう?一つのファイルに纏められ、随分コンパクトになった感があります。

一応動くようになりましたが、(元々のサンプルからしてそうですが)きちんと認識するには辞書が充実しないとだめですね。また、同じプログラムを静粛な64bit Win 11マシンと32bit Win 10マシンで稼働させると、後者はファンの音("ン~")が入るので可笑しな変換になりました。

 

まぁ、暇つぶしの探検、ということでお付き合い願いました。では、またネタ探しの旅に出ます。

 

【Dictation_SSpeech.cs】

//----------------------
// Dictation_SSpeech.cs
//----------------------

using System;
using System.Collections.Generic;

//using System.Diagnostics;
using System.Drawing;
//using System.Linq;
using System.Reflection;        //Assemblyを使う為
using System.Text;

//using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;

//using System.Windows.Automation;
//using System.Windows.Controls;
//using System.Windows.Controls.Primitives;
//using System.Windows.Data;
//using System.Windows.Documents;
//using System.Windows.Ink;
//using System.Windows.Input;
//using System.Windows.Markup;
//using System.Windows.Media;
//using System.Windows.Media.Animation;
//using System.Windows.Media.Effects;
//using System.Windows.Media.Imaging;
//using System.Windows.Media.Media3D;
//using System.Windows.Media.TextFormatting;
//using System.Windows.Navigation;
//using System.Windows.Shapes;
//using System.Windows.Shell;
//音声認識エンジン

using System.Speech.Recognition;

namespace Dictation_SSpeech
{
    ///////////////////////////
    //エントリーポイントクラス
    ///////////////////////////

    class MainApp
    {
        [STAThread]
        public static void Main()
        {
            Application.Run(new MainWindow());
        }
    }

    public partial class MainWindow : Form
    {
        //MainWindowクラスの変数
        SpeechRecognitionEngine recogEngine;
        TextBox TBox;

        //コンストラクター
        public MainWindow()
        {
            Assembly myOwn = Assembly.GetEntryAssembly();
            this.Icon = Icon.ExtractAssociatedIcon(myOwn.Location);    //プログラムアイコンをフォームにつける
            this.Load += new EventHandler(MainForm_Load);
            this.Text = "MainWindow Name";
            this.ClientSize = new Size(525, 350);
            this.MinimumSize = new Size(525, 350);
            this.BackColor = SystemColors.Window;
        }
        
        //WM_CREATE時処理
        private void MainForm_Load(object sender, EventArgs e)
        {
            //コントロールの設定
            InitializeComponent();
            recogEngine = new SpeechRecognitionEngine();
            // 音声認識が認識処理を終えたときのイベントハンドラを設定する。
            recogEngine.SpeechRecognized += recogEngine_SpeechRecognized;
            // 音声認識が推定処理を終えたときのイベントハンドラを設定する。
            recogEngine.SpeechHypothesized += recogEngine_SpeechHypothesized;
            // SystemSpeech を利用したディクテーションを行う場合には、
            // DictationGrammar (ディクテーション用の辞書) を追加する。
            recogEngine.LoadGrammar(new DictationGrammar());
            try
            {
                // 実行環境の標準の入力を音声認識エンジンの入力とする
                recogEngine.SetInputToDefaultAudioDevice();
                // 非同期の認識を継続して実行するようにして音声認識を開始する。
                recogEngine.RecognizeAsync(RecognizeMode.Multiple);
                MessageBox.Show("音声認識を開始します", "通知", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch
            {
                MessageBox.Show("音声標準入力がありません", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        //コントロールの設定
        public void InitializeComponent()
        {
            //テキストボックス
            TBox = new TextBox();
            //位置
            TBox.Location = new Point(10, 10);
            TBox.Anchor = (AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Bottom | AnchorStyles.Right);
            //サイズ
            TBox.Width = ClientSize.Width - 20;
            TBox.Height = ClientSize.Height - 20;
            //その他
            TBox.Multiline = true;
            TBox.ScrollBars = ScrollBars.Both;
            TBox.WordWrap  = false;
            //FormにTextBoxを追加
            this.Controls.Add(TBox);
        }

        // 推定時の処理
        void recogEngine_SpeechHypothesized(object sender, SpeechHypothesizedEventArgs e)
        {
            this.TBox.Text = "○" + e.Result.Text + "("+ e.Result.Confidence + ")\r\n" + this.TBox.Text;
        }

        // 認識時の処理
        void recogEngine_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
        {
            this.TBox.Text = "●" + e.Result.Text + "(" + e.Result.Confidence + ")\r\n" + this.TBox.Text;
        }

        //終了時処理
        protected override void OnClosed(EventArgs e)
        {
            base.OnClosed(e);
            // 終了時には破棄する。
            recogEngine.Dispose();
        }
    }
}
 

前回はVisual Studioが作成したWPFアプリのDictation_SSpeechにかかわるファイル一式がどのように保存されているかを調べてみました。今回はプロジェクト("WpfApplication1"-Visual Studioの命名です)がどのようなファイルから構成されているかを見てみましょう。

(1)リソース
Resource.Designer.csファイル(後掲)で、Resourceクラスを定義しており、ResourceManagerプロパティでアプリケーションに埋め込んだ"WpfApplication1.Properties.Resources"というリソースファイルにかかわるリソースマネージャー(private static global::System.Resources.ResourceManager resourceMan;)を取得(get)できます。また、Culturerプロパティでリソースのカルチャー()(private static global::System.Globalization.CultureInfo resourceCulture;)を取得(get)または設定(set)できます。

注:技術系の方は横棒とマイナス記号の誤読を回避するためにカタカナを横棒無しで記述する伝統があります。(例:カルチャーは「カルチャ」)私は文系だし、読者もそうだと思うので普通に書きますね。
また、xmlファイル(*.xml)とかxmalファイル(*.xaml)とかが出てきますが、これは「XML と XAML の違いは、前者が Extensible Markup Language を指し、後者が Extensible Application Markup Language を指すことです。 一方、前者はマークアップ言語であり、標準一般化マークアップ言語または SGML の非常に複雑なメカニズムを奪われています。後者は XML 自体のサブセットです。XMLドキュメントは、XAML ドキュメントと比較してはるかに柔軟です。」(出典)ということだそうです。


(2)システム設定
Settings.Designer.cs(後掲)というファイルでは、System.Configuration.ApplicationSettingsBaseというクラスから派生させたSettings(internal sealed partial class)というクラスのインスタンスを取得するためのファイルです。実行ファイルの設定にかかわる情報取得のためのもののようです。

(3)実行ファイルのフォーム(ウィンドウ)
MainWindow.xamlというxmlファイル(後掲)があり、これはどうもメインフォームを「高さ350、幅525」に、Grid()にScrollViewerを入れ、その中に"textBox"という名のTextBoxを入れるよう記述しているようです。
注:PC環境の違いにかかわらず正確なウィンドウとコントロール配置を行うオブジェクト。出典

MainWindow.g.cs(後掲)とMainWindow.g.i.csというファイルがありますが、その内容は見た目、まったく同じです。このファイルはMainWindowクラス()の定義の一部で例の"InitializeComponent()”関数を定義しており、その内容はmainwindow.xamlファイルに基づきLoadComponent()関数でコントロールを配置している模様です。また派生元のSystem.Windows.Markup.IComponentConnectorに"Connect(int connectionId, object target)"という関数を定義しており、この関数はTextBoxコントロールにTextBoxクラスをラッピングさせているのではないかと考えます。
注:このクラスはSystem.Windows.WindowとSystem.Windows.Markup.IComponentConnectorから派生させています。なお、MainWindow.xaml.csファイルでもMainWindowクラスの定義を行っていますが、そこでは単位Windowクラスからの派生になっています。("public partial class MainWindow : Window”)

最後にMainWindow.xaml.cs(後掲)というファイルがありますが、これが唯一、機械作成だけでなく、人間(ユーザー)が入力したコードを含むファイルとなっています。

(4)実行ファイル
App.g.cs(後掲)とApp.g.i.csという、またもや同じ内容のファイルがあります。これは(App.xaml.csと同じく)Appクラスの定義ファイルで、"InitializeComponent()”関数でメンバーのStartupUriにSystem.Uri()関数を使って"MainWindow.xaml"のURIを格納するとともに、ここで定番のエントリーポイント定義を行っていました。

        public static void Main() {
            WpfApplication1.App app = new WpfApplication1.App();
            app.InitializeComponent();
            app.Run();
        }

 

なお、実行ファイルのプロパティで表示するような属性情報はAssemblyInfo.csで[assembly: Assembly*]を使って設定するようです。
[assembly: AssemblyTitle("WpfApplication1")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("WpfApplication1")]
[assembly: AssemblyCopyright("Copyright ? ?2012")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
assembly: ComVisible(false)]
[assembly: ThemeInfo(略)]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

以上です。↑で述べた主要な後掲ファイルは以下を参照してください。なお、これらのコードをビルドしたプログラムがこれです。


次回はこれらの内容を眺めたうえで、「管理系」やXMLのコードを総て除き、手作業のみでMSCompAssにかけるコード書いてみようと考えています。

【Resource.Designer.cs】
//------------------------------------------------------------------------------
// <auto-generated>
//     このコードはツールによって生成されました。
//     ランタイム バージョン:4.0.30319.17929
//
//     このファイルへの変更は、以下の状況下で不正な動作の原因になったり、
//     コードが再生成されるときに損失したりします
// </auto-generated>
//------------------------------------------------------------------------------

namespace WpfApplication1.Properties
{
    /// <summary>
    /// ローカライズされた文字列などを検索するための、厳密に型指定されたリソース クラスです。
    /// </summary>
    // このクラスは StronglyTypedResourceBuilder クラスによって ResGen
    // または Visual Studio のようなツールを使用して自動生成されました。
    // メンバーを追加または削除するには、.ResX ファイルを編集して、/str オプションと共に
    // ResGen を実行し直すか、または VS プロジェクトをビルドし直します。
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    internal class Resources
    {
        private static global::System.Resources.ResourceManager resourceMan;
        private static global::System.Globalization.CultureInfo resourceCulture;
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal Resources()
        {
        }

        /// <summary>
        /// このクラスに使用される、キャッシュされた ResourceManager のインスタンスを返します。
        /// </summary>
     [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        internal static global::System.Resources.ResourceManager ResourceManager
        {
            get
                {
                    if ((resourceMan == null))
                    {
                        global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WpfApplication1.Properties.Resources", typeof(Resources).Assembly);
                        resourceMan = temp;
                    }
                    return resourceMan;
                }
            }

            /// <summary>
            /// 厳密に型指定されたこのリソース クラスを使用して、すべての検索リソースに対し、
            /// 現在のスレッドの CurrentUICulture プロパティをオーバーライドします。
            /// </summary>
         [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        internal static global::System.Globalization.CultureInfo Culture
        {
            get
            {
                return resourceCulture;
            }
            set
           {
                resourceCulture = value;
            }
        }
    }
}

【Settings.Designer.cs】
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.17929
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace WpfApplication1.Properties
{
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
    internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
    {
        private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));

        public static Settings Default
        {
            get
            {
                return defaultInstance;
            }
        }
    }
}

【MainWindow.xaml】
<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <ScrollViewer CanContentScroll="True">
            <TextBox x:Name="textBox"/>
        </ScrollViewer>
    </Grid>
</Window>

【MainWindow.g.cs】

#pragma checksum "..\..\MainWindow.xaml" "{406ea660-64cf-4c82-b6f0-42d48172a799}" "94A0B46286AACD2319897322C3096C83"
//------------------------------------------------------------------------------
// <auto-generated>
//     このコードはツールによって生成されました。
//     ランタイム バージョン:4.0.30319.34209
//
//     このファイルへの変更は、以下の状況下で不正な動作の原因になったり、
//     コードが再生成されるときに損失したりします。
// </auto-generated>
//------------------------------------------------------------------------------

using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using System.Windows.Media.TextFormatting;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Shell;

namespace WpfApplication1 {
    /// <summary>
    /// MainWindow
    /// </summary>
    public partial class MainWindow : System.Windows.Window, System.Windows.Markup.IComponentConnector {
        #line 7 "..\..\MainWindow.xaml"
        [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]
        internal System.Windows.Controls.TextBox textBox;
        #line default
        #line hidden
        private bool _contentLoaded;
        /// <summary>
        /// InitializeComponent
        /// </summary>
        [System.Diagnostics.DebuggerNonUserCodeAttribute()]
        [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")]
        public void InitializeComponent() {
            if (_contentLoaded) {
                return;
            }
            _contentLoaded = true;
            System.Uri resourceLocater = new System.Uri("/WpfApplication1;component/mainwindow.xaml", System.UriKind.Relative);
            #line 1 "..\..\MainWindow.xaml"
            System.Windows.Application.LoadComponent(this, resourceLocater);
            #line default
            #line hidden
        }
        [System.Diagnostics.DebuggerNonUserCodeAttribute()]
        [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")]
        [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
        [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")]
        [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
        [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]
        void System.Windows.Markup.IComponentConnector.Connect(int connectionId, object target) {
            switch (connectionId)
            {
            case 1:
            this.textBox = ((System.Windows.Controls.TextBox)(target));
            return;
            }
            this._contentLoaded = true;
        }
    }
}

【MainWindow.xaml.cs】
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;

using System.Speech.Recognition;

namespace WpfApplication1
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        SpeechRecognitionEngine recogEngine;

        public MainWindow()
        {
            InitializeComponent();

            recogEngine = new SpeechRecognitionEngine();

            // 音声認識が認識処理を終えたときのイベントハンドラを設定する。
            recogEngine.SpeechRecognized += recogEngine_SpeechRecognized;

            // 音声認識が推定処理を終えたときのイベントハンドラを設定する。
            recogEngine.SpeechHypothesized += recogEngine_SpeechHypothesized;

            // SystemSpeech を利用したディクテーションを行う場合には、
            // DictationGrammar (ディクテーション用の辞書) を追加する。
            recogEngine.LoadGrammar(new DictationGrammar());

            // 実行環境の標準の入力を音声認識エンジンの入力とする。
            recogEngine.SetInputToDefaultAudioDevice();
 

            // 非同期の認識を継続して実行するようにして音声認識を開始する。
            recogEngine.RecognizeAsync(RecognizeMode.Multiple);
        }

        // 推定時の処理
        void recogEngine_SpeechHypothesized(object sender, SpeechHypothesizedEventArgs e)
        {
            this.textBox.Text = "○" + e.Result.Text + "("+ e.Result.Confidence + ")\n" + this.textBox.Text;
        }

        // 認識時の処理
        void recogEngine_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
        {
            this.textBox.Text = "●" + e.Result.Text + "(" + e.Result.Confidence + ")\n" + this.textBox.Text;
        }

        protected override void OnClosed(EventArgs e)
        {
            base.OnClosed(e);

            // 終了時には破棄する。
            recogEngine.Dispose();
        }
    }
}

【App.g.cs】

#pragma checksum "..\..\App.xaml" "{406ea660-64cf-4c82-b6f0-42d48172a799}" "BA8CBEA9C2EFABD90D53B616FB80A081"
//------------------------------------------------------------------------------
// <auto-generated>
//     このコードはツールによって生成されました。
//     ランタイム バージョン:4.0.30319.34209
//
//     このファイルへの変更は、以下の状況下で不正な動作の原因になったり、
//     コードが再生成されるときに損失したりします。
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using System.Windows.Media.TextFormatting;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Shell;

namespace WpfApplication1 {

    /// <summary>
    /// App
    /// </summary>
    public partial class App : System.Windows.Application {
        /// <summary>
        /// InitializeComponent
        /// </summary>
        [System.Diagnostics.DebuggerNonUserCodeAttribute()]
        [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")]
        public void InitializeComponent() {
 

            #line 4 "..\..\App.xaml"
            this.StartupUri = new System.Uri("MainWindow.xaml", System.UriKind.Relative);
 

            #line default
            #line hidden
        }
 

        /// <summary>
        /// Application Entry Point.
        /// </summary>
        [System.STAThreadAttribute()]
        [System.Diagnostics.DebuggerNonUserCodeAttribute()]
        [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")]
        public static void Main() {
            WpfApplication1.App app = new WpfApplication1.App();
            app.InitializeComponent();
            app.Run();
        }
    }
}

 

本日アップした「【C#】Visual Studioのファイルを調べてみる(1)」は2回目に書いたもの。

 

1回目に描いたやつを一旦「下書き保存」し、次に別の原稿(「【C#】Visual Studioのファイルを調べてみる(2)」)を書いていました。そして、席を外すので、そいつを「下書き保存」したら、最初の「【C#】Visual Studioのファイルを調べてみる(1)」に上書きされたみたいで消えてしまった!!!

 

無念!「下書きは一原稿のみ」なんだねっ!

 

ということで、「【C#】Visual Studioのファイルを調べてみる(2)」を下書きで保存したまま、「ブログを書く」を別途(保存せずにアップするつもりで)「【C#】Visual Studioのファイルを調べてみる(1)」を再度書きなおして本日アップしました。そしたら.......

 

無念!「下書きは表題や内容が変わっていてもアップしたら消えちゃうのね?」!?

 

ということで、書き進んでいた「【C#】Visual Studioのファイルを調べてみる(2)」も消失、なので、

 

少しお時間をください!!!

 

プログラミングネタがないので、WEBを漁っていたらC#による音声入力機能のサンプルプログラムがあったので、覗いてみたらVisual Studioの「ソリューション」()ファイル一式でした。

注:「ソリューション」とは一つのアプリケーションを開発する際の、一つ以上の「プロジェクト」を管理する単位で、「プロジェクト」とは一つのプログラム(exeやdll等)を開発する際の、一つ以上の「ファイル」を管理する単位のことのようです。出典参考

 

Visual Studioは単にコーディング、コンパイル、ビルド、デバッグを行うIDEのみならず、システム環境に基づいて環境を管理するので、「管理系」の処理も膨大で関連ファイルも多くなります。(その結果、OPCの能力や環境によっては-事実私の32bit Win10の第4世代Core-7マシンでは-、一つのソリューションを読み込み、表示するまでに数十秒を要することも稀ではありません。)

 

このソリューションはDictation_SSpeechといい、その最上位のフォールダーはこのようになっています。

先ずソリューション管理ファイルがテキストベースであります。(WpfApplication.sln-.solution

.suoファイルはバイナリーデータのようで、内容はよくわかりません。また、隠しフォールダーの「.vs」は純管理用なので省略します。

 

次に「プロジェクト」のApfApplication1フォールダーを除くとbin、objおよびPropertyという3つのフォールダーが入っています。

 

最初のbinフォールダーの中でファイルが入っているのは(IDEの実行ファイル保存用フォールダーの規定値と思われる)Debugで、その内容は↓の通りです。実行ファイルと設定ファイルだけがある印象です。

 

次のobjフォールダーにもDebugフォールダーがあり、名称、サイズが同じ実行ファイルがありますが、こちらはコンパイル、ビルド、デバッグ関連ファイルが多いです。おそらくここに一次ビルドファイルが入り、最終ビルドファイルがbinの方に入るのではないでしょうか?

 

Propertyフォールダーには実行ファイルの情報やリソース、フォーム(ウィンドウ)関連情報のファイルが入っている模様です。

 

このようにVisual Studioでプログラミングをする場合には、開発用ファイルやプロセスの管理はIDEに任せ、人間(ユーザー)が勝手にその一部のファイルにアクセスして修正するようなことは禁止されていると考えるべきでしょう。(実際これら多数のファイルのほぼすべてがIDEが作成したファイルになっています。)

自分が描いたコードがどこになるのかもわからないので覗いてもよいですが、書き換える等の行為は深刻なトラブルになるのでご自身に自信がある場合を除き避けるべきか、と考えます。

 

でも、「やるな」といわれるとやりたくなっちゃうぅ!

 

という方(注)の為に、次回は私が代わりに覗いてあげましょう。ウヒヒ...(こういう親爺ギャグも不適切ですかねぇ?最近の「空気」はよくわからなくて。)

注:Curiosity killed the cat