2

I have been wondering for quite some time whether t is possible to create a library which would act as a file provider in Windows.

For example if you try to open ftp://example.com/touch.txt file using standard Open file dialog, it (somehow magically) works. Is there a way how to implement my own provider for my own URI scheme?

Could Asynchronous Pluggable Protocol be a solution? I was not able to find a working code example on how to make it work.

To understand: I need this to work system-wide. This is nowise connected to internet browsers.

What if I need this File.Open("my://test.txt") to work?

  • Totally possible and you're on the right track. Take a look at https://msdn.microsoft.com/en-us/library/aa767914%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396 – itsme86 Aug 24 '16 at 22:03
  • A sample is available here https://blogs.msdn.microsoft.com/noahc/2006/10/19/register-a-custom-url-protocol-handler/ – Simon Mourier Aug 25 '16 at 05:56
  • OK. This lets me to open my application when the URI is called. But what if I want to deliver an object via this URI. e.g. File.Read("my://test.txt"); – Jiří Travěnec Aug 25 '16 at 21:47

1 Answers1

0

Doing File.ReadAllBytes("ftp://example.com/touch.txt"); does not work, if you try it you get a exception like

System.NotSupportedException was unhandled
  Message=The given path's format is not supported.
  Source=mscorlib
  StackTrace:
       at System.Security.Util.StringExpressionSet.CanonicalizePath(String path, Boolean needFullPath)
       at System.Security.Util.StringExpressionSet.CreateListFromExpressions(String[] str, Boolean needFullPath)
       at System.Security.Permissions.FileIOPermission.AddPathList(FileIOPermissionAccess access, AccessControlActions control, String[] pathListOrig, Boolean checkForDuplicates, Boolean needFullPath, Boolean copyPathList)
       at System.Security.Permissions.FileIOPermission..ctor(FileIOPermissionAccess access, AccessControlActions control, String[] pathList, Boolean checkForDuplicates, Boolean needFullPath)
       at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy)
       at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy)
       at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
       at System.IO.File.ReadAllBytes(String path)
       at WindowsFormsApplication1.Form1.button1_Click(Object sender, EventArgs e) in D:\Code\WindowsFormsApplication1\WindowsFormsApplication1\Form1.cs:line 25
       at System.Windows.Forms.Control.OnClick(EventArgs e)
       at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
       at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ButtonBase.WndProc(Message& m)
       at System.Windows.Forms.Button.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at WindowsFormsApplication1.Program.Main() in D:\Code\WindowsFormsApplication1\WindowsFormsApplication1\Program.cs:line 17
       at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 

The reason it works when you do a OpenFileDialog is windows cheats with that and will download the file to a local temp folder first. It only does this for ftp: and http: because OpenFileDialog is handled by the windows shell and the shell is what uses URI schemes.

I believe the Source Filter key under HKCR\ftp points to a registered COM object that handles the logic of doing that local copy.

If you just want your application to be opened by going to a URL like steam does with it's steam://rungameid/382110 you just need to follow the instructions in this MSDN page.

If you want your file to be "openable" via a shell like http: or ftp: does with the open file dialog you will need to write a COM object that acts as the "Source Filter", I do not know of any place to find documentation on that.

Update: Reading more it does look like Asynchronous Pluggable Protocol like you mentioned is how you make those source filters. I have never tried to make one so I can't help you beyond that.

Scott Chamberlain
  • 124,994
  • 33
  • 282
  • 431