Custom browser protocol to open IE with params - windows

I need to implement something similar to this answer
https://stackoverflow.com/a/41749105/1004374
but I have several issues.
I changed it slightly so be able to pass arguments into the url:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>openie</title>
</head>
<body>
<h1>Hello world!</h1>
Google1
Google2
</body>
</html>
and changed reg script:
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Classes\openie]
"URL Protocol"="\"\""
#="\"URL:OPENIE Protocol\""
[HKEY_CURRENT_USER\Software\Classes\openie\DefaultIcon]
#="\"explorer.exe,1\""
[HKEY_CURRENT_USER\Software\Classes\openie\shell]
[HKEY_CURRENT_USER\Software\Classes\openie\shell\open]
[HKEY_CURRENT_USER\Software\Classes\openie\shell\open\command]
#="cmd /k set myvar= & call set myvar=\"%1\" & call set myvar=%%myvar:openie:=%% & call \"C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe\" %%myvar%% & exit /B"
The only update is shielding of %1 argument:
myvar=\"%1\
This is needed to pass arguments with &. Otherwise will be copied url until first ampersand:
openie:https://www.google.com/?word=abc&word2=abc2
All is fine when you click the link first time. When IE is already opened url is copied incorrectly with encoded quotes inside it and automatically added http in the begining:
http://%22https//www.google.com/?word=abc&word2=abc2"
I realize that issue with cmd script inside but cannot guess what should be changed to be able to pass arguments and click links many times.

Not found a good way to modify the script to accept the '&'. but as a workaround, I suggest you could encode the url, and change the '&' to '%26', the link as below:
Google2
Then, in the destination page, you could decode the url and change '%26' to '&', then, split the string and get the parameters.
More details, please refer to the HTML URL Encoding.

Related

Include some kind of "header"-file to VBScript [duplicate]

VBScript doesn't appear to have a way to include a common file of functions.
Is there a way to achieve this?
You can create a (relatively) small function in each file that you want to include other files into, as follows:
sub includeFile (fSpec)
dim fileSys, file, fileData
set fileSys = createObject ("Scripting.FileSystemObject")
set file = fileSys.openTextFile (fSpec)
fileData = file.readAll ()
file.close
executeGlobal fileData
set file = nothing
set fileSys = nothing
end sub
and then use it to include specific files - these are executed as if they were inline.
includeFile "commonapi.vbi"
includeFile "dbcalls.vbi"
It basically opens the file, reads the entire contents into a string, then executes that string. There's no error handling on the I/O calls since this sort of stuff is usually done once on program start, and you want to fail if there's a problem including it.
Note that the includeFile function can be compressed to:
Sub includeFile(fSpec)
With CreateObject("Scripting.FileSystemObject")
executeGlobal .openTextFile(fSpec).readAll()
End With
End Sub
Or even to (if you're not adverse to long lines):
Sub includeFile(fSpec)
executeGlobal CreateObject("Scripting.FileSystemObject").openTextFile(fSpec).readAll()
End Sub
The "Windows Script Host" framework (if ya want to call it that), offers an XML wrapper document that adds functionality over regular vbs files. One of which is the ability to include external script files of both the VBscript and Jscript flavors. I never got very deep into it, but I think it would do what you're wanting to do.
http://msdn.microsoft.com/en-us/library/15x4407c(VS.85).aspx
You can include JavaScript, VBScript, or modules of other WScript script languages.
Example WSF file:
<job id="IncludeExample">
<script language="JavaScript" src="sprintf.js"/>
<script language="VBScript" src="logging.vbs"/>
<script language="VBScript" src="iis-queryScriptMaps.vbs"/>
</job>
If the above file is called "iis-scriptmaps.wsf", run it this way with cscript.exe:
cscript.exe iis-scriptmaps.wsf
I know this is an old thread but I post my answer anyway so others can learn what I have learnt about VBS and WSF files by "trial and error" :
So to have the same functionality as in other languages you can create one WSF file and include all of your VBS libs there, including the main program.
Something like this :
<job id="MainProg">
<script language="VBScript" src="Constants.vbs"/>
<script language="VBScript" src="FileFunctions.vbs"/>
<script language="VBScript" src="SendMail.vbs"/>
<script language="VBScript" src="LoggingFunctions.vbs"/>
<script language="VBScript" src="MainProgram.vbs"/>
<script language="VBScript">
' Here we call the main program
MainProgram()
</script>
</job>
In Constants.vbs collect all constants you want to use later and in the other VBS files define your functions. In your main program file MainProgram.vbs, create a sub called MainProgram() and write your program there.
In this subroutine, you can use all of the constants and functions defined in the other VBS files.
For example :
sub MainProgram()
' Local variables
Dim strMessage, strSendTo, strSubject
' OpenFile is a function from FileFunctions.vbs
strMessage = OpenFile("C:\Msg\message.html")
strSendTo = "email.address#yourdomain.com"
strSubject = "Daily report - " & date
' SendMessage is a function from SendMail.vbs
' cFrom and cServer are constants from Constants.vbs
SendMessage(cFrom, strSendTo, strSubject, strMessage, cServer)
' Logger is a function from LoggingFunctions.vbs
Logger("Daily report sent - " & now())
end sub
Hope you get the idea and I could help some people write better VBS apps :)
Building on the accepted answer, here's an include sub procedure which takes a path relative to the script location instead of the working directory:
Sub include( relativeFilePath )
Set fso = CreateObject("Scripting.FileSystemObject")
thisFolder = fso.GetParentFolderName( WScript.ScriptFullName )
absFilePath = fso.BuildPath( thisFolder, relativeFilePath )
executeGlobal fso.openTextFile( absFilePath ).readAll()
End Sub
Note the you can additionally use . and .. parts in your path to include files in parent folders, etc. and it will not matter where you launch the script from. Example:
include "..\Lib\StringUtilities.vbs"
Is this VBScript being used locally, or served classic ASP style?
If its classic ASP, you can use SSI todo it:
<!-- #include virtual="/PathTo/MyFile.vbs" -->
You can use the ExecuteGlobal function to run arbitrary VBS code in the global namespace. An example can be found here : http://www.source-code.biz/snippets/vbscript/5.htm
IIS 5 and up also allow a script tag for including other files from an ASP file. (Is your VBScript an ASP page or a Windows script?) Here's an example:
<script language="VBScript" runat="server" src="include.asp"></script>
The behavior and rules are a bit different from server-side includes. Note: I have never actually tried using this syntax from classic ASP.
you can definately use the WSF script tag in cscript:
<script language="VBScript" src="ADOVBS.INC"/>
If you use ADOVBS.inc for an ADODB access make sure to remove the
<% %>
tags from ADOVBS.INC.

external VBScript in a HTA

I am trying to get my HTA to load a script from an external location to save me releasing new HTA files, some of it can be loaded dynamically as I continue to add new functions to it. I can get it to work when I am using IIS to host the script file locally on my PC. But when I am trying to host it externally (I have only tried GitHub so far) I get the following error:
Line: 1
Char: 1
Error: "Type mismatch: 'Hello'"
Code: 0
URL:
I have something like:
<html>
<HEAD>
<title>HTA Test</title>
<HTA:APPLICATION
SCROLL="yes"
SINGLEINSTANCE="yes"
WINDOWSTATE="maximize"
>
<script language="VBScript" src="http://localhost/HtaUpdates/script.txt"></script>
<SCRIPT Language=vbscript>
Sub Window_OnLoad
setTimeout "Hello", 100, "VBScript"
End Sub
</SCRIPT>
</HEAD>
<BODY>
</BODY>
</html>
and in the script.txt on the server:
Sub Hello
MsgBox("Hello.")
End Sub
I have two recommendations for you.
Firstly, the reason why the script isn't loading is because you're specifying the script as type 'txt'. This means when you serve the script over your local/remote web server, the MIME type for the script will be 'text/plain' which won't be accepted. If you rename it to be a proper 'vbs' extension, IIS will serve the file with the MIME type 'text/vbscript' which is what the HTA is expecting.
Additionally, using setTimeout in this way is fragile because it requires that your script contents are loaded successfully within 100ms. If the network is slow, the call will fail. It's better to simply make the call to Hello at the end of the script that you are requesting over the network. You could repurpose the setTimeout call to check if the script has loaded successfully within e.g. 10 seconds (by looking for a variable, maybe?) and show an error message if it hasn't. Note that in my solution below, I have put the main code before the script tag, so that the global variable loaded is visible to the remote script.
One final warning: While testing this, I found that the HTA was caching the VBS file so when I made changes to script.vbs, they weren't taking effect when I reloaded the application. You'd need to either...
configure the web server to set an Expires header so that these files don't get cached
write some code in your HTA file to request the script with a 'nonce' value after it, to override the cache. For example requesting http://localhost/script.vbs?nonce=[RANDOM NUMBER], using VBScript's Randomize and Rnd functions. Requesting a static file with a nonce like this will still work on IIS because the parameters are ignored - it only cares that the file exists.
test.hta:
<html>
<HEAD>
<title>HTA Test</title>
<HTA:APPLICATION SCROLL="yes" SINGLEINSTANCE="yes" WINDOWSTATE="maximize">
<SCRIPT Language=vbscript>
Dim loaded : loaded = False
Sub CheckLoaded()
If loaded Then
MsgBox("Yes, the script loaded.")
Else
MsgBox("Oh dear! The script hasn't loaded.")
End If
End Sub
Sub Window_OnLoad
setTimeout "CheckLoaded", 1000, "VBScript"
End Sub
</SCRIPT>
<script language="VBScript" src="http://localhost/script.vbs"></script>
</HEAD>
<BODY>
</BODY>
</html>
script.vbs:
loaded = True
MsgBox("Hello.")

Open Internet Explorer from Chrome using a protocol handler (ie:url)

I've followed these steps and it doesn't work correctly for me.
Custom protocol handler in chrome
Basically, I don't have a custom app. I just want to create an handler to open IE with a specific URL.
Here are my reg:
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Classes\ie]
"URL Protocol"="\"\""
#="\"URL:IE Protocol\""
[HKEY_CURRENT_USER\Software\Classes\ie\DefaultIcon]
#="\"explorer.exe,1\""
[HKEY_CURRENT_USER\Software\Classes\ie\shell]
[HKEY_CURRENT_USER\Software\Classes\ie\shell\open]
[HKEY_CURRENT_USER\Software\Classes\ie\shell\open\command]
#="\"C:\\Program Files\\Internet Explorer\\iexplore.exe\" \"%1\""
It's working but... when I'm opening ie:www.google.com from Chrome, it ask to open IE but it keeps the "ie:" in the opened URL... which generate a endless loop.
How can I fix that?
Thanks
Create a Protocol Handler
save this script as internet-explorer-protocol-handler.reg:
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Classes\ie]
"URL Protocol"="\"\""
#="\"URL:IE Protocol\""
[HKEY_CURRENT_USER\Software\Classes\ie\DefaultIcon]
#="\"explorer.exe,1\""
[HKEY_CURRENT_USER\Software\Classes\ie\shell]
[HKEY_CURRENT_USER\Software\Classes\ie\shell\open]
[HKEY_CURRENT_USER\Software\Classes\ie\shell\open\command]
#="cmd /k set myvar=%1 & call set myvar=%%myvar:ie:=%% & call \"C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe\" %%myvar%% & exit /B"
Then run the script to install the keys in your registry. It will look like this:
Now links that use the ie: protocol will open in Internet Explorer.
Google
Demo Page
Here is a solution that should solve the problem with extended url's that contain parameters and special characters (&, % etc.)
Like this:
https://www.google.com/search?q=open-internet-explorer-from-chrome-using-a-protocol-handler&oq=open-internet-explorer-from-chrome-using-a-protocol-handler&aqs=chrome..69i57j69i60l3.1754j0j4&sourceid=chrome&ie=UTF-8
Replace the command in reg file with this:
powershell -windowstyle hidden -command "& {$Url = '%1' ; $Url = $Url -replace 'ie:',''; $IE=new-object -com internetexplorer.application ; $IE.navigate2($Url) ; $IE.visible=$true }"
After few tests, I move to another strategy.
I'm targetin an intermediate batch script instead.
And the batch split the protocol and the url, and open IE.
Here is the batch:
echo %1%
set var=%1
set var=%var:~4,-1%
Start "" "%ProgramFiles%\Internet Explorer\iexplore.exe" %var%
Working registry:
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Classes\ie]
"URL Protocol"=""
#="URL:IE Protocol"
[HKEY_CURRENT_USER\Software\Classes\ie\shell]
[HKEY_CURRENT_USER\Software\Classes\ie\shell\open]
[HKEY_CURRENT_USER\Software\Classes\ie\shell\open\command]
#="cmd /c set url=\"%1\" & call set url=%%url:ie:=%% & call start iexplore -nosessionmerging -noframemerging %%url%%"
Some important notes:
You have to wrap %1 in double quotes. Otherwise url with multiple params like example.com?a=1&b=2 will be stripped to example.com?a=1, params after & will be ignored.
You have to remove the double quotes when calling iexplore. If you don't remove the double quotes and open multiple IE window from chrome, only the first IE window will get the correct URL. But removing quotes with command set url=%%url:\"=%% or set url=%%url:~1,-1%% doesn't work.
If you just can't make it to remove those quotes, add switches -nosessionmerging and -noframemerging to iexplore. These are command-line options to control "merging" behavior for IE.
The implementation of the registry will be more generic if you last line of the registry as
#="cmd /C set myvar=%1 & call set myvar=%%myvar:ie:=%% & call start /separate iexplore %%myvar%% & exit"
You wont need to create a custom script.
In case, the target URL can have more than 1 query params, you might face an issue that only the first param gets passed to IE (check the address bar on IE to validate).
In such a case, you can go for the following workaround ... simply create a new html file passing the target URL after encoding it and open this HTML on IE.
window.location = "ie:"+<URL to the above HTML>+"?path="+encodeURIComponent(<target URL>);
In the HTML file, just redirect to the decoded target URL
<html>
<head>
<title>
IE Redirect
</title>
<script>
function getUrlVars() {
var vars = {};
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi,
function(m,key,value) {
vars[key] = value;
});
return vars;
}
function openURL(){
window.location.href=decodeURIComponent(getUrlVars()["path"]);
}
</script>
</head>
<body onload="openURL()">
</body>
</html>
The above worked perfectly in my application.
the following command will work for all query params to be passed:
cmd /C set myvar="%1" & call set myvar=%%myvar:ie:=%% & call start /separate "iexplore.exe" %%myvar%% & exit
the following command will work for all query params to be passed:
cmd /C set myvar="%1" & call set myvar=%%myvar:ie:=%% & call start
/separate "iexplore.exe" %%myvar%% & exit
We need to use the double quotes when a link had an ampersand in it and would not open in IE11 as anything after the ampersand was trimmed off.

How to set margin top for header?

The --margin-top option is for the contents margin, but I would like to set the margin from the top of the page to the header. The project I'm working on allows users to create header and footer themselves, so the height of the header or footer is dynamic.
I don't know how to do it so can anyone help?
The built-in options for top margin are
--margin-top (as you mentioned above) and
--header-spacing Spacing between header and content in mm (refer: http://wkhtmltopdf.org/usage/wkhtmltopdf.txt).
None of them will probably help you as there is no option (at least to my knowledge) that can explicitly set some margin from the top of the page to the header. However, in your case, you could explore --header-html <url> and add a html header. This can take an HTML where you could probably set the custom header and add space/margin accordingly and then the HTML gets displayed in on the header.
Use -T -B -L and -R for margins.
wkhtmltopdf -B 13 -L 13 -R 13 -T 53 /tmp/e0cb9c4597860b5abfbf2bafc1000d5a.html /tmp/e0cb9c4597860b5abfbf2bafc1000d5a.pdf
-T 10 is working by adding an empty HTML.
wkhtmltopdf.exe -T 10 --header-html header.html content.html generatedpdf.pdf
the empty html:
<!DOCTYPE html>
<html lang="en">
<head>
<META http-equiv="Content-Type" content="text/html; charset=utf-16">
</head>
<body >
</body>
</html>

How do I include a common file in VBScript (similar to C #include)?

VBScript doesn't appear to have a way to include a common file of functions.
Is there a way to achieve this?
You can create a (relatively) small function in each file that you want to include other files into, as follows:
sub includeFile (fSpec)
dim fileSys, file, fileData
set fileSys = createObject ("Scripting.FileSystemObject")
set file = fileSys.openTextFile (fSpec)
fileData = file.readAll ()
file.close
executeGlobal fileData
set file = nothing
set fileSys = nothing
end sub
and then use it to include specific files - these are executed as if they were inline.
includeFile "commonapi.vbi"
includeFile "dbcalls.vbi"
It basically opens the file, reads the entire contents into a string, then executes that string. There's no error handling on the I/O calls since this sort of stuff is usually done once on program start, and you want to fail if there's a problem including it.
Note that the includeFile function can be compressed to:
Sub includeFile(fSpec)
With CreateObject("Scripting.FileSystemObject")
executeGlobal .openTextFile(fSpec).readAll()
End With
End Sub
Or even to (if you're not adverse to long lines):
Sub includeFile(fSpec)
executeGlobal CreateObject("Scripting.FileSystemObject").openTextFile(fSpec).readAll()
End Sub
The "Windows Script Host" framework (if ya want to call it that), offers an XML wrapper document that adds functionality over regular vbs files. One of which is the ability to include external script files of both the VBscript and Jscript flavors. I never got very deep into it, but I think it would do what you're wanting to do.
http://msdn.microsoft.com/en-us/library/15x4407c(VS.85).aspx
You can include JavaScript, VBScript, or modules of other WScript script languages.
Example WSF file:
<job id="IncludeExample">
<script language="JavaScript" src="sprintf.js"/>
<script language="VBScript" src="logging.vbs"/>
<script language="VBScript" src="iis-queryScriptMaps.vbs"/>
</job>
If the above file is called "iis-scriptmaps.wsf", run it this way with cscript.exe:
cscript.exe iis-scriptmaps.wsf
I know this is an old thread but I post my answer anyway so others can learn what I have learnt about VBS and WSF files by "trial and error" :
So to have the same functionality as in other languages you can create one WSF file and include all of your VBS libs there, including the main program.
Something like this :
<job id="MainProg">
<script language="VBScript" src="Constants.vbs"/>
<script language="VBScript" src="FileFunctions.vbs"/>
<script language="VBScript" src="SendMail.vbs"/>
<script language="VBScript" src="LoggingFunctions.vbs"/>
<script language="VBScript" src="MainProgram.vbs"/>
<script language="VBScript">
' Here we call the main program
MainProgram()
</script>
</job>
In Constants.vbs collect all constants you want to use later and in the other VBS files define your functions. In your main program file MainProgram.vbs, create a sub called MainProgram() and write your program there.
In this subroutine, you can use all of the constants and functions defined in the other VBS files.
For example :
sub MainProgram()
' Local variables
Dim strMessage, strSendTo, strSubject
' OpenFile is a function from FileFunctions.vbs
strMessage = OpenFile("C:\Msg\message.html")
strSendTo = "email.address#yourdomain.com"
strSubject = "Daily report - " & date
' SendMessage is a function from SendMail.vbs
' cFrom and cServer are constants from Constants.vbs
SendMessage(cFrom, strSendTo, strSubject, strMessage, cServer)
' Logger is a function from LoggingFunctions.vbs
Logger("Daily report sent - " & now())
end sub
Hope you get the idea and I could help some people write better VBS apps :)
Building on the accepted answer, here's an include sub procedure which takes a path relative to the script location instead of the working directory:
Sub include( relativeFilePath )
Set fso = CreateObject("Scripting.FileSystemObject")
thisFolder = fso.GetParentFolderName( WScript.ScriptFullName )
absFilePath = fso.BuildPath( thisFolder, relativeFilePath )
executeGlobal fso.openTextFile( absFilePath ).readAll()
End Sub
Note the you can additionally use . and .. parts in your path to include files in parent folders, etc. and it will not matter where you launch the script from. Example:
include "..\Lib\StringUtilities.vbs"
Is this VBScript being used locally, or served classic ASP style?
If its classic ASP, you can use SSI todo it:
<!-- #include virtual="/PathTo/MyFile.vbs" -->
You can use the ExecuteGlobal function to run arbitrary VBS code in the global namespace. An example can be found here : http://www.source-code.biz/snippets/vbscript/5.htm
IIS 5 and up also allow a script tag for including other files from an ASP file. (Is your VBScript an ASP page or a Windows script?) Here's an example:
<script language="VBScript" runat="server" src="include.asp"></script>
The behavior and rules are a bit different from server-side includes. Note: I have never actually tried using this syntax from classic ASP.
you can definately use the WSF script tag in cscript:
<script language="VBScript" src="ADOVBS.INC"/>
If you use ADOVBS.inc for an ADODB access make sure to remove the
<% %>
tags from ADOVBS.INC.

Resources