VisualStudioでのC++やC実行プロジェクトのC++/CLIでのdll化について

まずプロジェクトの設定から
CやC++のプロジェクトをC++/CLIに変換する(プラットフォームをすべてのプラットフォームにして設定すると便利)

・プロジェクトのプロパティー
  ・詳細
        ・共通言語ランタイムサポート /cli
        ・ターゲットファイルの拡張子 .dll
  ・C/C++
        ・言語
                ・準拠モード いいえ
                ・基本ランタイムチェック 規定
        ・詳細設定
                ・コンパイル言語の選択 /TP
  ・リンカー
        ・出力ファイル 設定されていたら適切に修正

・ソースコードのプロパティー
  ・C/C++
        ・基本ランタイムチェック 規定

マネージドのクラスの処理はネイティブと別のソースにする。
これはCやC++の#defineが強力すぎるためマネージドのOKなどの定数が1や0などに置き換えられコンパイルが通らなくなるのを防ぐので必須です。
ネイティブ側の関数も独自にhを作り間接的に参照するようにしましょう。
マネージドのクラスはdllexportなどなくても参照できるようになるから便利
以下のようなファイルを追加し元のmain処理を修正する(ここではcustom_main)
export.cpp

#include "export.h"
using namespace System;
using namespace System::Runtime::InteropServices;
using namespace System::Collections::Generic;
namespace Demo {
	public ref class Option
	{
	public:
		const static int AUTO_COUNT = -1;//定数サンプル
		int Count;
		String^ Name;
		array<unsigned char>^ Data;//C# byte[] Data
	};
	public ref class DemoClass
	{
	public:
		//デフォルト引数の代わりの処理
		static void DemoCall(String^ Args) {
			DemoCall(Args,gcnew Option());
		}
		static void DemoCall(String^ Args,Option^ option) {
			String^ cmmandLine = "demo.dll";
			if (Args != "")
				cmmandLine += " "+Args;
			array<String^>^ args;
			char** tmpArgs = nullptr;
			NativeOption noption;
			try {
				//ここのサンプルは半角スペースでの簡易的な引数分解です
				args = cmmandLine->Split(' ');
				tmpArgs = new char* [args->Length];
				for (int i = 0; i < args->Length; i++) {
					tmpArgs[i] = (char*)(void*)Marshal::StringToHGlobalAnsi(args[i]);
				}
				//マネージドのOptionをネイティブに変換設定
				noption.count = option->Count;
				//文字列はネイティブで扱える形に変換 解放が必要
				noption.name = (char*)(void*)Marshal::StringToHGlobalAnsi(option->Name);
				//データ配列はメモリー確保してコピーするか ポインタが動かないように固定する
				pin_ptr<unsigned char> p= &option->Data[0];
				noption.data = p;
				if(custom_main(args->Length, tmpArgs, &noption)){
					throw gcnew Exception("失敗しました");
				}
			}
			catch (char* msg) {
				String^ str = gcnew String(msg);
				throw gcnew Exception(str);
			}
			finally {
				if(noption.name!=nullptr){
					Marshal::FreeHGlobal(IntPtr((void*)noption.name));
				}
				for (int i = 0; i < args->Length; i++) {
					Marshal::FreeHGlobal(IntPtr((void*)tmpArgs[i]));
				}
				delete[] tmpArgs;
			}
		}
	};

}

export.h

struct nativeOption {
	int count;
	char *name;
	unsigned char *buffer;
};
//必要なら引数ふやす
int custom_main(int argc, char* argv[],nativeOption* option);

あと必要であればネイティブの独自コード用にexport_native.cppなど追加

main関数以下の修正の注意点
abortやexitなどの処理に注意。DLLを使用したアプリが終了する。
throwで文字列などを返すように修正する。
メモリー解放がアプリ終了に依存している場合適切に開放するようにする
内部で変動するグローバル変数に依存する処理がある場合
スレッドセーフでなくなるため必要であれば引数を増やすなどで参照しないよう修正する。
C#でいうoutの引数を行う場合
[Runtime::InteropServices::Out] Option^% option
などとすればよいです。

あとはC#プロジェクトで参照すると
Demo.DemoClass.DemoCallが見えて呼べるようになってるはず

VisualStudioでMicrosoft Store 送信設定の構成について

かなりハマったのでメモ

このポップアップ画面で最後のクライアントキーとはなんぞやとなった
https://docs.microsoft.com/ja-jp/windows/msix/package/packaging-uwp-apps
こちらを参考にするようにVisualStudioにはリンクが貼られてました。
はい、新しいキーの追加なんてないです。権限の設定画面です。ガッデム!!
昔はあったのかもしれない・・。
超絶試行錯誤した末
パートナーセンターと書かれてるけどそれは嘘で操作方法も嘘で
Microsoft AzureのポータルにてAzure Active Directoryを開き
アプリの登録から該当のアプリを開き
左側の証明書とシークレットを選び
+新しいクライアント シークレット
これで作れます。

これ全部同じ意味みたい
・クライアント シークレット
・アプリケーションパスワード
・クライアントキー

※あきらめて手動で申請送信した後なのでVisualStudioがポップアップ画面を正常に閉じさせてくれたとこまでしか確認してないけど。(内容がおかしいと怒られる)

Microsoft Visual Studio Installer Projects

昔のVisualStudioについてたSetupプロジェクトが標準から外れて読めなくなり
別にダウンロードすれば使えるけど基本は有料、一応無料版もあるけどメアドとかいれないとダウンロードできない仕組みで試すのも最終手段にしたい
有料版がとても使いやすくてよいものなら払うけどなんか評判悪いのよね。
そんなわけでWixに移行したのだけどそれも難しくて大変だった。
今回Wix移行前のプロジェクトの修正依頼が来たのでまた移行作業するのも面倒でどうにかならんかなぁと調べてたら
これ入れればいいだけだった
MicrosoftVisualStudio2017InstallerProjects
使ってみた感想Wix移行いらなかったのでは・・
不思議とググって簡単に見つからないのよね。

メモ的な意味も含めて投稿

Web開発でのDebug Tips

JavaScriptで空ウィンドウ生成しログウィンドウとして使用する
具体的にはwindow.openで空のウィンドウを生成しそこにdocument.writeする。
Webアプリの開発などで動作ログを取りたいが画面内にあるとUIの邪魔になったり場合によってはレイアウトが崩れたりしてしまう。
この手法を使えばポップアップが抑制されない限りはモバイル端末でのデバッグの手助けになりそう。
ブラウザについている開発環境のコンソールでの出力作業領域としてもよいね。

例:
指定したURLを連番で開きselectorにあったリンクを抽出し空のページに出力するジャンクコード(未テスト)

var url="http://";//URL+NOで開く
var selector='a[href$=".zip"]';//これだとリンク先がzipであるリンクを抽出
var startno=0,endno=999;//開始Noと終了No
var cwnd=window.open("");//Popupブロックされていないか要確認
var cbk=function(no){var twnd=window.open(url+no);twnd.onload=function(){twnd.document.querySelectorAll(selector).forEach(function(e){cwnd.document.write(e.outerHTML);cwnd.document.write("<br>");});twnd.close();if(no<endno){cbk(no+1);}}}
cbk(startno);

[LookingGlass]holoplay.jsで焦点をオブジェクトの表面に合わせる

回転するとオブジェクトの裏に焦点がいきぼやけてしまうので
視線からオブジェクト表面の距離を求めてフォーカスをそこに合わせるようにしてみた

var vlocal = new THREE.Vector3(0, 0, -1);
var dir = vlocal.applyQuaternion(camera.quaternion);
//カメラと中心部の距離
var length = camera.position.clone().sub(objcenter).length();
//大体の表面位置を算出し焦点を移動
var pos = dir.multiplyScalar(length - objradius).add(camera.position);
holoPlay.lookAt(pos, camera);

レンダリングの直前に行うとよさそう

TypeScriptでclassをテンプレートとして活用

TypeScriptでクラスのテンプレートみたいなものがあって基本はそれを参照するけどメンバーに値を設定すればそちらを参照し
テンプレートは影響受けないみたいなの作ろうとして試行錯誤した結果
メンバー増えるごとに処理するのめんどいのでインスタンス生成時に

class PlayerTemplate {
    constructor(public Name:string="Template", public Level:number=0) {
    }
}
var player = new class extends PlayerTemplate {
    Name="Hoge";//設定しなければTemplateのまま
    Level = 99;
};

が一番楽という結論に。
テンプレート変更は困難だけどメソッドも簡単に置き換えられるし
テンプレートを使って別のテンプレート生成みたいなのも簡単だからいいね。

なんとなく動的にclassを宣言生成するのに別言語から来てると違和感があるけど便利すぎる。

乱数の偏り

スプラトゥーン2で勝ち負けがどうも偏るよなぁという
個人的に感じたので勝ち負けを乱数としてみなした場合
偏りとは何ぞやということを考えた。
公式でもあるのかなぁとか探したけどよくわからなかったので
同じ値が続いた数:値が変化した数で偏りを表現してみようと試みる
例えば
〇●〇〇●● 2:3
〇〇〇●●● 4:1
〇●〇●〇● 0:5
みたいな感じでどうだろうか。当然合計すると全体-1の数になるね。
でも値の比率が偏ってると求めたいものは多分求められないので
〇〇〇〇〇〇 5:0
みたいなのはなし。
ちょうどイカリング2を見たら
勝率が25:25だったので(大体そう不思議)
6連勝して6連敗して4連勝したところで終わってる試合だったけど結果は
27:22
んー誤差なのかなぁ。
●〇のような2値じゃないケースだとどうやって計算すればいいのかは思いつかなかった

edge.jsではまり中

Visual Studio 2017でNode.jsのプロジェクトを作成
npmでedge.jsを入れたら
var edge = require(‘edge’);
の瞬間に落ちる。
追いかけてみたら例外メッセージでgitのURLが出てきた。
そこから落としたらものでやり直してみると今度はedge-csがないと怒られるのでnpmで入れてみたら謎なエラーになる。
試行錯誤してedge-csもgitから落としてきてやり直す。
今度は.NETの処理はコメントで書けとエラーが出るがgitに書かれてるes5のサンプルのままなんだよね。
tsconfig.jsonはes5になってるけどes6のサンプルで動かしてみたら動いた!

4時間ほどかけてまだ入り口・・

pixi.jsの動画再生を調べてみた

動画再生対応してるならよいなということで
https://pixijs.io/examples/#/basics/video.js
見てみると動かない。
コードを落としてIISで動かしてみると動く。
よくよく調べてみると
testvideo.mp4を読み込みに行って見つからないでエラーになってる。
でも読み込み処理は
var texture = PIXI.Texture.fromVideo(‘required/assets/testVideo.mp4’);
となってる。
上記処理がiframeにべた書きされたスクリプトでchromeで追いかけるのが困難だったので
Textureクラスにブレイクして逆にたどることで何とか発見。
おそらく問題は
pixi.jsファイルでパスを全部小文字変換してるとこ

function createSource(path, type) {
    if (!type) {
        path = path.split('?').shift().toLowerCase();

three.jsでのviewport領域のclearについて

ビューポートを変更しながら描画しても一度に全体を描画しないと消えるのを回避するには
preserveDrawingBufferをtrueにする
部分描画のときに全体クリアがはしるのを防ぐにはautoClearをfalseにする

var renderer = new THREE.WebGLRenderer({
                    preserveDrawingBuffer: true
                });
renderer.autoClear = false;

ビューポートを設定したあとその領域だけクリアして描画するには以下のようにする。

renderer.setViewport(rect.x, rect.y, rect.w, rect.h);
renderer.setScissorTest(true);
renderer.setScissor(rect.x, rect.y, rect.w, rect.h);
renderer.clear();
renderer.setScissorTest(false);
renderer.render(scene, camera);

今のところ正常に動いてるっぽい。