Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Garuda/Eagle in starpack

34 views
Skip to first unread message

Yusuke Yamasaki

unread,
Sep 13, 2021, 4:20:53 AM9/13/21
to
Is it possible for a starpack-wrapped Tcl/Tk application to use external
.NET assemblies using Garuda? I use the latest build (1.0.7900.33333,
2021-08-23).

My Tcl/Tk application is wrapped into a starpack with ActiveState
TclApp. I wanted to check if Garuda can work with my app.

Ideally, I want to embed Eagle.dll and Garuda.dll into my starpack but
at first, I just installed Eagle/Garuda binaries to the lib folder under
the working directory and inserted the path to the head of ::auto_path.

The purpose to use Garuda is to load an external managed assembly from
the local sub-folder. The assembly is dependent on several DLLs in the
same folder. I keep them out of my starpack.

+ lib\
+ Garuda-1.0\
+ dotnet.tcl
+ Eagle.dll
+ Garuda.dll
+ helper.tcl
+ pkgIndex.tcl
+ RemoteClient\
+ Google.Protobuf.dll
+ Grpc.Core.Api.dll
+ Grpc.Core.dll
+ grcp_csharp_ext.x86.dll
+ GRPCRemoteClient.dll (This is the DLL to be loaded from MyApp.tcl)
+ System.Buffers.dll
+ System.Memory.dll
+ System.Numerics.Vectors.dll
+ System.Runtime.CompilerServices.Unsafe.dll
+ MyApp.tcl

MyApp.tcl is the main script. It loads Garuda.
The eagle command loads RemoteClient\GRPCRemoteClient.dll and the
classes and the methods are used.

If MyApp.tcl is not wrapped into a starkit, it works well.
However, if it is wrapped, it can't create any instance of classes
defined inside GRPCRemoteClient.dll, although it seemed to load
GRPCRemoteClient.dll successfully.

I followed the instruction in this article and added
METHOD_PROTOCOL_V1R2 flag before loading Garuda package.

https://wiki.tcl-lang.org/page/Garuda.

# MyApp.tcl

set exehome [pwd]

set auto_path [linsert $auto_path 0 [file join $::exehome lib]]

namespace eval ::Garuda {
variable methodFlags 0x40; # METHOD_PROTOCOL_V1R2
}
package require Garuda
eagle {
set dll_dir "./GRPCRemoteClient"
set dll_file "GRPCRemoteClient.dll"
set dll_path [file join $dll_dir $dll_file]
object invoke System.Reflection.Assembly LoadFrom $dll_path
}
# => {GRPCRemoteClient, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null} c199bf34-6a72-4256-8e1c-5857959232ad 293
# => Seemed successful.

eagle {
object create -alias GRPCRemote.GRPCRemoteClient "127.0.0.1" 50051
}
# => {type "GRPCRemote.GRPCRemoteClient" not found} {expected type value
but got "GRPCRemote.GRPCRemoteClient"}
# => Failed.


Yusuke Yamasaki <tm92...@gmail.com>

Harald Oehlmann

unread,
Sep 13, 2021, 4:41:22 AM9/13/21
to
Dear Yusuke,

thank you for the question. Your work looks great. I have never used
Garunda but have implemented .net DLL's using C++ code in a DLL witten
by me and called by TCL.

I can only report from my personal experiences about DLL's loading other
DLL's. It does not make any difference, if it is a .net dll or a C dll.
The observed mechansim is the same.

When a dll is packed into a starpack, its invocation happens like that:
- copy the dll to the tmp folder (with a funny tmp name)
- load it with the load command and the foll path.

That works well, but if the dll loads other dll's, they are often not
found, as the dll location should be beside the calling dll or beside
the executable (or in the system folders). I did not find any way to
control this mechanism from the C side. I had no control over the .net
library.

So, I found two solutions which are not beautiful:
- put the TCL DLL in the starkit but the depenedent DLL's beside the
executable.
- put the TCL DLL in a subfolder (I use lib) and put all dependent DLL's
in the same folder.

Sorry, only my two pennies,
Harald

Harald Oehlmann

unread,
Sep 13, 2021, 4:52:30 AM9/13/21
to
I have to add, that you may unpack all DLL's and depending DLL's from
the starpack. You may also look to my post on the Wiki on cleaning-up
the temporary DLL's, as a new copy is created on each start-up.

Take care,
Harald

Yusuke Yamasaki

unread,
Sep 13, 2021, 8:01:56 AM9/13/21
to
Dear Harald,

Thank you for your response.

Actually, MyApp.exe (not MyApp.tcl, sorry for my typo.) is a wrapped
Tcl/Tk application. And it doesn't wrap Garuda and managed DLLs because
I knew that DLLs except for the ones built as Tcl extensions normally
can't be loaded from temporary folders as you pointed out. They are in
normal folders under the working folder (./RemoteClient/*).

I also use native DLLs written in C++ with C-style export functions and
I load it from the working directory using Ffidl not from starpack's
temporary folders and it works well. Although it is not beautiful, I
decided to follow the same way because the important point for me is to
make it work somehow. However, it didn't work... That's why I posted
this question here.

I think your's is so called a mixed-mode assembly written in C++/CLI.
So I guess the interface is a C-style export function isn't it?
The difference I can think of is the the interface whether it is loaded
by Garuda or by a foreign function call library.

+ lib\
+ Garuda-1.0\
+ dotnet.tcl
+ Eagle.dll
+ Garuda.dll
+ helper.tcl
+ pkgIndex.tcl
+ RemoteClient\
+ Google.Protobuf.dll
+ Grpc.Core.Api.dll
+ Grpc.Core.dll
+ grcp_csharp_ext.x86.dll
+ GRPCRemoteClient.dll (This is the DLL to be loaded from MyApp.tcl)
+ System.Buffers.dll
+ System.Memory.dll
+ System.Numerics.Vectors.dll
+ System.Runtime.CompilerServices.Unsafe.dll
+ MyApp.exe

Regards,
Yusuke

Harald Oehlmann

unread,
Sep 13, 2021, 8:33:44 AM9/13/21
to
Dear Yusuke,

what you write sounds completly reasonable. I suppose, I can not help
you any further.
Take care,
Harald

Yusuke Yamasaki

unread,
Sep 13, 2021, 11:08:51 AM9/13/21
to
Dear Harald,

I found that Eagle has a public forum. I will ask this question there.
Anyway, thank you for your comments.

Regards,
Yusuke


On 2021/09/13 21:33, Harald Oehlmann wrote:
> Dear Yusuke,
>
0 new messages