2019年7月30日火曜日

VisualStudioで既存のフォルダをプロジェクトに追加する

諸事情で(謎)、VisualStudio 2015 を使い続けてます。
他のプロジェクトをコピーして新しいプロジェクトとして再構築しようとする際にフォルダ配下のファイルをプロジェクトに追加するとフォルダーなしでプロジェクトに追加されてしまいます。

でもって、新規フォルダで同名のフォルダを追加しようとするとエラー。

WEBを検索すると、エクスプローラからソリューションエクスプローラにフォルダをドラッグ&ドロップするとうまくいくとの記述を見ますが、こちらの環境ではうまく動いてくれません。

ということで、以下の手続きでフォルダを追加しました。

1.VisualStudio を終了
2.目的のプロジェクトの .csproj ファイルをエディタで開く
3.以下の記述を追加
<ItemGroup>
<Folder Include="フォルダ名\" />
</ItemGroup&lgt;
4.保存終了して .sln を開く。

無事フォルダが追加されます。
既存ファイルを追加すると、上記の Folder Include は消えてなくなります。

本題に関係ありませんが、エクスプローラがとてもよく落ちてしまうようになって、ストレスまっくすな状態です。
こっちを何とかしたいw

2019年6月11日火曜日

XML HTTP Request status 12157

WEBサーバーへの問合せにXML応答をするよう構築しているのですが、とある企業様から
Response status:12157
と表示されてエラーになる!とのご指摘がありました。

10,000を超えるユーザーが同じ処理を利用しているのに、この企業様のコンピュータからはエラーが表示されて失敗するとおっしゃるのです。
そこで HTTP Request 12157 のキーワードでいろいろと調べてみますと、最終的にこの部分が該当するのではないか、となったわけです。

https://support.microsoft.com/ja-jp/help/3140245/update-to-enable-tls-1-1-and-tls-1-2-as-default-secure-protocols-in-wi

ところが、企業様ではTLS 1.1, 1.2 ともに有効だから関係ない!とおっしゃる。

さらに調べると、公開鍵や秘密鍵のやり取りうんぬんが必要とか出てきて、わけわかめ状態になってしまいました。

企業様に、APIのあるサイトにテストCGIを用意してアクセスをお願いしてみましたら、原因がわかりました。

WEBサーバーのアドレスがファイアウォールのブラックリストに追加されていたのだそうです。

ホワイトリストに追加していただくことで問題が解決しました。

でも、ちょっと待て!
なぜにうちのサーバーがブラックなの?
とお問い合わせしてみましたら、「パークドメイン」だからなのだそうです。

たしかにAPI専用のサーバで、WEBコンテンツは公開してないけど・・・
今後のためにWEBコンテンツを配置しておいたほうがいいのかな・・・

2019年1月21日月曜日

Perl uri_unescape で文字化け

実は文字化けにはその後も苦しんでおりまして。
原因となる現象をようやく突き止めましたのでサンプルプログラムを公開しますね。

use Carp::Heavy;
use strict;
use URI::Escape;
use Encode;
use encoding 'utf-8';

my $a1 = '%E8%A9%A6%E9%A8%93';
my $b0 = '試験';
my $b1 = uri_escape_utf8($b0); #内容は '%E8%A9%A6%E9%A8%93'
print("$a1\n");
print("$b1\n");
print("1\n") if($a1 eq $b1);    #当然のごとく1が出力される

my $a2 = uri_unescape($a1);
my $b2 = uri_unescape($b1);
print("1\n") if($a2 eq $b2);    #なぜか 1 が表示されない
print("$b2\n"); #こちらは '試験'
print("$a2\n"); #文字化け
exit;


use encoding 'utf-8' を取ったり use utf8; にしたりすると他所に
大影響が出てしまうため変更できません。

これ。本当にハマりましたよ。
いったい何がどうなっているのかさっぱりわかりませんでした。

※実際には CGI 上のパラメータが文字化けしてました。

上記の謎の動作ですが
$a1= encode_utf8($a1);
を呼び出すことで期待通りの動きをすることがわかりました。

さて、本番環境に対応しようと・・・
my $cgi = new CGI();
my $a2 = $chi->param('a2');
文字化けです。
CGI の sub new で取得するuri_encode されたパラメータに対して事前に
encode_utf8を実行しなければならないのに、POSTリクエストだから標準
入力を変更する術が見つかりません。

じゃあ、ってことで呼び出し側を GET にしましたら、なんの変更も加えず
文字化けしなくなりましたよ。
Perlモジュールのバージョンの影響かと思い、さんざん調査すること3日
こういうのって、あっけなく解決するもんなんですねぇ
あー眠たい。

2018年12月30日日曜日

perl CGI HTML::Template で文字化け

Perl CGI での文字化け問題は何年も前に解決させたはずだったのですが(以前は Perl + Template の場合)
新しい CentOS (サーバに無料で入ってる Ver 6)の環境で、現在動作しているcgiを実行すると文字化けしてしまう現象に悩まされました。

ハマった手順を書いてみますね。

1)httpd.conf の変更
文字化けはこれでなおる!とネット上のあちこちに書いてあります。
# vi /etc/httpd/conf/httpd.conf

AddDefaultCharset off
または
#AddDefaultCharset off コメントアウト。


動作結果:NG
世界中でほとんど解決しているらしいのですが、うまくいきません。

2)php.ini の変更
# vi /etc/php.ini

;default_charset = "UTF-8"

default_charset = ""
に変更


動作結果:NG
そもそも php 使ってませんし。

ここでブラウザ側のレスポンスヘッダを確認してみますと utf-8 となっていました。
んー?なのに文字化け?理解できないぞ・・・

ちなみに、cgi のソースや HTML, CSS, JS, テンプレートファイルなど、すべてのファイルは UTF-8 で記述してます。(改行は LF)
なぜだろう、と、試験を実施することに。


3)簡単なHTMLを用意
[test.html]

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>テストページ</title>
    </head>
    <body>
        UTF-8で記述されたページ
    </body>
</html>


動作結果:なんと、うまく表示されます。

4)cgi だとダメなのかな?
[test.cgi]

#!/usr/bin/perl --
print "Content-Type: text/html; charset=utf-8\n\n";
print "<html><body><div>\n";
print 'クオート文字';
print '<br>';
print "ダブルクオート文字";
print '<br>';
print "<div></body></html>\n";
exit;

クオートとダブルクオートで分けたのは、 perl の動作で文字化けしているのかどうかを確認するためです。

動作結果:なんと、うまく表示されます。

5)HTML::Template が怪しい。
どうやら使用している HTML::Template が怪しいのではないかとあたりを付けて検索したら情報がありました。
HTML::Template 2.98 で UTF問題が解決してる!というのです。
移行先のサーバーの HTML::Template は Ver,2.97 です。
ちなみにうまくいっていた旧サーバーの HTML::Template は Ver,2.94 でした。

Ver 2.98 のソースはここにありました。
https://github.com/mpeters/html-template

CPAN からのインストールしかやったことないので、git からどうやってインストールするのかわからずw
ダウンロードした HTML/Template.pm, HTML/Template/FAQ.pm をそのまま perl5 のファイルに上書きw

文字化けする cgi を動作させてみました。

動作結果:NG
ここまで、大量に時間を食ったにもかかわらず、うまくいかないとは・・・

6)binmode => 'utf8' を記述
既存 cgi の new HTML::Template 構文で、binmode => 'utf8' を追加する、との記述があったので
試してみました。

動作結果:NG
この記述は、上記リンクをたどる際に対応したパッチを当てたソースの場合に有効だったもので、動かないことは予想できていました。

7)utf8 => 1 を記述
HTML/Template のドキュメントを読み、new 構文の utf8 オプションがあることを発見。(旧サーバにはないオプションでした。)

既存 cgi の new HTML::Template 構文で、utf8 => 1 オプションを追加して実行してみました。

my $tmpl = HTML::Template->new(die_on_bad_params => 0, filename => $file, utf8 => 1);

動作結果:おお!!!!ようやく文字化けせずに表示されました!

しかしながら、問題があります。
既存プログラムの cgi ファイルは山のようにあります。
その全部にフラグを追加するのは困難ですよ。
デグレードなんか発生させちゃった日にゃ目も当てられません。
なんとかならないかな・・・

8)HTML::Template を編集。
perl5 の HTML/Template.pm を開いてみると、次のような部分なありました。

my %OPTIONS;
BEGIN {
    %OPTIONS = (
        debug                       => 0,
        ;
        utf8                        => 0,
        ;

ええい、こいつを1にしてしまえ!

        utf8                        => 1,

と変更した後で、既存の cgi に戻して動作

動作結果:OK

文字化けが解消されました!!!

モジュールの挙動が変わるなんて、ほんと困りものです。

2018年10月15日月曜日

マルチディスプレイ環境で親ウィンドウの中心にウィンドウを表示するには

表題の通りです。

親ウィンドウの中央にダイアログなどを表示しようとすると、親ウィンドウそのものが画面から外れている場合に表示領域外に表示されてしまったりして困ったことになります。

マルチディスプレイ環境だったりすると、座標域に負数が含まれる場合などもあって、なかなかややこしい。

WEB上を検索しても、GetSystemMetrics(SM_CXSCREEN)とかGetSystemMetrics(SM_CXSFULLCREEN) などを使ったサンプルしか公開されていなくて、ちょっと不満だったので書いてみました。

ま、実際にはもっとややこしい環境もあると思うので完全ではないかもしれないけど、うちの環境では表示されるのでよしとしようw

ヘッダファイルの記述

extern BOOL SetWindowCenterParent(HWND handle, HWND parent, int width, int height, int min_width = -1, int min_heigh = -1);

ソースファイル

#include 
//
// ウィンドウを親ウィンドウの中心に表示する
//
// 【パラメータ】
//  HWND handle     対象となるウィンドウハンドル
//  HWND parent     親ウィンドウハンドル(HWND_DESKTOP も可)
//  int width       ウィンドウの幅
//  int height      ウィンドウの高さ
//  int min_width   最小ウィンドウ幅(不要な場合は負数を指定)
//  int min_heigh   最小ウィンドウ高さ(不要な場合は負数を指定)

BOOL SetWindowCenterParent(HWND handle, HWND parent, int width, int height, int min_width, int min_heigh)
{
 // 親ウィンドウの中心を取得
 RECT parent_rect;
 GetWindowRect(parent, &parent_rect);

 POINT center;
 center.x = (parent_rect.right + parent_rect.left) / 2;
 center.y = (parent_rect.bottom + parent_rect.top) / 2;

 // ディスプレイ情報
 SIZE display;
 display.cx = GetSystemMetrics(SM_CXVIRTUALSCREEN);
 display.cy = GetSystemMetrics(SM_CYVIRTUALSCREEN);
 
 // タスクバーの大きさを調整
 SIZE screen;
 screen.cx = GetSystemMetrics(SM_CXSCREEN);
 screen.cy = GetSystemMetrics(SM_CYSCREEN);
 RECT work_area;
 SystemParametersInfo(SPI_GETWORKAREA, 0, &work_area, 0);
 SIZE task_bar;
 task_bar.cx = screen.cx - (work_area.right - work_area.left);
 task_bar.cy = screen.cy - (work_area.bottom - work_area.top);
 display.cx -= task_bar.cx;
 display.cy -= task_bar.cy;

 POINT origin;
 origin.x = GetSystemMetrics(SM_XVIRTUALSCREEN);
 origin.y = GetSystemMetrics(SM_YVIRTUALSCREEN);

 // 最小サイズ、最大サイズの検査
 if ((0 < min_width) && (width < min_width))
 {
  width = min_width;
 }
 if ((0 < min_heigh) && (height < min_heigh))
 {
  height = min_heigh;
 }
 if (display.cx < width)
 {
  width = display.cx;
 }
 if (display.cy < height)
 {
  height = display.cy;
 }
 // 表示位置
 POINT place;
 place.x = center.x - (width / 2);
 place.y = center.y - (height / 2);

 // ディスプレイの座標範囲(マルチディスプレイ含む)からのはみだし検査
 if ((origin.x + display.cx) < (place.x + width))
 {
  place.x = origin.x + display.cx - width;
 }
 if (place.x < origin.x)
 {
  place.x = origin.x;
 }
 if ((origin.y + display.cy) < (place.y + height))
 {
  place.y = origin.y + display.cy - height;
 }
 if (place.y < origin.y)
 {
  place.y = origin.y;
 }
 return SetWindowPos(handle, HWND_TOP, place.x, place.y, width, height, 0);
}

2018年8月17日金曜日

Windows 10 でコントロールパネルを開く

同じような情報がWEB上にたくさんありますが、Windows10でコントロールパネルを開く方法です。

1.エクスプローラを開きます。
タスクバーのアイコンをクリックするのが早いですね。


2.メニュー下の「↑」ボタンを押します。
コントロールパネルがこんなところにありますね。
 
おや。デスクトップ上のアイコンもあるではないですか。
こいつは便利だ。
と思ったので書き留めておきました。


2018年7月30日月曜日

HTML 枠内にできるだけ大きめの表示。大きければ縮小して全体を表示

WEBページ表示で、「Excel のように縮小して全体を表示したい」という衝動には何度も駆られますね。
住所表示用の枠を用意していて、通常はうまいこと表示できるけど長い住所だとはみ出してしまう、とか。
あともう一つ。「枠内にできるだけ大きく表示させたい」というのもあります。
PDFの編集領域とか宛名ラベル用のアプリケーションなどにそういった枠があります。
今回はその両方、つまり
『文字列が短いときは枠内にできるだけ大きく表示』
『文字列が長いときは枠内に縮小して全体を表示』
という2つの要求を満たしたい、という仕様です。
まぁ印刷する必要のあるページなどには必須だと思います。

WEB上を探していくつかダウンロードしてみましたけど、思うように動いてくれなかったので自作しました。
突っ込みどころあると思いますが、とりあえず動いたので公開しときます。
(きっとたくさんの人がこういった情報を求めているだろうと想像したのでw)

住所表示用に用意した、span id="span_address" のタグに「秋田県北秋田郡上小阿仁村大字沖田面字小蒲野下タ川原」を放り込みたいときのサンプルコードを示します。
(※住所は長い住所で検索したら出てきたもの)

<html>
<head>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
  <script type="text/javascript">
    <!--
      // sample
      window.onload=function()
      {
        $('#span_address').text('秋田県北秋田郡上小阿仁村大字沖田面字小蒲野下タ川原');
        adjust_tagfont();
      }
      // 表示、再表示時に呼び出す
      function adjust_tagfont()
      {
        //はみ出しそうなタグの親idを列挙
        var tags = ['div_address'];
        tags.forEach(adjust_tag);
      }
      // タグの確認
      function adjust_tag(tag, index, array_name)
      {
        if(document.getElementById(tag) !== null)
        { 
            $('#' + tag).autoSizeByWidth();
        }
      }
      // width/height のクラス
      function ssize(_width, _height)
      {
        this.width = _width;
        this.height = _height;
      }
      // 文字列表示の幅と高さを計算する
      function string_size(str, font_size)
      {
        var chk_span = $("#for_check");
        chk_span.text(str);
        chk_span.css('fontSize', font_size + 'px');
        var width = chk_span.outerWidth();
        var height = chk_span.outerHeight();
        chk_span.empty();
        return new ssize(width, height);
      }
      // 
      jQuery.fn.extend(
      {
        autoSizeByWidth: function()
        {
          $this = $(this);    // 枠
          this.each(function()
          {
            $this = $(this);
            var p_width = $this.width()
            var p_height = $this.height();
            var str = $.trim($this.text()); //センタリングなどの処理をはずす
            var fontSize = parseInt($this.css('fontSize').replace('px', ''));
            var child_size = string_size(str);
            // できるだけ大きく
            while((child_size.width < p_width) && (child_size.height < p_height))
            {
              child_size = string_size(str, ++fontSize);
            }
            //はみ出しているとき
            while((p_width < child_size.width) || (p_height < child_size.height))
            {
              child_size = string_size(str, --fontSize);
            }
            $this.css('fontSize', fontSize + 'px');
          });
          return this;
        },
      });
    -->
  </script>
</head>

<body>
  <span id="for_check" style="visibility:hidden;position:absolute;white-space:nowrap;">
  </span>
  <table width="400" border="1">
    <tr>
      <td width="300" height="50">
        <div id="div_address">
            <span id="span_address">&nbsp;</span>
        </div>
      </td>
      <td width="100">
        &nbsp;
      </td>
    </tr>
</body>
</html>

table タグで物理的な大きさを指定してます。
任意のサイズにして確認してみてください。

いちおう解説しますと・・・
まず枠の大きさを取得します。
フォントサイズを拡張して枠からはみ出すところまで確認した後で枠の中に納まるようフォントサイズを縮小していきます。
これだけなんだけど、まわりっくどいっすねw

お役に立てれば幸いです。