How to generate a Windows 10 desktop notification

Started by daz_1234, May 20, 2021, 04:21:00 AM

Previous topic - Next topic

daz_1234

Hi all, first time poster, long time Winbatch user but probably not much past novice ...

Is it possible to generate standard Windows 10 desktop notifications in Winbatch? (sometimes called 'toaster' notification). And even better, can we create an action to run when the notification is clicked?

similar to say Outlook notification and when clicked it opens the email.

(I have unsuccessfully already tried to search this forum and the online db)

Many thanks,
Darren.

td

There is no means that I am aware of to create notifications in a WinBatch script. 

[edit] That said there is some possibility that you could do something in a script that would cause another application to produce a notification.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

JTaylor

No idea if you can do something in C# that would work in WinBatch or not but assuming this is what you mean...

           https://docs.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/send-local-toast?tabs=uwp

Here is a place to check.

Jim

td

or you could make a WinBatch script a system tray app and have it pop up a window based on a trigger. It would be more or less faking a notification...

https://docs.winbatch.com/mergedProjects/WindowsInterfaceLanguage/html/WILAK_I__085.htm

Not sure that the .Net approach will work because it likely requires something called a delegate underneath the hood and the CLR does not permit using delegates in WinBatch scripts. That means it would require some investigation just to figure out if it is even possible.

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

daz_1234


ChuckC

I took some time to read thru the "Send local toast notification from C# apps" article referred to in a previous message, and it does look like it should work OK from WinBatch using CLR hosting.  There don't appear to be any delegates required.  The documentation indicates that .NET Framework desktop apps are supported, so that also meets the requirements for use with CLR hosting.  The only caveat, if you will, is that a specific NuGet package is required to provide the support class that actually does the low-level work of sending the notification.

td

Delegates are not necessarily presented to the would-be user of a framework or API. They can be hidden behind the facade. Anything named "OnActivated" raised the possibility of a hidden delegate. Not saying that it will not work but given how the underlying native code API is put together, it is a possibility.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

ChuckC

Understood.

What I read about how the gadget that receives the "toast" notifications is that if it has to communicate back to the application that sent the notification, it either sends a window activate message via normal desktop window messaging or it can even launch the source application with a command line parameter used to convey context information back to the application so that it understands why it was launched.  It seems to allow for a great degree of decoupling between the sources of toast notifications the gadget that displays & manages them, with all toast notifications ultimately being nothing more than an XML payload that gets communicated.  The NuGet package that is required is for a library that provides data objects to C# & C++ client code such that the data object can be configured via method calls and setting properties, after which they are rendered into XML and dispatched.

td

If a user presents a working script using dotNet and WIL CLR hosting, great! But until then I will remain skeptical.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

ChuckC

As of this afternoon, after quite a bit of monkeying around with extracting some assemblies from some NuGet packages, I have it working under both PowerShell v7.1.3 w/.NET Core 5.x and Windows PowerShell [ISE].

I'll convert it to WIL code and get it posted in the near future.

There is a dependency on retrieving a NuGet package and then manually extracting a specific assembly DLL file from it.  Given that there's no guarantee that a WinBatch script developer will have Visual Studio handy do the dirty work, I'll include some instructions on what is needed to get the necessary assembly DLL file out of the package.

td

I hope you don't need to use .Net Core and can use the FCL instead because you can't use .Net core with WIL CLR hosting. Otherwise, you would have to launch a PS script from WIL CLR hosting or whatever.  That said, it would be a great addition to the Tech. Database.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

ChuckC

The assembly in question has builds for .NET Framework, .NET Standard and .NET Core.

Some of the functions on the TestContentBuilder class turn out to have a number of optional parameters implemented as nullable types along the lines of "bool? hintWrap", which induces aggravation in WIL's CLR support.


Invoking the Toast functionality via PowerShell is feasible and may be the most expedient way of doing so.

The NuGet package that is required is as follows:

https://www.nuget.org/packages/Microsoft.Toolkit.Uwp.Notifications/

Choose the "Download package" link and save the file "microsoft.toolkit.uwp.notifications.7.0.2.nupkg" to a convenient local location.

Rename the ".nupkg" extension to ".zip" and then drill down into it and extract "lib\net461\Microsoft.Toolkit.Uwp.Notifications.dll".  Be sure to clear the zone identifier that flags it as having come from an untrusted network location, as failing to do so will result in the assembly failing to load.  Ideally, put the assembly in the same location as the WinBatch script and, optionally, the .ps1 file that are going to make use of it.


Here's the PowerShell code:

#  TestToast-01.ps1

if (-not ("Microsoft.Toolkit.Uwp.Notifications.ToastContentBuilder" -as [Type]))
{
    if ($PSEdition -eq "Core")
    {
        #  For PowerShell Core v6.x & PowerShell v7+

        Add-Type -Path $(Join-Path $env:USERPROFILE "Documents\AppDevProjects\NuGet\microsoft.windows.sdk.net.ref.10.0.19041.17\lib\Microsoft.Windows.SDK.NET.dll")

        Add-Type -Path $(Join-Path $env:USERPROFILE "Documents\AppDevProjects\NuGet\microsoft.windows.sdk.net.ref.10.0.19041.17\lib\WinRT.Runtime.dll")
   
        Add-Type -Path $(Join-Path $env:USERPROFILE "Documents\AppDevProjects\NuGet\Microsoft.Toolkit.Uwp.Notifications\lib\net5.0-windows10.0.17763\Microsoft.Toolkit.Uwp.Notifications.dll")
    }
    else
    {
        #  For Windows PowerShell and Windows PowerShell_ISE

        Add-Type -Path $(Join-Path $env:USERPROFILE "Documents\AppDevProjects\NuGet\Microsoft.Toolkit.Uwp.Notifications\lib\net461\Microsoft.Toolkit.Uwp.Notifications.dll")
    }
}


$toast = [Microsoft.Toolkit.Uwp.Notifications.ToastContentBuilder]::new()

#  This can be considered to the the "title" text on line #1.
#  A minimum of 1 line of text is required when preparing a
#  Toast Notification.

$toast.AddText("<Text Element #1>")

#  The remaining 2nd & 3rd text lines are optional.

$toast.AddText("<Text Element #2>")

$toast.AddText("<Text Element #3>")

#  The attribution text is optional.

$toast.AddAttributionText("<Attribution Text>")


#  Make the notification appear on the desktop.

$toast.Show()


Please note that the Add-Type command needs to be altered to refer to the correction location for the assembly.


td

Usually, method not found problems can be fixed by creating a full method signature but not luck this time. Just produces an "Invalid parameter" error.  Maybe someone else can see something I missed.

Code (winbatch) Select
;; Add types to parameters as necessary to assist in building the method's signature
;; Since WIL CLR hosting does not support named parameters.
hintStyle = ObjectClrType('Microsoft.Toolkit.Uwp.Notifications.AdaptiveTextStyle',0)
hintWrap = ObjectClrType('System.Boolean', 0)
hintMaxLines = 2
hintMinLines = 1
hintAlign = ObjectClrType('Microsoft.Toolkit.Uwp.Notifications.AdaptiveTextAlign',0)
language = "en-US"

objToast.AddText("<Text Element #1>", hintStyle, hintWrap, hintMaxLines, hintMinLines, hintAlign, language)
;objToast.AddText("<Text Element #2>", hintStyle, hintWrap, hintMaxLines, hintMinLines, hintAlign, language)
;objToast.AddAttributionText("<Attribution Text>", hintStyle, hintMaxLines, hintMinLines, hintAlign, language)

objToast.Show()

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

ChuckC

You have almost exactly the same WIL code that I had written in my attempt to port the logic from PowerShell to WIL.

If you look at the docs for the TestContentBuilder's AddText() instance method, you'll quickly see the crux of the problem:

https://docs.microsoft.com/en-us/dotnet/api/microsoft.toolkit.uwp.notifications.toastcontentbuilder.addtext?view=win-comm-toolkit-dotnet-7.0

public Microsoft.Toolkit.Uwp.Notifications.ToastContentBuilder AddText (string text, Microsoft.Toolkit.Uwp.Notifications.AdaptiveTextStyle? hintStyle = default, bool? hintWrap = default, int? hintMaxLines = default, int? hintMinLines = default, Microsoft.Toolkit.Uwp.Notifications.AdaptiveTextAlign? hintAlign = default, string language = default);

There are optional nullable parameters in the signature.  Sometimes, those will even give PowerShell fits and seizures, but that wasn't the case this time.  It's just WIL's CLR support that's pitching a fit over it.

In WIL, how does one pass an untyped null the parameter for a formal argument that is of a nullable type?

I think we had an earlier discussion a few months back regarding WIL having issues with generic types, to the Nullable<T> type is out of the question to work around "bool? hintWrap = default" by passing null cast to Nullable<bool>.

Even reflection seemed outside the reach of WIL in this case.  I've had a number of times that I needed to invoke a class method, instance or static, that was scoped internal or private, and that is easy to do in C# with just a few lines of code.  However, even reflection requires being able identify the types of each of the formal arguments in the signature if attempting to get a specific method overload when there are numerous overloads with similar signatures.  Then again, perhaps one of the alternative reflection methods that returns an IEnumerable<> of method information instances would serve better in this case since it would return a container with only a single item in it.  I may do some more dinking around with that to see if I can obtain method information, and if I can, then invoking the method becomes trivial if I can get WIL to produce proper null values to use when calling the method via its method information.  The other thing that is needed is to determine what the WIL CLR equivalent is of C#'s "typeof(some-class-or-struct-type)".



td

I had viewed the documentation before I posted the test example. Neither "nullable" nor "optional" parameters should give WIL CLR issues by themselves since they have regular values in the example above. The CLR is successfully finding the correct method based on the passed parameters. This fact is known based on the error message generated and by viewing the call in the "native" debugger.  Uninstantiated template classes will cause issues. However, it appears to be a CLR internal implementation contradiction to have the CLR find the method using the specified types but not accept the very same types in the actual method call.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

stanl

I take it the CLR cannot work with the Windows.UI.Notifications / Windows.UI.Notifications.ToastNotificationManager class/methods.

ChuckC

Tony would have to weigh in on the issue in terms of whether or not any modifications to WinBatch/WIL are required to make it possible for the class method in question to be accessible from a script.

In the mean time, there are 2 work-arounds:

1)  Use a WinBatch script to provide the notification content and then have it utilize a captive PowerShell instance to actually send the notification.  PowerShell can be instructed to simply invoke an external .ps1 file wile passing parameters to it, or PowerShell can have statements injected into it to send the notification without making use of an external .ps1 file.

2)  Use a WinBatch script with utilizes the CLR to dynamically compile some C# code into an in-memory assembly which can then be used to send the notification.


td

The only way to "fix" support for this particular set of classes would be to first eliminate WinBatch support for older versions of Windows and for most non-current versions of dotNet.  Then we could completely rewrite the CLR hosting implementation. And no it is not possible to support the current implementation and a new one in a single DLL/executable. Basically, it would require splitting the WIL interpreter into two DLLs and that is not something we are willing to do at this time.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

ChuckC

Got it working.  Dynamically creating an in-memory assembly and then using reflection to call into a static method did the trick.

Make sure that the "net461" targeted "Microsoft.Toolkit.Uwp.Notifications.dll" file is in the same directory as the script.


; TestToast-01.wbt

ObjectClrOption('appbase', DirScript())


ObjectClrOption('useany', 'System')

ObjectClrOption('useany', 'System.Collections')

ObjectClrOption('useany', 'System.Reflection')


oCSharp = ObjectClrNew('Microsoft.CSharp.CSharpCodeProvider')

oParams = ObjectClrNew('System.CodeDom.Compiler.CompilerParameters')

oParams.ReferencedAssemblies.Add( "system.dll" )

oParams.ReferencedAssemblies.Add( "system.collections.dll" )

oParams.ReferencedAssemblies.Add( "system.core.dll" )

oParams.ReferencedAssemblies.Add( "system.runtime.dll" )

oParams.ReferencedAssemblies.Add( "mscorlib.dll" )

oParams.ReferencedAssemblies.Add( "Microsoft.Toolkit.Uwp.Notifications.dll" )


sCode = ''

sCode = sCode : 'using System;' : @CRLF

sCode = sCode : 'using System.Collections;' : @CRLF

sCode = sCode : 'using System.Collections.Generic;' : @CRLF

sCode = sCode : 'using System.Linq;' : @CRLF

sCode = sCode : 'using Microsoft.Toolkit.Uwp.Notifications;' : @CRLF

sCode = sCode : '' : @CRLF

sCode = sCode : 'namespace wb.toast' : @CRLF

sCode = sCode : '{' : @CRLF

sCode = sCode : '  public static class WBToast' : @CRLF

sCode = sCode : '  {' : @CRLF

sCode = sCode : '    public static void SendToastNotification(string TextLine1In, string TextLine2In, string TextLine3In, string AttributionTextIn)' : @CRLF

sCode = sCode : '    {' : @CRLF

sCode = sCode : '        var toast = new ToastContentBuilder();' : @CRLF

sCode = sCode : '' : @CRLF

sCode = sCode : '        if (TextLine1In != null) toast.AddText(TextLine1In);' : @CRLF

sCode = sCode : '' : @CRLF


sCode = sCode : '        if (TextLine2In != null) toast.AddText(TextLine2In);' : @CRLF

sCode = sCode : '' : @CRLF

sCode = sCode : '        if (TextLine3In != null) toast.AddText(TextLine3In);' : @CRLF

sCode = sCode : '' : @CRLF

sCode = sCode : '        if (AttributionTextIn != null) toast.AddAttributionText(AttributionTextIn);' : @CRLF

sCode = sCode : '' : @CRLF

sCode = sCode : '        toast.Show();' : @CRLF

sCode = sCode : '' : @CRLF

sCode = sCode : '    }' : @CRLF

sCode = sCode : '  }' : @CRLF

sCode = sCode : '}' : @CRLF

sCode = sCode : '' : @CRLF


aSource[0] = sCode


oCR = oCSharp.CompileAssemblyFromSource(oParams, BSTR:aSource)

;  Check for compiler errors.

if oCR.Errors.Count > 0

  foreach error In oCR.Errors
    Pause("Error", error.ToString())
  next

  exit

endif


args[0] = '<Text Element #1>'

args[1] = '<Text Element #2>'

args[2] = '<Text Element #3>'

args[3] = '<Attribution Text>'


modules = oCR.CompiledAssembly.GetModules()

method = modules[0].GetType("wb.toast.WBToast").GetMethod("SendToastNotification")

method.Invoke(0, args)


exit

JTaylor


td

The c# compiler option is always an option to work around the limitations of WIL CLR hosting. It has been documented several times on this forum and in the Tech Database.  The reason I don't mention it is because most users have no interest in it. I can only speculate about why that is...

[edit] Here is but one example:

https://techsupt.winbatch.com/webcgi/webbatch.exe?techsupt/nftechsupt.web+WinBatch/dotNet/System_Drawing+Use~System.Drawing~for~Steganograhpy.txt
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

JTaylor

Yep.  I have found it extremely useful over the years.

Jim

JTaylor

Here is a variation on Chuck's fine work that some may find useful...

Code (winbatch) Select



#DefineFunction Loadem_Toastem()

  ObjectClrOption('appbase', DirScript())
  ObjectClrOption('useany', 'System')
  ObjectClrOption('useany', 'System.Collections')
  ObjectClrOption('useany', 'System.Reflection')
 
  oCSharp = ObjectClrNew('Microsoft.CSharp.CSharpCodeProvider')
  oParams = ObjectClrNew('System.CodeDom.Compiler.CompilerParameters')
  oParams.ReferencedAssemblies.Add( "system.dll" )
  oParams.ReferencedAssemblies.Add( "system.collections.dll" )
  oParams.ReferencedAssemblies.Add( "system.core.dll" )
  oParams.ReferencedAssemblies.Add( "system.runtime.dll" )
  oParams.ReferencedAssemblies.Add( "mscorlib.dll" )
  oParams.ReferencedAssemblies.Add( "Microsoft.Toolkit.Uwp.Notifications.dll" )
  oParams.GenerateInMemory = ObjectType( "VT_BOOL", 1 ) ;TRUE
 
  sCode = $"using System;
            using System.Collections;
            using System.Collections.Generic;
            using System.Linq;
            using Microsoft.Toolkit.Uwp.Notifications;
   
            namespace wb_toast {
               public static class WBToast {
                 public static void STN(string TextLine1In, string TextLine2In, string TextLine3In, string AttributionTextIn) {
                    var toast = new ToastContentBuilder();
                    if (TextLine1In != null) toast.AddText(TextLine1In);
                    if (TextLine2In != null) toast.AddText(TextLine2In);
                    if (TextLine3In != null) toast.AddText(TextLine3In);
                    if (AttributionTextIn != null) toast.AddAttributionText(AttributionTextIn);
                    toast.Show();
                 }
              }
            }
         $"

  aSource[0] = sCode
 
  oCR = oCSharp.CompileAssemblyFromSource(oParams, BSTR:aSource)
 
  ;  Check for compiler errors.
  If oCR.Errors.Count > 0
    Foreach error In oCR.Errors
      Pause("Error", error.ToString())
    Next
    Return 0
  EndIf
 
  Return 1

#EndFunction

 
Loadem_Toastem()
tcall = ObjectClrNew( 'wb_toast.WBToast' )



  arg0 = "arg0"
  arg1 = "arg1"
  arg2 = "arg2"
  arg3 = "arg3"
 
  resp  = tcall.STN(arg0,arg1,arg2,arg3)

  arg0 = "g0"
  arg1 = "g1"
  arg2 = "g2"
  arg3 = "g3"
 
  resp  = tcall.STN(arg0,arg1,arg2,arg3)


ChuckC

run with it...

at least now we know that we have toast.  of course, i'm not sure if it's sour dough, some sort of crostini or if it's actually champagne or scotch...

if it is some sort of bread, i expect that the next question will be whether it's buttered, or not, and is, on which side?


JTaylor


ChuckC

There is more to to the Toast notifications than just a couple of lines of text.   When looking over the examples showing various way of using them, there are options to include pictures, web links, buttons and other data that allows acknowledgement of the notification to result in communicating back to the originating application with a windows message or by launching a program and passing command line parameters to it.

If I get some time to play around with it, I'll see how feasible those are to wrap up for use in WinBatch.  It may well be something that works best as a UDF library that includes a .CS source code file with a "toast" wrapper class in it that provides multiple static class methods that encapsulate the more complex toast-related class methods with easy to use "send toast notification type XYZ" methods.


oh, and when it coms to which side the toast is buttered on, don't forget that you can butter the crust on the sides... or, per one of the orphans in "The Matrix", the 1st thing to know that there is no toast...

JTaylor

Not sure if this is the best method, and it is a work-in-progress, but thought maybe we could all come up with a useful set of Methods for Toasts.   Happy for names to change or for a completely different approach.

I broke out many of the options for Toasts into their own Methods.  Hopefully everything is, reasonably, self-explanatory.

Things I haven't figured out yet and/or haven't gotten to yet.   

        How to make use of the Buttons.   Tells me Specified Batch File Not Found.   Not sure if that can only be specified in XML and if so, how to make use of XML in script.
        Audio.   Nothing seemed to work.  Didn't get errors.  Just no sound.

Note:  You will need to change image path.

Jim


Code (winbatch) Select



#DefineFunction Load_Toaster()

  ObjectClrOption('appbase', DirScript())
  ObjectClrOption('useany', 'System')
  ObjectClrOption('useany', 'System.Collections')
  ObjectClrOption('useany', 'System.Reflection')
 
  oCSharp = ObjectClrNew('Microsoft.CSharp.CSharpCodeProvider')
  oParams = ObjectClrNew('System.CodeDom.Compiler.CompilerParameters')
  oParams.ReferencedAssemblies.Add( "system.dll" )
  oParams.ReferencedAssemblies.Add( "system.collections.dll" )
  oParams.ReferencedAssemblies.Add( "system.core.dll" )
  oParams.ReferencedAssemblies.Add( "system.runtime.dll" )
  oParams.ReferencedAssemblies.Add( "mscorlib.dll" )
  oParams.ReferencedAssemblies.Add( "Microsoft.Toolkit.Uwp.Notifications.dll" )
  oParams.GenerateInMemory = ObjectType( "VT_BOOL", 1 ) ;TRUE
 
  sCode = $"using System;
            using System.Collections;
            using System.Collections.Generic;
            using System.Linq;
            using Microsoft.Toolkit.Uwp.Notifications;

            namespace WBToast {
               public static class Toaster {

                 public static void STN(string TextLine1In, string TextLine2In, string TextLine3In, string AttributionTextIn) {
                    var toast = new ToastContentBuilder();
                    if (TextLine1In != "") toast.AddText(TextLine1In);
                    if (TextLine2In != "") toast.AddText(TextLine2In);
                    if (TextLine3In != "") toast.AddText(TextLine3In);
                    if (AttributionTextIn != "") toast.AddAttributionText(AttributionTextIn);
                    toast.Show();
                 }


                 public static ToastContentBuilder Toast()
                 {
                     var toast = new ToastContentBuilder();
                     return toast;
                 }
         

                 public static void Popup(ToastContentBuilder toast)
                 {
                     toast.Show();
                 }
         

                 public static void AddText(ToastContentBuilder toast, string TextLine)
                 {
                     toast.AddText(TextLine);
                 }
         
         
                 public static void AddAttributionText(ToastContentBuilder toast, string AttributionTextIn)
                 {
                     if (AttributionTextIn != "") toast.AddAttributionText(AttributionTextIn);
                 }
         

                 public static void AddImage(ToastContentBuilder toast, string ImageURL)
                 {
         
                     if (ImageURL != "") toast.AddInlineImage(new Uri(ImageURL));
                 }
         
         
                 public static void AddAppLogo(ToastContentBuilder toast, string ImageURL, string lstyle = "circle")
                 {
                     if (lstyle == "circle")
                       toast.AddAppLogoOverride(new Uri(ImageURL), ToastGenericAppLogoCrop.Circle);
                     else
                       toast.AddAppLogoOverride(new Uri(ImageURL));
                 }
         
         
         
                 public static void AddArgument(ToastContentBuilder toast, string ArgName, string ArgValue)
                 {
                     if (ArgName != "") toast.AddArgument(ArgName, ArgValue);
                 }
         
         
                 public static void AddArgument(ToastContentBuilder toast, string ArgName, int ArgValue)
                 {
                     if (ArgName != "") toast.AddArgument(ArgName, ArgValue);
                 }
         
         
                 public static void AddButton(ToastContentBuilder toast, string BText, string BArgName, string BArgValue)
                 {
             
                    toast.AddButton(new ToastButton() 
                         .SetContent(BText)
                         .AddArgument(BArgName, BArgValue)
                         .SetBackgroundActivation() );
                 }
         
         
                 public static void TextBox(ToastContentBuilder toast, string ReplyVar, string PlaceHolder)
                 {
                     toast.AddInputTextBox(ReplyVar, placeHolderContent:: PlaceHolder);
                 }
         




              }  //End Class
            }    // End Namespace
         $"

  aSource[0] = sCode
 
  oCR = oCSharp.CompileAssemblyFromSource(oParams, BSTR:aSource)
 
  ;  Check for compiler errors.
  If oCR.Errors.Count > 0
    Foreach error In oCR.Errors
      Pause("Error", error.ToString())
    Next
    Return 0
  EndIf
 
  Return 1

#EndFunction

 
Load_Toaster()



tcall = ObjectClrNew( 'WBToast.Toaster' )

toast = tcall.Toast;

tcall.AddText(toast, "Jim")

tcall.AddImage(toast, "C:\gbat\wb_test\Toasts\coffee.jpg")
tcall.AddAppLogo(toast, "C:\gbat\wb_test\Toasts\coffee.jpg","circle")
tcall.AddArgument(toast, "ID",123)
tcall.AddButton(toast, "Reply","action","reply")
tcall.AddButton(toast, "View","action","view")
tcall.TextBox(toast, "reply_var","Type a Reply")

tcall.Popup(toast)


;Below is the original single call for a simple Text Toast.

  arg0 = "arg0"
  arg1 = "arg1"
  arg2 = "arg2"
  arg3 = "arg3"
 
; resp  = tcall.STN(arg0,arg1,arg2,arg3)




stanl


ChuckC

nice touch with the verbatim string to clean up the concatenation i was using.

after looking thru the online WIL consolidated help, locally installed consolidated help, the tech support database and the FAQ, i saw zero references to verbatim string support.

i'd hazard to guess the introduction of the feature was in the release notes for a specific version of WinBatch, but i also didn't see a comprehensive cumulative release notes anywhere on the site.

what version of WinBatch introduced verbatim strings and is there a cumulative collection of the release notes for all WinBatch versions somewhere on the site?

JTaylor

Search for "String" in the Index and then Choose "Constants".   Always takes me a bit to find it, even knowing it is there.

Jim

stanl


td

Actually, the "hint" came from a background in Unix scripting and a user named snowsnowsnow. Both of which have been around a lot longer than PS. The documentation can be found here:

https://docs.winbatch.com/mergedProjects/WindowsInterfaceLanguage/html/HTMLWIL_SC_001.htm

and in the release notes here:

https://www.winbatch.com/winbatchversions.html#WB2016B


Admittedly, it doesn't show up in any indices. However, each WinBatch installation includes a file called "The list of fixes and improvements.txt". It can be searched with your favorite text editor. You can also search the on-line release notes by selecting the lastest release from the WinBatch Versions page and using your browser's page search functionality. For example, in Firefox navigate to the release notes by selecting Whats's New from the WinBatch Home page, select the current latest version, use the cntl+f key combination, and then type "Multiline text" sans quotes.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

td

A Wikipedia article that describes the "Here Document" which is the inspiration for WIL "Multiline text" as used in several Unix shells and other language environments.

https://en.wikipedia.org/wiki/Here_document
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

stanl

I was joking about the PS comment as I figured it would get you to comment. But on the topic of C# compilation. Jim's code could be compiled into a physical .dll, if read as a .cs file. Maybe an abstract or pointless ask: but if possible could the .dll be wrapped into a WB Service that could be accessed by any number of WB scripts?

JTaylor

Not sure what you mean by a WB Service but could easily make it a COM accessible DLL.    If having a separate file is acceptable it would probably be easier to Encode it for Calls from Exes....although that might not accomplish what you are asking.  In any event, I have found the Encoding options extremely useful when I want data available but reasonably secure.

Jim