RSS

ASP.NET アプリが Windows 10 のアップデートで動かなくなった件

前々回くらいの Windows 10 アップデートで突然、ASP.NET アプリが動かなくなりました。アップデートが原因なら、そのうち対策が出てくると思ってほったらかしにしていました。

ASP.NET_error_win10update

ところが、今日、ググってみたら、それらしき投稿が見当たりません(日本語環境では)。
英語で検索してみたら、対策記事が出ていました。

https://developercommunity.visualstudio.com/content/problem/59516/vs-2017-152-cant-debug-aspnet-projects.html

これによると、レジストリにキーを追加しないといけないようです。コマンドプロンプトを管理者モードで開いて、次のコマンドを実行したら、前のようにちゃんと動くようになりました。

reg add HKLM\Software\WOW6432Node\Microsoft\InetStp /v MajorVersion /t REG_DWORD /d 10 /f
reg add HKLM\Software\Microsoft\InetStp /v MajorVersion /t REG_DWORD /d 10 /f

やはり、英語圏の情報は豊富ですね。

広告
 
コメントする

投稿者: : 2017/12/01 投稿先 ASP.NET, Windows

 

関数のパラメータの参照渡しとはどういうことなのか?

関数呼び出しで、関数(メソッド)のパラメータの渡し方には「値渡し」と「参照渡し」というのがあります。

ただ、Java や JavaScript には言語仕様としての参照渡しはなく、常に値渡しになります。

参照渡しの例ですが、最初に C# を例にして説明します。次のサンプルは2つのパラメータの値を交換するのに参照渡しを使っています。

using System;

public class SwapFunc
{
  static void Main(String[] args)
  {
    int x = 0;
    int y = 1;

    // x と y の値を交換
    Swap(ref x, ref y);

    Console.WriteLine("x = {0:d}, y = {1:d}\n", x, y);
  }

  // x と y の値を交換するメソッド
  static void Swap(ref int x, ref int y)
  {
    var u = x;
    x = y;
    y = u;
  }
}

これの IL (中間コード) は次のようになります。

コメントに動作を書きましたが、正確かどうかは別として、スタックマシン (仮想マシン) を使って、スタックフレーム上のデータをプッシュしたりポップしたりして計算を行っています。

このまま実行すると遅いので、通常、さらにネイティブコードに変換されて実行されます。

参照渡しに関わる部分は Main では、IL_0005 と IL_0006 のあたりです。ここで、スタックフレーム上のデータ x, y のアドレスをスタックに積んでいます。

関数 Swap 側で参照渡しに関わる部分は、ldind 命令を使っているあたりです。この命令は指定したオペランドの内容をアドレスとみなして、そのアドレスの行った先のデータをスタックに積んでいます。

//  Microsoft (R) .NET Framework IL Disassembler.  Version 4.0.30319.18020
//  Copyright (c) Microsoft Corporation. All rights reserved.



// Metadata version: v4.0.30319
.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
  .ver 4:0:0:0
}
.assembly Swap
{
  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) 
  .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
                                                                                                             63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )       // ceptionThrows.
  .hash algorithm 0x00008004
  .ver 0:0:0:0
}
.module Swap.exe
// MVID: {DDFC4E86-9AF5-4AC3-927E-267DAB2AEE1E}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003       // WINDOWS_CUI
.corflags 0x00000001    //  ILONLY
// Image base: 0x04700000


// =============== CLASS MEMBERS DECLARATION ===================

.class public auto ansi beforefieldinit SwapFunc
       extends [mscorlib]System.Object
{
  .method private hidebysig static void  Main(string[] args) cil managed
  {
    .entrypoint
    // コード サイズ       39 (0x27)
    .maxstack  3
    .locals init (int32 V_0,
             int32 V_1)
    IL_0000:  nop
    IL_0001:  ldc.i4.0  0 をプッシュ。
    IL_0002:  stloc.0  0 をポップしスタックフレーム V_0 に保存
    IL_0003:  ldc.i4.1  1 をプッシュ。
    IL_0004:  stloc.1  1 をポップしてスタックフレーム V_1 に保存
    IL_0005:  ldloca.s   V_0  V_0 のアドレスをプッシュ。
    IL_0007:  ldloca.s   V_1  V_1 のアドレスをプッシュ。
    IL_0009:  call       void SwapFunc::Swap(int32&,  Swap をコール
                                             int32&)
    IL_000e:  nop   何もしない。
    IL_000f:  ldstr      "x = {0:d}, y = {1:d}\n"  フォーマットのアドレスをプッシュ
    IL_0014:  ldloc.0  V_0 の値をプッシュ。
    IL_0015:  box        [mscorlib]System.Int32 スタックのトップをボクシング
    IL_001a:  ldloc.1  V_1 の値をプッシュ。
    IL_001b:  box        [mscorlib]System.Int32 スタックのトップをボクシング
    IL_0020:  call       void [mscorlib]System.Console::WriteLine(string, Console.WriteLine をコール
                                                                  object,
                                                                  object)
    IL_0025:  nop  何もしない。
    IL_0026:  ret  もどる。
  } // end of method SwapFunc::Main

  .method private hidebysig static void  Swap(int32& x,
                                              int32& y) cil managed
  {
    // コード サイズ       12 (0xc)
    .maxstack  2
    .locals init (int32 V_0)
    IL_0000:  nop
    IL_0001:  ldarg.0  引数0をプッシュ。
    IL_0002:  ldind.i4 スタックトップをアドレスとしてその行った先の内容をプッシュ。
    IL_0003:  stloc.0  ローカル変数 0 に格納。
    IL_0004:  ldarg.0  引数0をプッシュ。
    IL_0005:  ldarg.1  引数1をプッシュ。
    IL_0006:  ldind.i4  スタックトップをアドレスとして、その行った先の内容をプッシュ。
    IL_0007:  stind.i4  スタックトップをアドレスとして、その行った先へストア。
    IL_0008:  ldarg.1 引数1をプッシュ。
    IL_0009:  ldloc.0 ローカル変数0をプッシュ。
    IL_000a:  stind.i4 その行った先の内容をプッシュ。
    IL_000b:  ret
  } // end of method SwapFunc::Swap

  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    // コード サイズ       7 (0x7)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  ret
  } // end of method SwapFunc::.ctor

} // end of class SwapFunc


// =============================================================

// *********** 逆アセンブルが完了しました ***********************
// 警告: Win32 リソース ファイル C:\workspace\dotNET\IL\Swap\Swap.res を作成しました。

次に、C 言語の例を見てみます。

C 言語の場合、VM (仮想マシン) は使用しない、つまり、いきなりネイティブコードを生成します。

ここでは、PC で使われている x86 と x64 について述べます。RISC や IBM などでは、基本的考え方は同じはずですが、Calling Convention (呼び出し規約) がそれぞれ異なるのでいろいろ異なります。

まず、C のソースですが、下のようなものとします。

#include <stdio.h>

void swap(int*, int*);

int main(int argc, char* argv[]) {
  int x = 0;
  int y = 1;

  swap(&x, &y);

  printf("x = %d, y = %d\n", x, y);

  return 0;
}

void swap(int* x, int* y) {
  int u = *x;
  *x = *y;
  *y = u;
}

 

これのコンパイル結果は、次のようになります。(x86 の場合)

	.file	"Swap.c"
	.section	.rodata
.LC0:
	.string	"x = %d, y = %d\n"
	.text
.globl main
	.type	main, @function
main:
	leal	4(%esp), %ecx
	andl	$-16, %esp
	pushl	-4(%ecx)
	pushl	%ebp
	movl	%esp, %ebp
	pushl	%ecx
	subl	$36, %esp
	movl	$0, -8(%ebp)  0 をスタックフレームのローカルアドレスに保存(x)
	movl	$1, -12(%ebp)  1 をスタックフ
レームのローカルアドレスに保存(y)
	leal	-12(%ebp), %eax y のアドレスを EAX にロード
	movl	%eax, 4(%esp) EAX をスタックに積む。
	leal	-8(%ebp), %eax x のアドレスを EAX にロード
	movl	%eax, (%esp) EAX をスタックに積む。
	call	swap  関数 swap を呼び出す。
	movl	-12(%ebp), %eax
	movl	-8(%ebp), %edx
	movl	%eax, 8(%esp)
	movl	%edx, 4(%esp)
	movl	$.LC0, (%esp)
	call	printf
	movl	$0, %eax
	addl	$36, %esp
	popl	%ecx
	popl	%ebp
	leal	-4(%ecx), %esp
	ret
	.size	main, .-main
.globl swap
	.type	swap, @function
swap:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$16, %esp
	movl	8(%ebp), %eax 後から積んだパラメータ(x)を EAX にロード
	movl	(%eax), %eax  EAX の行った先のデータを EAX にロード
	movl	%eax, -4(%ebp) EAX をローカル変数に保存。
	movl	12(%ebp), %eax 最初に積んだパラメータ(y)を EAX にロード
	movl	(%eax), %edx  EAX の行った先のデータを EDX にロード
	movl	8(%ebp), %eax 後から積んだパラメータ(x)を EAX にロード
	movl	%edx, (%eax) EDX を EAX の行った先に保存
	movl	12(%ebp), %edx 最初に積んだパラメータ(y)を EDX にロード
	movl	-4(%ebp), %eax ローカル変数の内容を EAX にロード
	movl	%eax, (%edx) EAX を EDX の行った先に保存。
	leave
	ret
	.size	swap, .-swap
	.ident	"GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)"
	.section	.note.GNU-stack,"",@progbits

x64 の場合は、関数の呼び出し規約が異なっており、整数や浮動小数点数は最適化しなくてもレジスタ渡しになります。

これは、x64 では、汎用レジスタが8本から16本に増えたためで、余ったレジスタを関数のパラメータとして活用しています。

	.file	"Swap.c"
	.section	.rodata
.LC0:
	.string	"x = %d, y = %d\n"
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	subq	$32, %rsp
	movl	%edi, -20(%rbp)
	movq	%rsi, -32(%rbp)
	movl	$0, -8(%rbp)
	movl	$1, -4(%rbp)
	leaq	-4(%rbp), %rdx  RDX には y のアドレスが入る。
	leaq	-8(%rbp), %rax  RAX には x のアドレスが入る。
	movq	%rdx, %rsi  呼び出し規約に基づいて、パラメータを RSI レジスタ渡しにしている。
	movq	%rax, %rdi  呼び出し規約に基づいて、パラメータを RDI レジスタ渡しにしている。
	call	swap
	movl	-4(%rbp), %edx
	movl	-8(%rbp), %eax
	movl	%eax, %esi
	movl	$.LC0, %edi
	movl	$0, %eax
	call	printf
	movl	$0, %eax
	leave
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.globl	swap
	.type	swap, @function
swap:
.LFB1:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	movq	%rdi, -24(%rbp)
	movq	%rsi, -32(%rbp)
	movq	-24(%rbp), %rax
	movl	(%rax), %eax
	movl	%eax, -4(%rbp)
	movq	-32(%rbp), %rax
	movl	(%rax), %edx
	movq	-24(%rbp), %rax
	movl	%edx, (%rax)
	movq	-32(%rbp), %rax
	movl	-4(%rbp), %edx
	movl	%edx, (%rax)
	popq	%rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE1:
	.size	swap, .-swap
	.ident	"GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4"
	.section	.note.GNU-stack,"",@progbits

 

参照渡しができない言語の場合、言語仕様として参照表現がないというだけで、参照渡しは使われています。

パラメータが値渡しされる場合は、汎用レジスタに値がロードできるもの、具体的には整数や浮動小数点数が値渡しになり、汎用レジスタに値がロードできないもの、具体的には配列や一般のオブジェクトが参照渡しになります。

したがって、参照渡しされる型を利用すれば、swap 関数と同様の機能が実現できます。

つぎのコードは JavaScript で参照渡しと同様の機能を実現する例です。配列は参照渡しなので、swap 関数により2つのパラメータの中身が交換されます。

 

'use strict';

const swap = (x, y) => {
    let u = x[0];
    x[0] = y[0];
    y[0] = u;
};

var a = [0];
var b = [1];

swap(a, b);

console.log("%i, %i", a, b);


 

 
コメントする

投稿者: : 2017/11/30 投稿先 未分類

 

Windows 10 で勝手にすぐスリープする件

Windows 10 でスリープ設定は20分とかにしてあるのに、すぐスリープしてしまうことがあります。

いつも、そうなる訳ではないのですが、ちょっと目を離したすきにスリープしてしまうので困っていました。

どこかのレジストリが壊れたのかと思っていましたが、ググってみたら、そういう症状がほかでも起こっているようで、解決方法が見つかりました。(英語ですが)

https://ugetfix.com/ask/how-to-fix-windows-10-going-into-the-sleep-mode-after-1-minute-idle/#qm-h2-2

やってみたのはレジストリエディタを使う方法なので、コンピュータに詳しくない人はやめておいた方がいいかもしれません。

手順

  1. レジストリエディタを起動
  2.  HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power\PowerSettings\238C9FA8-0AAD-41ED-83F4-97BE242C8F20\7bc4a2f9-d8fc-4469-b07b-33eb785aaca0
  3. 上のキーを開く。
  4. Attributes の値を2に変更する。
  5. レジストリエディタを閉じる。
  6. コントロールパネルを開く。
  7. コントロール パネル\システムとセキュリティ\電源オプション\プラン設定の編集 を開く。
  8. 「詳細な電源設定の変更」をクリック。
  9. 「スリープ」の中に「システム無人スリープタイムアウト」という設定が追加されているので、設定を2分から長い値に変更する。
  10. OK ボタンを押してダイアログを閉じる。
  11. コントロールパネルを閉じる。

 

レジストリエディタの変更位置

Regedit

電源オプションの変更位置

PowerOption

PowerOpt2

 

 
コメントする

投稿者: : 2017/11/29 投稿先 Windows

 

Node.js Event Loop とは

Node.js は、 Event Loop というループ内で実行されます。これはブラウザの JavaScript が DOM からのイベントを処理するメカニズムを継承したものである。

Node.js Event Loop

(図をクリックすると拡大できます)

各フェーズの概要は次の通りです。

  • timers: setTimeout() と setInterval()により設定されたコールバックを実行する。
  • I/O callbacks: ほとんど全部のコールバックはここで実行される。例外はタイマ関連とsetImmidaite()関連である。
  • idle, prepare: 内部的に利用される。
  • poll: 新たな I/O イベントを取り出す。
  • checksetImmediate() はここでコールバックと呼び出しを行う。
  • close callbacks:  socket.on('close', ...)などはここで行う。

詳しくは Node.js のイベントループを理解する を参照。

 

 

 
コメントする

投稿者: : 2017/11/10 投稿先 JavaScript, node.js

 

Ubuntu に最新のNode.jsをインストールしてみた。

Qiita の下記投稿「Ubuntuに最新のNode.jsを難なくインストールする」を参考にやってみました。環境は Ubuntu 16.04LTS です。

https://qiita.com/seibe/items/36cef7df85fe2cefa3ea

この投稿で最初の手順

sudo apt-get install -y nodejs npm

は古いNode.jsがすでに入っていたので省略しました。よって「n package を導入」からです。

sudo npm cache clean
sudo npm install n -g

これは問題なし。次の手順「最後に n package を使って node をインストール」です。

sudo n stable
sudo ln -sf /usr/local/bin/node /usr/bin/node

ここで、n stable は安定版(この時点では8.9.0LTS)になるかと思っていましたが、9.0.0がインストールされました。n コマンドで具体的なバージョン番号を指定したほうがよさそうです。(自分は9.0.0でもかまわなったので、やってませんが)

ln -sf /usr/local/bin/node /usr/bin/node ですが、Node.js のインストール先は、/usr/local/bin/node にはならず、自分の場合は /usr/local/n/versions/node/9.0.0 になっていました。

よって、このコマンドをそのまま実行しても機能しませんでした。

さらに、nodejs というのが node コマンドの別名になっていていました。(自分の環境だけかもしれませんが)

最後の古いNode.js を削除する手順を行わないと、古いバージョンと新しいバージョンがバッティングするので必ず行ったほうがよさそうです。

sudo apt-get purge -y nodejs npm

この後に、3つのシンボリックリンク /usr/bin/node, /usr/local/bin/node, /usr/bin/nodejs を

/usr/local/n/versions/node/9.0.0/bin/node

に変更しました。これでどれが使われても安心です。

user@ubuntu:~$ node -v
v9.0.0

ところで、SSL Error: CERT UNTRUSTED というエラーが出ることがあります。次の対処法を行ったら回避できました。

npm install で SSL Error になった時の対処法。
https://blog.yug1224.com/archives/563d9b67bf652a600632d01e

具体的には npm config set ca “” を行いました。

 

終わり

 

 

 
コメントする

投稿者: : 2017/11/08 投稿先 node.js

 

ASP.NET: アプリケーションのバージョンを表示するには

アプリケーションのプロパティの「アセンブリ情報」で定義したバージョンをWebページに表示したい場合、MVC の場合なら、Views/Shared/_Layout.vbhtml (または .cshtml) に次のように1行追加するとよい。(場所は任意)

Version @ViewContext.Controller.GetType().Assembly.GetName().Version

画面上では、次のような感じで表示される。

 
コメントする

投稿者: : 2017/06/04 投稿先 未分類

 

Oracle のストアドプロシージャ実行

SQL*PLUS (や SQL Developer) でストアドプロシージャを実行するとき、EXECUTE (または EXEC) で行います。
しかし、ストアドプロシージャの動作確認後、プログラムに埋め込んで実行したら、SQL が間違っているみたいなメッセージが出て動作しません。

この原因は、EXECUTE は SQL*PLUS のコマンドで、SQL*PLUS でのみ使用可能なためだそうです。

EXECUTE の代わりに CALL にしたらちゃんと動きました。

CALLとEXECUTEの違い
http://www.shift-the-oracle.com/sqlplus/tutorial/call-execute-plsql.html

 
コメントする

投稿者: : 2017/05/26 投稿先 Database