CLR and VB.net dll

Started by stanl, November 10, 2013, 10:26:05 AM

Previous topic - Next topic

stanl

Just thought I'd throw this out. The attached Powershell script if run under Powershell will create a 7k dll with a method to CopyToClipboard(). Big Deal - WB can already do that.
I also know that even if WB couldn't do that the following WB code would fail with a DLL Entry error
Code (WINBATCH) Select

a0="Hello World"
dllname="C:\powershell\extension.dll"
a1=DllCall(dllname, lpstr:"CopyToClipboard", lpstr:a0)
Message(a0,a1)

The point being, is there a possibility that the WB CLR interface could execute the method?

stanl

I read you could use System.Reflection to call a dll method. May be overkill and the Clipboard method is trivial. But if possible it gives WB more leverage with .NET IMOH:

stanl

Here is my S.W.A.G. (and I attached the dll).
Code (Winbatch) Select

ModuleName = dirscript():"extension.dll";
TypeName = "Utility";
MethodName = "CopyToClipboard";
ObjectClrOption("use","System.Net, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b03f5f7f11d50a3a")
;oAssembly = ObjectClrNew( 'System.Reflection.Assembly' )
;oAssembly = oAssembly.Load( ModuleName )
oBase =  ObjectClrNew( 'System.Reflection.MethodBase' )
oMethod = ObjectClrNew( 'System.Reflection.MethodInfo' )
oModule = ObjectClrNew( 'System.Reflection.Module', ModuleName )
oMethod.GetType(TypeName)   ;fails here, but surprised I got that close
oMethod.GetMethod(MethodName)
oMethod.Invoke("Hello World")
oMethod=0
oAssembly=0
Exit

Deana

Stan,

So it appears you would like to call the CopyToClipboard method in this "extension" module. Is that correct? It appears the code is compiled as a Visual Basic DLL. I wonder if you could load it like any other assembly?

Here is what I tried:

Code (winbatch) Select
ObjectClrOption( "appbase", "c:\temp\" )
objUtility = ObjectClrNew("ClipboardAddon.Utility")
 

However that was unsuccessful.

I may need to defer to Tony's knowledge on this subject....
Deana F.
Technical Support
Wilson WindowWare Inc.

td

For starters the 'appbase' option cannot be used to specify a specific assembly.  It is used to specify the location of all non-GAC assemblies used by the application or script in this case. 

The dll as provided does not want to load on my system even when 'appbase' is used correctly because some assembly dependencies are missing.  This problem might (or might not) be corrected by taking PowerShell out of the equation.  WinBatch is perfectly capable of compiling properly written VB code into a dotNet assembly.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

Deana

Okay this seems to work for me. Give this a try Stan...:

Code (winbatch) Select
ModuleName = "c:\temp\extension.dll";
objectClrOption( 'use', 'System.Reflection, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a') 
oAssembly = ObjectClrNew( 'System.Reflection.Assembly' )
oAssembly = oAssembly.LoadFrom( ModuleName )

objUtility = ObjectClrNew("ClipboardAddon.Utility")
objUtility.CopyToClipboard("Hello World")
Exit
Deana F.
Technical Support
Wilson WindowWare Inc.

Deana

Here is the WinBatch code that can generate the extenstion.dll:

Code (winbatch) Select
;***************************************************************************
;**   Compile assembly library from VB source.
;**
;** Purpose:  Compile assembly from source.
;** Inputs:   VB source code
;** Outputs:  Compiled VB DLL
;** Reference:
;**       REQUIRES WinBatch 2013A or newer & File
;**       
;**
;** Developers: Deana Falk 2013.11.12
;***************************************************************************
If Version( )< '2013A'
   Pause('Notice', 'Need 2013A or Newer Version of WinBatch')
   Exit
EndIf

code = 'Imports Microsoft.VisualBasic':@lf
code = code: 'Imports System':@lf
code = code: 'Namespace ClipboardAddon':@lf
code = code: '  Public Class Utility':@lf
code = code: '    Private Declare Function OpenClipboard Lib "user32" (ByVal hwnd As Integer) As Integer':@lf
code = code: '    Private Declare Function EmptyClipboard Lib "user32" () As Integer':@lf
code = code: '    Private Declare Function CloseClipboard Lib "user32" () As Integer':@lf
code = code: '    Private Declare Function SetClipboardData Lib "user32"(ByVal wFormat As Integer, ByVal hMem As Integer) As Integer':@lf
code = code: '    Private Declare Function GlobalAlloc Lib "kernel32" (ByVal wFlags As Integer, ByVal dwBytes As Integer) As Integer':@lf
code = code: '    Private Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Integer) As Integer':@lf
code = code: '    Private Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Integer) As Integer':@lf
code = code: '    Private Declare Function lstrcpy Lib "kernel32" (ByVal lpString1 As Integer, ByVal lpString2 As String) As Integer':@lf
code = code: '':@lf
code = code: '    Public Shared Sub CopyToClipboard(ByVal text As String)':@lf
code = code: '      Dim result As Boolean = False':@lf
code = code: '      Dim mem As Integer = GlobalAlloc(&H42, text.Length + 1)':@lf
code = code: '      Dim lockedmem As Integer = GlobalLock(mem)':@lf
code = code: '      lstrcpy(lockedmem, text)':@lf
code = code: '      If GlobalUnlock(mem) = 0 Then':@lf
code = code: '        If OpenClipboard(0) Then':@lf
code = code: '          EmptyClipboard()':@lf
code = code: '          result = SetClipboardData(1, mem)':@lf
code = code: '          CloseClipboard()':@lf
code = code: '        End If':@lf
code = code: '      End If':@lf
code = code: '    End Sub':@lf
code = code: '  End Class':@lf
code = code: 'End Namespace'

;Add-Type -TypeDefinition $code -Language VisualBasic -OutputType Library -OutputAssembly c:\temp\extension.dll

If Version( )< '2013A'
   Pause('Notice', 'Need 2013A or Newer Version of WinBatch')
   Exit
EndIf


;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Load assemblies into the WinBatch process.
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; mscorlib assembly is automatically loaded by WinBatch when the CLR is loaded.
ObjectClrOption('use','System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Prompt for Input
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
assemblydll =  DirScript():'extension.dll'

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Create a class implemented by a managed assembly.
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
objVB = ObjectClrNew('Microsoft.VisualBasic.VBCodeProvider')
objParams = ObjectClrNew('System.CodeDom.Compiler.CompilerParameters')
;objParams.ReferencedAssemblies.Add( 'System.dll' )
objParams.OutputAssembly  = assemblydll
;objParams.CompilerOptions = '/optimize'
objResult = objVB.CompileAssemblyFromSource(objParams, BSTR:code)
;; Check for compiler errors.
If objResult.Errors.Count > 0
   ForEach ce In objResult.Errors
      Pause('Error', ce.ToString())
   Next
   Exit
EndIf

Exit


For complete example see:
http://techsupt.winbatch.com/webcgi/webbatch.exe?techsupt/tsleft.web+WinBatch/dotNet/System_CodeDom+Compile~Dll~from~VB~Source.txt
Deana F.
Technical Support
Wilson WindowWare Inc.

td

Quote from: Deana on November 12, 2013, 01:23:36 PM
Okay this seems to work for me. Give this a try Stan...:

Code (winbatch) Select
ModuleName = "c:\temp\extension.dll";
objectClrOption( 'use', 'System.Reflection, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a') 
oAssembly = ObjectClrNew( 'System.Reflection.Assembly' )
oAssembly = oAssembly.LoadFrom( ModuleName )

objUtility = ObjectClrNew("ClipboardAddon.Utility")
objUtility.CopyToClipboard("Hello World")
Exit


Actually all you need to do is
Code (winbatch) Select

ObjectClrOption( "appbase", "C:\Projects\DotNet\StansDll" )
ObjectClrOption("use", "extension")
objUtility = ObjectClrNew("ClipboardAddon.Utility")


I was getting an error because I left the .dll extension on "extension"...
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

stanl

Thank you both. Obviously my initial interpretation was a bit off from how WB can actually handle working with VB dll's (and create them). However, this (at least to me) opens up an incredible opportunity to [once again] leverage .net stuff into WB.

stanl

Everything works but one question. Deana's code called
objectClrOption( 'use', 'System.Reflection, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a')
oAssembly = ObjectClrNew( 'System.Reflection.Assembly' )
My laptop doesn't recognize this (Win 7 32 bit, updated .NET 4.5)
instead I use
ObjectClrOption("use","System.Net, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b03f5f7f11d50a3a")
oAssembly = ObjectClrNew( 'System.Reflection.Assembly' )

Just wondered why the difference?

P.S. and all worked with the original Powershell created dll, but happy to see WB can create as well.




stanl

One final observation. I compiled the script after adding a Message() to display what was in the clipboard. Worked on my laptop and a desktop I placed the EXE on. Tried it on my work laptop (it is PGP encrypted). It worked, but before the message() was displayed I got the attached pop-up - outside the WB error-handler. Is there a way to trap for it?

JTaylor

To make sure I understand....What does this do for us?   Allow us to load a DLL and then call any Methods from within it?  If so, what type of DLL's would work?

Apologies if the answer is obvious and I'm just being dense, as usual.

Jim

Deana

Quote from: stanl on November 13, 2013, 06:32:35 AM
One final observation. I compiled the script after adding a Message() to display what was in the clipboard. Worked on my laptop and a desktop I placed the EXE on. Tried it on my work laptop (it is PGP encrypted). It worked, but before the message() was displayed I got the attached pop-up - outside the WB error-handler. Is there a way to trap for it?

That seems to be a dotNet related error. I Googled the error message and found these threads:

http://answers.microsoft.com/en-us/windows/forum/windows_vista-windows_install/parser-error-0xc00ce556/c8a0a7cd-a5cc-46c3-9e76-96306143d36b
http://social.msdn.microsoft.com/Forums/en-US/ab6aff56-e42e-4da2-88d1-07311116b084/configuration-parser-error?forum=whatforum
Deana F.
Technical Support
Wilson WindowWare Inc.

Deana

Quote from: JTaylor on November 13, 2013, 06:52:08 AM
To make sure I understand....What does this do for us?   Allow us to load a DLL and then call any Methods from within it?  If so, what type of DLL's would work?

Apologies if the answer is obvious and I'm just being dense, as usual.

Jim

Basically yes. If you have a managed code assembly you can use WinBatch to access said assembly. In order to access using the CLR functions in WinBatch, it must be a "managed code assembly".

We have added three new functions give WinBatch scripts access to the Microsoft .Net Framework. WinBatch makes this possible by hosting the common language runtime (CLR) and exposing functionality for creating and accessing the members of classes, structures and enumerations of managed code assemblies (DLLs) that are part of or based on the Framework.

I found this blog that helps explain managed code assemblies: http://blogs.msdn.com/b/slessard/archive/2010/04/09/types-of-managed-code-assemblies.aspx
Deana F.
Technical Support
Wilson WindowWare Inc.

JTaylor

Aware of the new functions and have used them, with some help, but what is does this thread demonstrate that is different?   Just the use of a DLL whereas the other things I've seen and done just call the .NET stuff directly?

Jim

Deana

Quote from: JTaylor on November 13, 2013, 08:05:37 AM
Aware of the new functions and have used them, with some help, but what is does this thread demonstrate that is different?   Just the use of a DLL whereas the other things I've seen and done just call the .NET stuff directly?

Jim

It shows that you can not only create your own custom managed assembly, but it can also be called/accessed by WinBatch.
Deana F.
Technical Support
Wilson WindowWare Inc.

td

Quote from: stanl on November 13, 2013, 04:09:30 AM
Everything works but one question. Deana's code called
objectClrOption( 'use', 'System.Reflection, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a')
oAssembly = ObjectClrNew( 'System.Reflection.Assembly' )
My laptop doesn't recognize this (Win 7 32 bit, updated .NET 4.5)
instead I use
ObjectClrOption("use","System.Net, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b03f5f7f11d50a3a")
oAssembly = ObjectClrNew( 'System.Reflection.Assembly' )

Just wondered why the difference?

You apparently did see my response to Deana's post.  The only assembly you need to load is your 'extension' dll.  WinBatch will pick up any dependent assemblies that 'extension' needs.

Quote
P.S. and all worked with the original Powershell created dll, but happy to see WB can create as well.

Yes we know but the point is that there is no need to introduce another dependency  like Powershell into the equation. All you need is WinBatch and the FCL.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

td

Quote from: stanl on November 13, 2013, 04:09:30 AM
Everything works but one question. Deana's code called
objectClrOption( 'use', 'System.Reflection, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a')
oAssembly = ObjectClrNew( 'System.Reflection.Assembly' )
My laptop doesn't recognize this (Win 7 32 bit, updated .NET 4.5)
instead I use
ObjectClrOption("use","System.Net, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b03f5f7f11d50a3a")
oAssembly = ObjectClrNew( 'System.Reflection.Assembly' )

Just wondered why the difference?


Didn't directly answer your question in my previous post so... You don't need to load any assemblies to use the 'System.Reflection.Assembly'  class.  It is part of the mscorlib assembly which is automagically loaded when the CLR is loaded into a WinBatch process.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

JTaylor

Thanks.  Just wanted to make sure I understood.

Jim

stanl

Quote
You apparently did see my response to Deana's post.  The only assembly you need to load is your 'extension' dll.  WinBatch will pick up any dependent assemblies that 'extension' needs.

Not sure if you meant to write 'didn't see' rather than 'did see'. But I did see it and your code worked perfectly. My question was about why the particular line

objectClrOption( 'use', 'System.Reflection, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a')

cannot be used on my laptop, but apparently worked for Deana.

As for powershell. I used it because it was easily called from the command line. I assume the code Deana posted could be re-written as a generic load VB code from a Text file and with a couple parameters export a DLL.  Hard to call PS a dependency as it is more and more part of the OS.

moot points.  I will put your comments about appbase and the fact that reflection is loaded by default into a header file so that I don't forget the next time I venture into .NET la-la land....  :o

td

Quote from: stanl on November 13, 2013, 10:46:31 AM

Not sure if you meant to write 'didn't see' rather than 'did see'. But I did see it and your code worked perfectly. My question was about why the particular line

objectClrOption( 'use', 'System.Reflection, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a')

cannot be used on my laptop, but apparently worked for Deana.

I did mean 'didn't see' because the use of 'System.Reflection' is completely unnecessary in the case at hand.  However, after posting the response I realized that you may have been asking a question not directly related to the problem of loading your VB dotNet assembly. So I added the second post addressing the 'System.Reflection' issue by noting that you do not need a  'use' option with 'System.Reflection' because that namespace is part of the mscorlib assembly.

Quote
As for powershell. I used it because it was easily called from the command line. I assume the code Deana posted could be re-written as a generic load VB code from a Text file and with a couple parameters export a DLL.  Hard to call PS a dependency as it is more and more part of the OS.

It is still an additional dependency as far as I can tell.  There are more than a few XP machines out there that have dotNet but don't have PowserShell.  There are also more than a few newer machines build from corporate images that only have a limited subset of OS utilities and subsystems on board or available to standard users.  Avoiding dependencies is a concern that comes up often among our corporate WinBatch users.

Corporate users also have concerns about maintaining their scripts and programs.  Often when you add an additional tool to the mix you add the need for more knowledge and increase the chances of inadvertently breaking something.  So even if you know a tool is available, that fact doesn't necessarily negate the risks of adding that additional dependency.

There are certainly good reasons for adding dependencies but there are also good reasons to avoid doing so.
   
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

stanl

Without beating the dead horse on this thread your points well taken. Currently, I do nothing in WB that is work-related, so a lot of these threads are just personal learning experiences, but I trust members of the large WB community would look at this thread with a "Hey, didn't know you could do that" and the end result is more CLR threads.


td

Creating dotNet assemblies provides a quick and relatively easy way to extend WinBatch functionality, if you have a bit of fluency in one of the dotNet languages.  They allow you to create the rough equivalent of a WIL extender without having to master the WIL extender interface or C/C++.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

stanl

Quote from: td on November 14, 2013, 06:46:19 AM
Creating dotNet assemblies provides a quick and relatively easy way to extend WinBatch functionality, if you have a bit of fluency in one of the dotNet languages.  They allow you to create the rough equivalent of a WIL extender without having to master the WIL extender interface or C/C++.

Took the words out of my mouth.  I am looking into a SQL Server assembly.

kdmoyers

So, if I'm getting this right, When I want my .Net consultant to write me a bit of magic to do something, I can tell him to make a "managed code assembly" and that should result in something I can call from Winbatch, as long as it does not require "events" or "call backs".  Is that essentially correct?
(sorry if this is dumb -- really straining the limits of my understanding here)
-Kirby
The mind is everything; What you think, you become.

td

Quote from: kdmoyers on November 15, 2013, 05:29:31 AM
So, if I'm getting this right, When I want my .Net consultant to write me a bit of magic to do something, I can tell him to make a "managed code assembly" and that should result in something I can call from Winbatch, as long as it does not require "events" or "call backs".  Is that essentially correct?
(sorry if this is dumb -- really straining the limits of my understanding here)
-Kirby

I don't think you need to mention 'managed code assembly'.  If he is producing '.Net' (the MSFT marketing name for the MSFT implementation of the Common Language Infrastructure) assemblies, it will work given the two restriction you mentioned.  Note that a .Net based assembly can be in MicroSoft Intermediate Language (MSIL) assembled Bytecode or compiled into native code using MFST's ngen tool. It doesn't matter to WinBatch.

While dotNet seems to be new to many WinBatch users for some reason, it has been around for 13 years and is used in somewhere around  one-half of all Windows based software development projects.  There are many freely available assemblies and source code all over the web for solving all manor of problem.   The MSFT's CLI based language compilers are build into the Framework Class Library so you don't even need to buy anything to produce assemblies you write yourself.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

Deana

Quote from: kdmoyers on November 15, 2013, 05:29:31 AM
So, if I'm getting this right, When I want my .Net consultant to write me a bit of magic to do something, I can tell him to make a "managed code assembly" and that should result in something I can call from Winbatch, as long as it does not require "events" or "call backs".  Is that essentially correct?
(sorry if this is dumb -- really straining the limits of my understanding here)
-Kirby

Yes, you hit the proverbial nail on the head.

WinBatch supports access to the Microsoft .Net Framework. WinBatch makes this possible by hosting the common language runtime (CLR) and exposing functionality for creating and accessing the members of classes, structures and enumerations of managed code assemblies (DLLs) that are part of or based on the Framework.

You may want to give the consultant this list of limitations:

dotNet Limitations in WIL

While WinBatch CLR hosting has many advantages, it has limitations that should be considered before deciding whether or not to implement a solution using Framework based assemblies. The following is a partial listing of those limitations:

  • Delegates and event callbacks are not supported. (This limits the effectiveness of UI related classes.)
  • Generics can only be used when pre-instantiated with appropriate type parameters by another CLR object.
  • Remote access to an assembly running in another process is not supported.
  • WinBatch scripts cannot be compiled into CLR applications or assemblies.
  • Framework based object member names are case sensitive.
  • ObjectClrNew Limitations:


    • WinBatch relies on the CLR hosting's reflection functionality to instantiate classes.  There are a  few classes attributed to block instantiation via reflection
    • WinBatch does not support out parameters.  Method without parameters can still be called but out parameter values are not modified on the method's return.
    • Class member overloads that rely solely on the return type and name for their signature cannot be used.
    • Value types (structures) that only provide a multiple parameter constructor(s) cannot be used.
    • A small number of type member names conflict with WinBatch identifier naming rules and cannot be called directly.
    • Parameterize properties are not supported.
Deana F.
Technical Support
Wilson WindowWare Inc.

td

The only WinBatch dotNet limitations that are relevant to  a consultant creating an assembly are the lack of support for delegate (events) and uninstantiated  generics.  The former being the more important.

"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade