初createobject で .NET3.5系をNo.09320
こみやんま さん 21/04/10 04:33
 
仕様なのかミスなのか判然としないための質問となります。

.net framework 3.5系がインストールされていないPCで初めて気づいたのですが、
(3.5系は古すぎるため、Windows10などは最初はインストールされていない)


createobject経由で、.net framework 4.xのdllを「初めて読み込み実行した時」、
なぜか、.net framework 3.5系のインストーラーが起動します。

これは、Win10にある「実行プログラムが3.5系以下のアセンブリを参照しており、か
つ、プログラム実行で該当参照アセンブリを実際に利用するステップまで差し掛かっ
た時、3.5系を自動インストールするかユーザーに問い合わせる仕組み」のためと思
われます。

ということは、createobjectから.net framework 4.x系のdllを読み込む際に、
秀丸のプログラム内で.net framework 4.x と .net framework 3.5以下の「両方の
版」のアセンブリを参照した実装が為されているように思えます。

これは仕様でしょうか(普通は上位の.net frameworkのアセンブリ群への参照に成功
していれば、下位の版のへの参照は要らないように思えますが…)


[ ]
RE:09320 初createobject で .NET3.5系をNo.09322
秀丸担当 さん 21/04/12 09:53
 

情報ありがとうございます。
確かにそうなってしまうことが確認できました。
次のβ版で素のWindowsでもできるように修正します。

原因は、DLLが.netのものかどうかを判別するときにそうなっていました。
判別方法が、CorFlags.exe相当のことをするために、CoCreateInstanceでCorMetaDat
aDispenserRuntime(あるいはCorMetaDataDispenser)を作成しようとした時点でそ
うなるようでした。
これは秀丸ファイラーClassicのCPUカラム用に昔からしていた判別方法だったのです
が、秀丸ファイラーClassicのほうではなぜか失敗するだけで.NET3.5以下のインス
トールのウィンドウは出てこないようです。
依存性が無いようにEXE/DLLのヘッダーを地道に解析して判断するほうがよさそうです。
秀丸ファイラーClassicのほうも修正します。

[ ]
RE:09322 初createobject で .NET3.5系をNo.09325
秀丸担当 さん 21/04/13 11:39
 

V8.98β5で修正してみています。

あとV8.97でもなんとかする方法として、付属のHmRegAsm.exeを使ってユーザーごと
の登録をする方法があります。
HmRegAsm.exeのパラメータは仕様として公開されているものではないですが、以下の
ようにしてできます。
登録:
"C:\Program Files (x86)\Hidemaru\Hidemaru.exe" r "C:\MyFolder\MyClassLibrary.
dll"
登録解除:
"C:\Program Files (x86)\Hidemaru\Hidemaru.exe" u "C:\MyFolder\MyClassLibrary.
dll"

マクロにすると以下のような感じです。
#o=createobject("MyClassLibrary.Class1");
if(#o==0){
  runsync2 "\""+hidemarudir+"\\HmRegAsm.exe\" r \""
    + currentmacrodirectory+"\\MyClassLibrary.dll"
    + "\"";
  #o=createobject("MyClassLibrary.Class1");
}

でもこの場合は厳密には違って、MyClassLibrary.Class1が既に別の場所で登録済み
の場合は違うDLLになってしまいます。
#o=createobject($dllfile,$progid);の書き方の場合は常に指定したDLLとなるよう
に動作します。

[ ]
RE:09325 初createobject で .NET3.5系をNo.09330
こみやんま さん 21/04/14 14:06
 
β5での修正ありがとうございます。

>登録:
>"C:\Program Files (x86)\Hidemaru\Hidemaru.exe" r "C:\MyFolder\MyClassLibrar
>y.dll"
>登録解除:
>"C:\Program Files (x86)\Hidemaru\Hidemaru.exe" u "C:\MyFolder\MyClassLibrar
>y.dll"
管理者権限 なしで登録解除するのが秀丸から共通で一応は使えるわけですね。

>#o=createobject("MyClassLibrary.Class1");
>if(#o==0){
>  runsync2 "\""+hidemarudir+"\\HmRegAsm.exe\" r \""
>   + currentmacrodirectory+"\\MyClassLibrary.dll"
>    + "\"";
>  #o=createobject("MyClassLibrary.Class1");
>}

//-----------------------------------------------------------
$targetDllFullPath = currentmacrodirectory + @"\ClassLibrary100.dll";
#com = createobject( "ClassLibrary100.Class10");
if (!#com) {
    HmRegAsmで$targetDllFullPathのdll登録
}
// アセンブリの.dll自身のフルパスを返すようなメンバ関数を用意しておけばいい、
存在しなくとも処理は止まらず"0"みたいなものが返るだけ。
$currentComFullPath = member(#com, "GetAssemblyPath"); // return System.Refl
ection.Assembly.GetExecutingAssembly().Location; みたいなの返しておく

// 自分が想定しているアセンブリなのかチェック。同盟のNamespace+Classだけであ
るため違うdllを指している可能性がある。
if tolower($currentComFullPath) != tolower($targetDllFullPath)) {
    HmRegAsmで$targetDllFullPathのdll登録
}

#comを使った処理
//-----------------------------------------------------------

みたいにやれば、ミスマッチも防止できるとは思いますが、

ただまぁ、8.98でNET3.5インストーラー起動が修正されているのであれば、
非常に狭い範囲のバージョンで発生する現象ですのでまぁ普通の書き方でいいかなと
思っています。


[ ]