C# と VB.NET の質問掲示板

わんくま同盟

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

ツリー一括表示

VBAから扱えるDLLの作成 /あずさ2号 (24/12/10(Tue) 15:21) #103472
Re[1]: VBAから扱えるDLLの作成 /くま (24/12/10(Tue) 15:58) #103473
  └ Re[2]: VBAから扱えるDLLの作成 /くま (24/12/10(Tue) 16:07) #103474
    └ Re[3]: VBAから扱えるDLLの作成 /あずさ2号 (24/12/11(Wed) 10:51) #103475
      ├ Re[4]: VBAから扱えるDLLの作成 /魔界の仮面弁士 (24/12/11(Wed) 11:30) #103477
      └ Re[4]: VBAから扱えるDLLの作成 /くま (24/12/11(Wed) 11:23) #103476
        └ Re[5]: VBAから扱えるDLLの作成 /radian (24/12/13(Fri) 10:21) #103478


親記事 / ▼[ 103473 ]
■103472 / 親階層)  VBAから扱えるDLLの作成
□投稿者/ あずさ2号 (1回)-(2024/12/10(Tue) 15:21:50)

分類:[.NET 全般] 

宜しくお願い致します。
件名にあるとおり、VBAから扱えるDLLを作成したく、
https://excel.syogyoumujou.com/memorandum/dll_1.html
を見つけました。
VSのバージョンは、HPではVS2017、わたしのはVS2022版です。その違いなのか、該当する箇所の内容が表示出来ません。
結構プロパティを検索しましたが、見つかりませんでしたので、ご存知な方教えてもらえますか?

箇所ですが、
1)ソリューションエクスプローラーのプロジェクト名(Sample)を右クリックし、表示されるメニューの「プロパティ」を選択
  COM相互運用機能の登録(E)のチェックボックス(ページ下部にある)にチェックを入れる。 <ー見つかりました
2)同「プロパティ」メニューの「アプリケーション」→「アセンブリ情報」を選択。
  「アセンブリをCOM参照可能にする」にチェック  <ー見つかりません

原因がそれに依るものなのか、わかりませんが
以降の流れで、VBAの参照設定に、作成したSampleのDLLが現れるはずが現れません。

そこで、バージョンにより場所が移動したのかもしれませんので、「アセンブリ情報」を表示する場所を
教えていただけませんでしょうか?
宜しくお願い致します。


[ □ Tree ] 返信 編集キー/

▲[ 103472 ] / ▼[ 103474 ]
■103473 / 1階層)  Re[1]: VBAから扱えるDLLの作成
□投稿者/ くま (34回)-(2024/12/10(Tue) 15:58:54)
No103472 (あずさ2号 さん) に返信

・Visual Studio 2022
・vb.net
・.net framework 4.8 (4.8.1)
・WinForm

で作ってるけど表示自体は存在しますね...?
ただあってもOnにしない方が良いです。
理由は
・アセンブリをCOM参照可能にする(M)
off: <ComVisible(True)>を設定しないとCOM参照されない。
on : 登録されているClass等すべて<ComVisible(True)>となり公開されます。

簡単な仕組みなら良いですが、すべて登録されてしまうので思わぬ落とし穴にはまります。
きちんと公開するクラスのみ<ComVisible(True)>を付けてるようにした方が良いです。

実際の動作もきちんと「C:\Program Files (x86)」の下に実行ファイルをコピーして「レジストリ登録」して動作確認すると良いですよ。

どこの設定が影響するかは以下の通り

My Project > アプリケーション
・アセンブリ名(N):
com外部で参照する際使用する名前
生成ファイル名
・ルート名前空間(R):
内部でで参照する際使用する名前

My Project > アプリケーション > アセンブリ情報(Y)...
・タイトル(T):
dll参照時のタイトルプロパティ値
・説明(D):
dll参照時の説明プロパティ値
com参照時に表示される内容
・製品(P):
dll参照時の製品プロパティ値
・アセンブル バージョン(A):
com登録上別扱いで登録される
[ 親 103472 / □ Tree ] 返信 編集キー/

▲[ 103473 ] / ▼[ 103475 ]
■103474 / 2階層)  Re[2]: VBAから扱えるDLLの作成
□投稿者/ くま (35回)-(2024/12/10(Tue) 16:07:33)
こんなバッチファイルを用意して
ショートカットを作成し実行者権限を「管理者として実行」にしておくと
1クリックで登録できるようになります。

-----↓以下のテキストを.batファイルに張り付ける↓-----

@echo off
rem ****************************************************************************
rem ファイル名 :登録.bat
rem スクリプト名称 :
rem 処理概要 :フォルダ存在チェック→フォルダ作成→ファイルコピー→com登録
rem ****************************************************************************

rem ■■■変数設定■■■
rem -取得元パス
SET COPY_FROM="<プロジェクト保存先パス>\<プロジェクト名>\<プロジェクト名>\bin\Release"
rem -dllパス
SET DLL_PATH="%PROGRAMFILES%\<com保存先フォルダ名>\<アセンブリ名>.dll"

rem ■■■メイン処理■■■
echo □□□□ %COPY_TO%取得中 □□□□
rem -ローカルフォルダ存在チェック
call :check_folder %COPY_TO%

rem -com解除
call :com_reset %DLL_PATH%

rem -最新ファイル取得
call :copy_dll %COPY_FROM% %COPY_TO%

rem -com登録
call :com_setting %DLL_PATH%

pause
rem exit

rem ■■■ローカルフォルダ存在チェック■■■
:check_folder
if not exist %1 (
mkdir %1
)

exit /b 0

rem ■■■最新ファイル取得■■■
:copy_dll
@echo on
xcopy %1\* %2 /E /Y
@echo off
exit /b 0

rem ■■■com解除■■■
:com_reset
@echo on
call "C:\windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe" -u %1
@echo off
exit /b 0

rem ■■■com登録■■■
:com_setting
@echo on
call "C:\windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe" /codebase /tlb %1
@echo off
exit /b 0
[ 親 103472 / □ Tree ] 返信 編集キー/

▲[ 103474 ] / ▼[ 103477 ] ▼[ 103476 ]
■103475 / 3階層)  Re[3]: VBAから扱えるDLLの作成
□投稿者/ あずさ2号 (2回)-(2024/12/11(Wed) 10:51:59)
No103474 (くま さん) に返信
くまさん、色々とアドバイスありがとうございます。
そうします。
確かに、公開となると、よく理解していないだけに、すくんでしまします。
私としては、登録等などOSに手をかけない方法がいいでんすが・・・
例えば、作成したDLLをEXCELとセットでカレントに格納されてれば動作するよう
環境でしょうか。
そこで、検索中で、マクロからDLLをロードし、処理するサイトがありました。


一つ気になることがあります。
EXCElが32ビットなら、DLLも32ビットであることとネットで見たような気がします。
作成したDLL自体が、どちらなのか、新たな問題が発生しそうです。

本題に戻り、テストコードを作成しましたが、うまくいかない箇所がありますので、
そちらの方向で、皆さんアドバイスいただけないでしょうか?
宜しくお願い致します。
参考にしたURL
https://liclog.net/vba-dll-create-5/#google_vignette
https://excel.syogyoumujou.com/memorandum/dll_1.html  ←前質問で記載済みのURL
以下に、
クラスのコード-----------------------------------
ビルドしエラーは無く、Dllが作成されました。DLL名:ClassLibrary1.dll
Public Class Class1
Public Function Add(ByVal num1 As Integer)
Return num1 + 10
End Function

Public Function Hallo(ByVal sName As String)
Return sName & "sasaki"
End Function
End Class

以下、EXCELのVBAマクロ-----------------------------------
'動的にDLLを取得するためのWinAPI
Private Declare PtrSafe Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As LongPtr
Private Declare PtrSafe Function GetProcAddress Lib "kernel32" (ByVal hModule As LongPtr, ByVal lpProcName As String) As LongPtr
Private Declare PtrSafe Function FreeLibrary Lib "kernel32" (ByVal hLibModule As LongPtr) As Long
'DLLファイルの関数定義
Private Declare PtrSafe Function Hello Lib "ClassLibrary1.dll" (ByVal sName As String) As String

Public Sub maintest()
Dim hDll As LongPtr
Dim hProc1 As LongPtr
Dim hProc2 As LongPtr
Dim sFolderPath As String
Dim iFileSize As Long
Dim sFilePath As String

'DLLファイルを保存するフォルダパスを設定
sFolderPath = ThisWorkbook.Path

'DLLファイルを読み込む
hDll = LoadLibrary(sFolderPath & "\" & "ClassLibrary1.dll") '"DLLファイルフルパス

'DLLファイルの指定関数のアドレス取得
hProc1 = GetProcAddress(hDll, "Add")  'ここでエラーとなり取得出来ない、値=0
hProc2 = GetProcAddress(hDll, "Hallo") 'Halloで試みるが同じ結果 
If hProc1 = 0 Then
Call MsgBox("DLLファイルの読み込みに失敗しました")
Call FreeLibrary(hDll)
Exit Sub
End If

 Console.WriteLine (Class1.Add(20)) '30
'DLL解放
Call FreeLibrary(hDll)
End Sub


[ 親 103472 / □ Tree ] 返信 編集キー/

▲[ 103475 ] / 返信無し
■103477 / 4階層)  Re[4]: VBAから扱えるDLLの作成
□投稿者/ 魔界の仮面弁士 (3817回)-(2024/12/11(Wed) 11:30:50)
No103475 (あずさ2号 さん) に返信
> 私としては、登録等などOSに手をかけない方法がいいでんすが・・・

一応、COM にもレジストリ登録不要な Side-by-side インストールの仕組みはありますが、
Office からは Registration-Free COM を利用できなかったんじゃないかな…。

なので COM参照タイプのDLL (ActiveX DLL) を採用するなら、レジストリ登録が必須になるはずです。
ストアアプリ版の Office だと、それすら呼び出せなかったりもするようですが。


別案としては、VBA から Declare ステートメントで呼び出すタイプの関数公開型 DLL を作るか
https://qiita.com/mania3bb2007/items/020bea59e7c35c3204d3
https://github.com/3F/DllExport

あるいは、標準入出力でデータをやりとりする EXE を作って
それを VBA から WshShell の Exec メソッドで操作するという手も。
https://atmarkit.itmedia.co.jp/ait/articles/0407/08/news101_3.html
https://rcie.hatenablog.com/entry/2023/02/19/134601



> EXCElが32ビットなら、DLLも32ビットであることとネットで見たような気がします。
> 作成したDLL自体が、どちらなのか、新たな問題が発生しそうです。
DLL が x86 なのか x64 なのか AnyCPU なのかなどは、ビルド時に指定できます。
ビルド済みの .NET 製 DLL の状態を調べたい場合は、corflags.exe にて確認できます。

COM DLL の場合、32bitと64bitとで別管理されているため、レジストリ登録は
登録したい側もしくは両方でそれぞれ実施する必要があります。

> https://liclog.net/vba-dll-create-5/#google_vignette
URL 末尾の #google_vignette は要らないです。
https://coffee.hidetani.com/archives/658

でもって、そのサイトに書かれているのは COM 公開型の DLL の話ではなく、
Declare ステートメント等で使う関数公開型の DLL の話です。
VB や C# には、標準では関数公開型を作る機能は無いので、どうしても必要なら
先ほど述べた DllExport などを併用することになるでしょう。

> https://excel.syogyoumujou.com/memorandum/dll_1.html  ←前質問で記載済みのURL
こちらは COM 公開型の DLL 向けの情報です。まったく別の話。
[ 親 103472 / □ Tree ] 返信 編集キー/

▲[ 103475 ] / ▼[ 103478 ]
■103476 / 4階層)  Re[4]: VBAから扱えるDLLの作成
□投稿者/ くま (36回)-(2024/12/11(Wed) 11:23:07)
No103475 (あずさ2号 さん) に返信
> ■No103474 (くま さん) に返信
> くまさん、色々とアドバイスありがとうございます。
> そうします。
> 確かに、公開となると、よく理解していないだけに、すくんでしまします。
> 私としては、登録等などOSに手をかけない方法がいいでんすが・・・
その為のバッチだったんですが...

> 例えば、作成したDLLをEXCELとセットでカレントに格納されてれば動作するよう
> 環境でしょうか。
> そこで、検索中で、マクロからDLLをロードし、処理するサイトがありました。

この場合、技術的に別の内容ですので
質問は一度閉じられてまた別に立てられた方がよろしいかと思いますよ。

ちなみにdllだとstringに代表される配列の受け渡し問題がありますね
https://liclog.net/vba-dll-create-4/
あと32bit/64bitで違うとか
普段からWindows APIをVBAで使ってないと感覚がつかめないかもしれません。
あとC++だとできる事はVBAでもできたりしますから...C#で作るとか?

結局
> VBAから扱えるDLL
で何をしたいのかが問題になります。

VBAからWindows API呼べますので、大体やりたい事ってできます。
ややこしい事しないでもコマンドプロンプトで実行できるコンソールアプリを作って
引数与えて結果を文字列でもらうだけでも困んない場合もあります。
(なんせデバックが単体実行できるから楽)

Excel限定なら「excel アドイン」として開発するのも手です。
(Excel VBA、vb.net、C#で作成可能)

その辺りを書かれないともうちょっと具体的な回答はできないかな...


[ 親 103472 / □ Tree ] 返信 編集キー/

▲[ 103476 ] / 返信無し
■103478 / 5階層)  Re[5]: VBAから扱えるDLLの作成
□投稿者/ radian (162回)-(2024/12/13(Fri) 10:21:05)
今はNativeAOTを使用して、COMではないネイティブDLLも作成出来るようになりました。

https://kagasu.hatenablog.com/entry/2022/12/09/173354

UnmanagedCallersOnly属性を付与して関数をエクスポートすると、
-----
using System.Runtime.InteropServices;

namespace CsNativeDLL;

public class Exports
{
    [UnmanagedCallersOnly(EntryPoint = "ShowMessage")]
    public static void ShowMessage(IntPtr pMessage)
    {
        var msg = Marshal.PtrToStringUni(pMessage);
        MessageBox.Show(msg);
    }
}
-----

Excel側からはこのように呼び出せます。
-----
Private Declare PtrSafe Sub ShowMessage Lib "CsNativeDLL.dll" (ByVal pStr As LongPtr)


Private Sub CommandButton1_Click()
    Call ShowMessage(StrPtr("あいうえお"))
End Sub
-----

[ 親 103472 / □ Tree ] 返信 編集キー/


管理者用

- Child Tree -