20201115のC#に関する記事は4件です。

VS2019 C#でCOM DLLを作ってみた

はじめに

を参考にさせて頂きました。圧倒的感謝……!

環境

  • Windows 10 Home (64bit)
  • Visual Studio Community 2019

手順

プロジェクトの作成

プロジェクト テンプレート:クラス ライブラリ (.NET Framework) [C#]
プロジェクト名:ClassLibrary1

クラス ライブラリ (.NET Standard)
とは別なので注意。

インタフェースとクラスの作成

Class1.cs
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace Sample
{
    [ComVisible(true)]
    [Guid("EC463B16-E298-478E-A836-44585A30F806")]
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    public interface ITest
    {
        void Hello(string msg);
    }

    [ComVisible(true)]
    [Guid("A81D546F-6F4E-49E0-9A2B-A9DCC725C489")]
    [ProgId("Sample.Test")]
    [ClassInterface(ClassInterfaceType.None)]
    public class Test : ITest
    {
        public void Hello(string msg)
        {
            MessageBox.Show(msg, "Test");
        }
    }
}

Guid はツールから作成する。

MessageBox を使うのでプロジェクトにアセンブリ参照を追加する。
名前:System.Windows.Forms

アセンブリに署名

プロジェクトのプロパティを開き、署名の「アセンブリに署名する」をチェックする。
キー ファイル:test

署名しなくともRegAsmで警告は出るが登録は可能。

ビルド

ソリューション構成:Release
ソリューション プラットフォーム:Any CPU
ソリューションのビルド。

レジストリに登録

管理者権限の PowerShell やコマンド プロンプトでレジストリに登録する。

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm ClassLibrary1.dll /codebase

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm ClassLibrary1.dll /codebase /u
で登録解除。

/tlbを付けるとCOM一覧に表示されるがC#からは利用できない模様。
dllを直接参照する手もある。

テストプログラム

JScript

test.js
var test = new ActiveXObject("Sample.Test");
test.Hello("hello, JScript");

というファイルを用意しダブルクリックする。
クラスに定義した ProgID を指定。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

toio for Unity Editor Windows BLE対応

初めに

Unityでtoioの開発できるってことで飛びつきました。
https://toio.io/blog/detail/20200930-1.html
しかし、よく内容を見ているとUnity Editor内で確認できるのは
シュミレーターでのtoioの動き確認のみ。

う~ん。やっぱUnity Editorでtoioコアキューブが動いてほしい
というわけでtoioの仕様についていろいろ調べ始めました。

toio™コア キューブ 技術仕様2.2.0
https://toio.github.io/toio-spec/docs/ble_communication_overview.html

BLEで接続してtoioコアキューブが動いているようなので
Unity EditorでBLE接続出来てしまえばいけちゃうのでは?
って事で調べ始めました。

Uunity EitorでBLEを接続する

UnityでBLE接続するぞってって事でAssetstoreに行って検索を!
自分で作るんじゃないんだ。。。
無ければ自分で作るんですけどね。。

ということで調べたら、あった!!神
Arduino Bluetooth Plugin $19
https://assetstore.unity.com/packages/tools/input-management/arduino-bluetooth-plugin-98960

で早速ポチって見ました。
image.png

Arduino Bluetooth Pluginを使ってBLE接続

image.png
Arduino Unity Plugin.pdfの説明の最後のほうに
Setup BLE in unity editor for Windows 10の説明があるので手順書通りインストールします。

image.png

BLEの通信するアプリ(BluetoothDesktopServer)を立ち上げて
image.png

アプリはBLEのサーバーと通信するものですが、コマンドでループバックで通信を行えるようにコマンドで実行しておきます。

CheckNetIsolation.exe LoopbackExempt -is -n=BluetoothDesktopServer_t05x7yb6e6yp0

後はc#の方で

 BluetoothHelper.BLE_AS_CLIENT = true;

でBLEの接続の準備をしておきます。

Unity Editorで立ち上げて、toioのBLEを探すので接続したら
ServiceとCharacteristicsを指定して値を渡すと
toioがtoio™コア キューブ 技術仕様通りに値を送ると
値通り動いてくれます。

※注意
Arduino Bluetooth PluginのwindowsのBLEの接続はまだ開発途中らしく、安定した接続はまだらしいです。

この記事は2020/10に環境を作りました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WebView2 Windows Form C#(.Net) の実装と詰まった点・困った点

今年(2020年)の8月にMicrosoftは.Netに対応させた「WebView2」のプレリリースを発表しました。
今回はその「WebView2」を Windows Form で実装していき、実装時の詰まった点・困った点について話していきます。

WenView2とは?

「WenView2」とは、Windowsフォームに埋め込むことができるブラウザーコントロールの一種です。
Windowsフォームにブラウザーを埋め込むにはデフォルトの場合、「WebBrowser」を使用するのですが、「WebBrowser」は IE ベースとなっており、IE を使用すると一部 webページでは処理できない事象が発生します。
(先日、Rustでwasmを作成する記事を書いたのですが、IE ではwasmを処理できません)
今回使用する「WebView2」はEdgeベースとなっており、Edgeは「Chromium」ベースで作られてるため、IEで処理できないページを処理することができます。

WenView2 の実装

基本的には、下記のMicrosoft公式ページを参照して頂ければ実装できます。
https://docs.microsoft.com/ja-jp/microsoft-edge/webview2/gettingstarted/winforms

詰まった点・困った点

1.Canary チャネルをダウンロード

さあ、これから実装しようとなって、Nugetからプレリリース版の「Microsoft.Web.WebView2」をダウンロードし、WindowsフォームのデザイナーにWebView2を設置してブラウザーを表示しようとしたら、なぜかブラウザーがロードされない…
どういうことなのか?と思い迷うこと一時間。

公式リファレンスを読み直してみたところ、前提条件に、「WebView2 Runtime または windows 10、windows 8.1、または windows 7 にインストールされている 非安定した Microsoft Edge (Chromium) カナリアチャネル 」とあります…
つまり、WebView2 Runtimeか、Microsoft Edge (Chromium) カナリアチャネルをダウンロードする必要があるということみたいです。
てっきり私は、最新の Edgeがダウンロードされているならば、「WebView2 Runtime」が取り込み済みとなっているのかと勘違いしてしまっていたのですが、そういうことではないそうです。
ということで、「Edge Canaryチャネル」をダウンロードして再度挑戦したところ、無事にロードさせることができました。
ちなみに、「Canaryチャネル」は下記サイト内で、画像の赤枠で囲った部分のやつです。
https://www.microsoftedgeinsider.com/ja-jp/download
image.png
まあ、こんなミス、自分だけかもしれませんが(笑)

2.CoreWebView2がnull

まず、下記のコードを見てください。
このコードは正常に処理できる様に書いたコードですので、コピペしてもらってデバッグしても、エラーにならずに処理することができます。
(フォームのデザイナーは空の状態で大丈夫です。)
以降の話は、下記のコードを見比べながら読んで頂くとわかりやすいと思います。

Form1.cs
using Microsoft.Web.WebView2.Core;
using Microsoft.Web.WebView2.WinForms;
using System;
using System.Windows.Forms;

namespace SampleWebView2Form
{
    public partial class Form1 : Form
    {
        /// <summary>webviewのコントロール(今回はわかりやすい様に、デザイナーを使わずにコード側で実装します。)</summary>
        private WebView2 WebView = new WebView2
        {
            Source = new Uri("https://docs.microsoft.com/ja-jp/microsoft-edge/webview2/gettingstarted/winforms"),
        };

        public Form1()
        {
            this.Controls.Add(WebView);
            InitializeComponent();

            //WebView2のサイズをフォームのサイズに合わせる
            WebView.Size = this.Size;
            this.SizeChanged += Form1_SizeChanged;

            //WebView2のロード完了時のイベント
            WebView.NavigationCompleted += WebView_NavigationCompleted;
        }

        /// <summary>WebView2のロード完了時</summary>
        private void WebView_NavigationCompleted(object sender, CoreWebView2NavigationCompletedEventArgs e)
        {
            //WebView2のコントロールから CoreWebView2を取り出す
            //WebView2のロードが完了する前に CoreWebView2を取り出そうとすると nullになる。
            if (WebView.CoreWebView2 != null)
            {
                //ブラウザーのポップアップ発生時のイベント
                WebView.CoreWebView2.NewWindowRequested += CoreWebView2_NewWindowRequested;
            }
            else MessageBox.Show("WebView.CoreWebView2 == null");
        }

        /// <summary>WebView2でのポップアップを抑止したい</summary>
        private void CoreWebView2_NewWindowRequested(object sender, CoreWebView2NewWindowRequestedEventArgs e)
        {
            //本来なら、これでポップアップを抑止できるはず
            //だが、ロードの速度の都合で e.NewWindow(CoreWebView2)が nullになる場合があり、エラーが発生する
            if (e.NewWindow != null)
            {
                e.NewWindow.Stop();
                MessageBox.Show("ポップアップを抑止しました");
            }
            else
            {
                //ダミーのCoreWebView2を読み込ませてポップアップを抑止する
                //e.NewWindow = new Microsoft.Web.WebView2.Core.CoreWebView2();
                //↑ちなみに、これはできない
                e.NewWindow = DummyWebView.CoreWebView2;
                e.NewWindow.Stop();

                //これでJavaScriptが実行できる
                WebView.ExecuteScriptAsync("alert(\"ポップアップを抑止しました\");");
            }
        }

        /// <summary>ポップアップ抑止に使用するダミーのWebView2(の中のCoreWebView2)</summary>
        private WebView2 DummyWebView = new WebView2
        {
            Source = new Uri("https://www.google.co.jp/"),
        };

        /// <summary>サイズ変更時のイベントでWebView2のサイズをフォームに合わせる</summary>
        private void Form1_SizeChanged(object sender, EventArgs e)
        {
            WebView.Size = this.Size;
        }
    }
}

WebView2には「CoreWebView2」というオブジェクトがあるのですが、この「CoreWebView2」に対してイベントを設定することで、ブラウザー側の動きに合わせて、C#側の処理を行っていくことができます。
ということで、ロードのタイミングでポップアップ時のイベントを設定します。
…するとどうなるかというと、例外回避のために設定した「CoreWebView2」の null判定に引っ掛かり、
"WebView.CoreWebView2 == null")のメッセージが発生して、ポップアップ検知のイベントが設定されません。

Form1.cs
        public Form1()
        {
            this.Controls.Add(WebView);
            InitializeComponent();
            if (WebView.CoreWebView2 != null)
            {
                //ブラウザーのポップアップ発生時のイベント
                WebView.CoreWebView2.NewWindowRequested += CoreWebView2_NewWindowRequested;
            }
            else MessageBox.Show("WebView.CoreWebView2 == null");
        }

原因は何かというと、この「CoreWebView2」というのがブラウザーのエンジン的な役割をしているため、読み込ませたいwebページのロードが終了しない限り、「CoreWebView2」がnullのまま、ということになってしまうからです。
それを解決するためには、下記の様にコードを修正します。

Form1.cs
        public Form1()
        {
            this.Controls.Add(WebView);
            InitializeComponent();

            //WebView2のロード完了時のイベント
            WebView.NavigationCompleted += WebView_NavigationCompleted;
        }
        /// <summary>WebView2のロード完了時</summary>
        private void WebView_NavigationCompleted(object sender, CoreWebView2NavigationCompletedEventArgs e)
        {
            //WebView2のコントロールから CoreWebView2を取り出す
            //WebView2のロードが完了する前に CoreWebView2を取り出そうとすると nullになる。
            if (WebView.CoreWebView2 != null)
            {
                //ブラウザーのポップアップ発生時のイベント
                WebView.CoreWebView2.NewWindowRequested += CoreWebView2_NewWindowRequested;
            }
            else MessageBox.Show("WebView.CoreWebView2 == null");
        }

「WebView2」のナビゲーションが完了時に「CoreWebView2」を取得することで nullを回避できるため、例外回避に引っ掛からず、正常にイベントを設定することができます。

ポップアップが止まらない

イベントも無事設定できたので、今度はポップアップを抑止したいと思います。
ポップアップを抑止したらタブコントロールの別のタブページにポップアップのページを表示する、というのが実装するならば自然な処理となるでしょうが、わざわざそれを書くと長くなるので、タブコントロールに関しては、今回は省きます。
ちなみに、ポップアップが発生する場合というのは、WebView2内でリンクを右クリックし、「リンクを新しいウィンドウで開く」を押下すると、Windowsフォームの外にリンク先のページが表示されます。
(今回の記事の最初に書いたコードで実行すると、既にポップアップが抑止されるようになっています。)
image.png
ポップアップを抑止するため、下記のコードを追加しました。
「CoreWebView2NewWindowRequestedEventArgs e」の「.NewWindow」が「CoreWebView2」なので、それを「.Stop()」すればポップアップを抑止できるでしょう。本当なら、e.Cancel みたいのがあるべきかと思いますが…
(ちなみに、e.Uri でポップアップのURLが取得できるので、ポップアップをタブコントロールの別タブにしたい場合は、このURLを使用して新規にWebView2を作成し、タブページを追加するというのが無難な処理なるかと思います。)

Form1.cs
        /// <summary>WebView2のロード完了時</summary>
        private void WebView_NavigationCompleted(object sender, CoreWebView2NavigationCompletedEventArgs e)
        {
            if (WebView.CoreWebView2 != null)
            {
                //ブラウザーのポップアップ発生時のイベント
                WebView.CoreWebView2.NewWindowRequested += CoreWebView2_NewWindowRequested;
            }
            else MessageBox.Show("WebView.CoreWebView2 == null");
        }

        /// <summary>WebView2でのポップアップを抑止したい</summary>
        private void CoreWebView2_NewWindowRequested(object sender, CoreWebView2NewWindowRequestedEventArgs e)
        {
            //ポップアップを抑止
            if (e.NewWindow != null)
            {
                e.NewWindow.Stop();
                MessageBox.Show("ポップアップを抑止しました");
            }
            else MessageBox.Show("e.NewWindow == null");
        }

ということで実行してみると、またもや「null」…
原因は、さっきと同じでWebページ側がロード未完了なことです。
ならば、さっきみたいにナビゲーション完了で拾って.Stop()をかける、というのがやりたいわけですが、そもそもナビゲーション完了イベントを設定するためのWebView2コントロールが存在しません。(ポップアップ元のWebView2とは別の物が必要になるわけです)
「e.Navigatin」が nullならば作ればいい、というわけで = new CoreWebView2();としようとしたんですが、それはダメらしい…
苦肉の策のとして下記の様な実装となりました。

Form1.cs
        /// <summary>ポップアップ時のイベント_WebView2でのポップアップを抑止したい</summary>
        private void CoreWebView2_NewWindowRequested(object sender, CoreWebView2NewWindowRequestedEventArgs e)
        {
            //本来なら、これでポップアップを抑止できるはず
            //だが、ロードの速度の都合で e.NewWindow(CoreWebView2)が nullになる場合があり、エラーが発生する
            if (e.NewWindow != null)
            {
                e.NewWindow.Stop();
                MessageBox.Show("ポップアップを抑止しました");
            }
            else
            {
                //ダミーのCoreWebView2を読み込ませてポップアップを抑止する
                //e.NewWindow = new Microsoft.Web.WebView2.Core.CoreWebView2();
                //↑ちなみに、これはできない
                e.NewWindow = DummyWebView.CoreWebView2;
                e.NewWindow.Stop();

                //これでJavaScriptが実行できる
                WebView.ExecuteScriptAsync("alert(\"ポップアップを抑止しました\");");
            }
        }

        /// <summary>ポップアップ抑止に使用するダミーのWebView2(の中のCoreWebView2)</summary>
        private WebView2 DummyWebView = new WebView2
        {
            Source = new Uri("https://www.google.co.jp/"),
        };

「CoreWebView2」を newで作成することができないため、ダミーの「WebView2」を用意して、そこから「CoreWebView2」を取得します。
「e.NewWindow」に当てはめることで nullじゃなくなるため、「.Stop()」が適用できます。
ついでに、この処理でポップアップを抑止した場合、「ExecuteScriptAsync()」で、JavaScriptのアラートが出力される様な処理にしてあります。
処理に納得がいかない…とは思いましたが、まあ、プレリリース版だとこんなもんですかね?
もっと良い方法があったら教えてください。 m(_ _)m

まとめ

とりあえず今回はこんなところです。
プレリリース版ということもあるのか、処理が所々おかしいのが気になりますね。
贅沢言わなければ、ユーザー側に「IE」を使わせないという規制をかけることができるので、そこは良いところでしょうか?

本当なら、開発者ツールが表示されない様に、
WebView.CoreWebView2.Settings.AreDevToolsEnabled = false;
とできるらしいのですが、それが反応しない…。
まあ、今だと日本語リファレンスも少ないし、処理も所々おかしいので、今後に期待、というところですかね。

<2020.11.16 追記>
WebView2を使ったJavaScriptとC#の連携についての記事を書いたので、リンクを貼っておきます。
https://qiita.com/NagaJun/items/baf00494e0841a5e767e

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

.NET 5(C#9.0)を試してみた

2020/11/10 (日本時間11日 1:00)に、.NET 5が正式リリースされたそうなので試してみました。

.NET 5のインストール手順

Visual Studio 2019のインストール/アップデート

.NET 5をVisual Studioで扱う場合は、Visual Studio 2019 Version 16.8以降が必要とのことなので、
まずはアップデートを行います。
インストールがまだの場合は、最新のVisual Studioをインストールしましょう。
Download Visual Studio 2019 for Windows & Mac

既にインストールされている場合は、Visual Studio Installerを起動し、更新ボタンをクリック
update.png

または、Visual Studioの [ヘルプ] -> [更新プログラムの確認] で更新します。
check.png

アップデートが完了したら、 [ヘルプ] -> [Microsoft Visual Studio のバージョン情報] とクリック
version.png

現在のバージョンが確認できます。
nowver.png

.NET 5をインストール

いよいよ.NET 5のインストールです。
まず、ダウンロードページにて、.NET 5のSDKインストーラをダウンロードします。
(種類がいろいろあるので、自分の使ってる端末にあったものをダウンロードします。)
ダウンロードが完了したら、インストーラを起動し、インストールボタンをクリック
install.png
しばらく待つと、インストール完了の旨が表示されます。
インストール完了
これで、.NET 5の環境が整いました。
意外と簡単だった。

.NET 5(C#9.0)を使ってみる

さっそく新規プロジェクトを作って使ってみようと思います。

コンソールアプリの作成

とりあえずコンソールからやりたいと思います。
新しいプロジェクトの作成から、コンソール アプリ (.NET Core)を選択1して、次へのボタンをクリック
適当なプロジェクト名を決め、作成ボタンをクリック
仮に、「Dotnet5Test」としました。
proj.png

プロジェクトを作成したら、まずは、プロジェクトのプロパティを開きます。
プロパティ

対象のフレームワークを、.NET 5に変更します。
フレームワークの変更

これで.NET 5が使えるようになったので、さっそくコードを書いていきましょう。
個人的に目玉なのが、トップレベルステートメントというのが追加されたそうなので、試してみたいと思います。
最初に出力されたProgram.csのコードは、全てコメントアウトにします。
コメントアウト
そしたら、1行だけ書きます。

System.Console.WriteLine("Hello World!");

えっメインメソッドとかコメントアウトしたけど実行できるの?
HelloWorld
できちゃいました:relaxed:2
トップレベルステートメントというのは、メインメソッド相当のを自動生成してくれるらしいです。
なのでいきなり標準出力の処理を書いても、勝手にメインクラスとして認識してくれるというわけですね。
(なんか感動)
ちなみに以下のコードを実行すると...

using System;

Console.WriteLine("外側からHello World!");

namespace Dotnet5Test
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("内側からHello World!");
        }
    }
}

soto.png

こうなります。
Mainメソッドは無視されるようです。(たしか警告が出てたような...)
他の機能を試したい場合は、以下を参照してください。
What's new in .NET 5 (英語)
C# 9.0 の新機能 (日本語)

Windows Formsの作成

今度はFormsアプリを作ってみます。
Windows Forms App (.NET)で作成(dotnet5Formsで作成しました。)
FormsProj
プロジェクトを作成したら、先程と同じように、プロパティから、対象のフレームワークを.NET 5に変更します。
すると、Formsの場合、以下のような警告が表示されます。
image.png

警告  NETSDK1137  Microsoft.NET.Sdk.WindowsDesktop SDK を使用する必要はなくなりました。ルート プロジェクト要素の SDK 属性を 'Microsoft.NET.Sdk' に変更することをご検討ください。

検討してくださいとのことなので、.csprojのProject要素のSdk属性を、Microsoft.NET.Sdkに変更します。
(1行目のところ)
ビルドすると警告が消えるのでそのまま実行してみます。
image.png
この通り、普通に実行させることができました。

VS Code(コマンド)でプロジェクト作成/実行

.NET 5をインストールすると、dotnetというコマンドが使えるようになっています。

dotnet --version

image.png
なので、コマンドでプロジェクトを作って、実行ができます。

プロジェクト作成
dotnet new console -o Dotnet5Test
実行
dotnet run

image.png

感想

  • .NET 5のインストールが以外と簡単だった。
  • コンソールアプリに関しては、.NET 5だと入門しやすい、とっつきやすいのかなと思った。

参考サイト


  1. .NET 5のテンプレートプロジェクトがないようなので、今回は.NET Coreを選択しました。.NET 5のテンプレートを表示する方法ってあるのかな? 

  2. 予め、[ツール] -> [オプション] -> [デバッグ] -> [デバッグの停止時に自 動的にコンソールを閉じる] のチェックを外す。 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む