mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 08:23:05 -05:00
tst: notifyfs-dotnet: add .NET file system to demo file notification mechanism
This commit is contained in:
parent
8006763367
commit
40052b143e
9
tst/notifyfs-dotnet/.gitignore
vendored
Normal file
9
tst/notifyfs-dotnet/.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
build
|
||||||
|
*.ncb
|
||||||
|
*.suo
|
||||||
|
*.vcproj.*
|
||||||
|
*.vcxproj.user
|
||||||
|
*.csproj.user
|
||||||
|
*.VC.db
|
||||||
|
*.VC.opendb
|
||||||
|
.vs
|
394
tst/notifyfs-dotnet/Program.cs
Normal file
394
tst/notifyfs-dotnet/Program.cs
Normal file
@ -0,0 +1,394 @@
|
|||||||
|
/**
|
||||||
|
* @file Program.cs
|
||||||
|
*
|
||||||
|
* @copyright 2015-2020 Bill Zissimopoulos
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* This file is part of WinFsp.
|
||||||
|
*
|
||||||
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
|
* General Public License version 3 as published by the Free Software
|
||||||
|
* Foundation.
|
||||||
|
*
|
||||||
|
* Licensees holding a valid commercial license may use this software
|
||||||
|
* in accordance with the commercial license agreement provided in
|
||||||
|
* conjunction with the software. The terms and conditions of any such
|
||||||
|
* commercial license agreement shall govern, supersede, and render
|
||||||
|
* ineffective any application of the GPLv3 license to this software,
|
||||||
|
* notwithstanding of any reference thereto in the software or
|
||||||
|
* associated repository.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Security.AccessControl;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
using Fsp;
|
||||||
|
using VolumeInfo = Fsp.Interop.VolumeInfo;
|
||||||
|
using FileInfo = Fsp.Interop.FileInfo;
|
||||||
|
using NotifyInfo = Fsp.Interop.NotifyInfo;
|
||||||
|
using NotifyAction = Fsp.Interop.NotifyAction;
|
||||||
|
using NotifyFilter = Fsp.Interop.NotifyFilter;
|
||||||
|
|
||||||
|
namespace notifyfs
|
||||||
|
{
|
||||||
|
class Notifyfs : FileSystemBase
|
||||||
|
{
|
||||||
|
public override Int32 Init(Object Host)
|
||||||
|
{
|
||||||
|
_Host = (FileSystemHost)Host;
|
||||||
|
_Host.SectorSize = ALLOCATION_UNIT;
|
||||||
|
_Host.SectorsPerAllocationUnit = 1;
|
||||||
|
_Host.FileInfoTimeout = 1000;
|
||||||
|
_Host.CaseSensitiveSearch = false;
|
||||||
|
_Host.CasePreservedNames = true;
|
||||||
|
_Host.UnicodeOnDisk = true;
|
||||||
|
_Host.PersistentAcls = false;
|
||||||
|
_Host.PostCleanupWhenModifiedOnly = true;
|
||||||
|
_Host.VolumeCreationTime = 0;
|
||||||
|
_Host.VolumeSerialNumber = 0;
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
public override Int32 Mounted(Object Host)
|
||||||
|
{
|
||||||
|
_Timer = new Timer(this.Tick, null, 0, 1000);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
public override void Unmounted(Object Host)
|
||||||
|
{
|
||||||
|
WaitHandle Event = new ManualResetEvent(false);
|
||||||
|
_Timer.Dispose(Event);
|
||||||
|
Event.WaitOne();
|
||||||
|
}
|
||||||
|
public override Int32 GetVolumeInfo(
|
||||||
|
out VolumeInfo VolumeInfo)
|
||||||
|
{
|
||||||
|
VolumeInfo = default(VolumeInfo);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
public override Int32 GetSecurityByName(
|
||||||
|
String FileName,
|
||||||
|
out UInt32 FileAttributes/* or ReparsePointIndex */,
|
||||||
|
ref Byte[] SecurityDescriptor)
|
||||||
|
{
|
||||||
|
int Index = FileLookup(FileName);
|
||||||
|
if (-1 == Index)
|
||||||
|
{
|
||||||
|
FileAttributes = default(UInt32);
|
||||||
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileAttributes = 0 == Index ? (UInt32)System.IO.FileAttributes.Directory : 0;
|
||||||
|
if (null != SecurityDescriptor)
|
||||||
|
SecurityDescriptor = DefaultSecurity;
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
public override Int32 Open(
|
||||||
|
String FileName,
|
||||||
|
UInt32 CreateOptions,
|
||||||
|
UInt32 GrantedAccess,
|
||||||
|
out Object FileNode,
|
||||||
|
out Object FileDesc,
|
||||||
|
out FileInfo FileInfo,
|
||||||
|
out String NormalizedName)
|
||||||
|
{
|
||||||
|
FileNode = default(Object);
|
||||||
|
FileDesc = default(Object);
|
||||||
|
FileInfo = default(FileInfo);
|
||||||
|
NormalizedName = default(String);
|
||||||
|
|
||||||
|
int Index = FileLookup(FileName);
|
||||||
|
if (-1 == Index)
|
||||||
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
|
|
||||||
|
FileNode = Index;
|
||||||
|
FillFileInfo(Index, out FileInfo);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
public override Int32 Read(
|
||||||
|
Object FileNode,
|
||||||
|
Object FileDesc,
|
||||||
|
IntPtr Buffer,
|
||||||
|
UInt64 Offset,
|
||||||
|
UInt32 Length,
|
||||||
|
out UInt32 BytesTransferred)
|
||||||
|
{
|
||||||
|
int Index = (int)FileNode;
|
||||||
|
UInt64 EndOffset;
|
||||||
|
Byte[] Contents = FileContents(Index);
|
||||||
|
|
||||||
|
if (Offset >= (UInt64)Contents.Length)
|
||||||
|
{
|
||||||
|
BytesTransferred = 0;
|
||||||
|
return STATUS_END_OF_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
EndOffset = Offset + Length;
|
||||||
|
if (EndOffset > (UInt64)Contents.Length)
|
||||||
|
EndOffset = (UInt64)Contents.Length;
|
||||||
|
|
||||||
|
BytesTransferred = (UInt32)(EndOffset - Offset);
|
||||||
|
Marshal.Copy(Contents, (int)Offset, Buffer, (int)BytesTransferred);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
public override Int32 GetFileInfo(
|
||||||
|
Object FileNode,
|
||||||
|
Object FileDesc,
|
||||||
|
out FileInfo FileInfo)
|
||||||
|
{
|
||||||
|
int Index = (int)FileNode;
|
||||||
|
|
||||||
|
FillFileInfo(Index, out FileInfo);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
public override Boolean ReadDirectoryEntry(
|
||||||
|
Object FileNode,
|
||||||
|
Object FileDesc,
|
||||||
|
String Pattern,
|
||||||
|
String Marker,
|
||||||
|
ref Object Context,
|
||||||
|
out String FileName,
|
||||||
|
out FileInfo FileInfo)
|
||||||
|
{
|
||||||
|
IEnumerator<String> Enumerator = (IEnumerator<String>)Context;
|
||||||
|
|
||||||
|
if (null == Enumerator)
|
||||||
|
{
|
||||||
|
List<String> ChildrenFileNames = new List<String>();
|
||||||
|
for (int Index = 1, Count = FileCount(); Count >= Index; Index++)
|
||||||
|
ChildrenFileNames.Add(String.Format("{0}", Index));
|
||||||
|
Context = Enumerator = ChildrenFileNames.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (Enumerator.MoveNext())
|
||||||
|
{
|
||||||
|
FileName = Enumerator.Current;
|
||||||
|
FillFileInfo(int.Parse(FileName), out FileInfo);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileName = default(String);
|
||||||
|
FileInfo = default(FileInfo);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int CountFromTicks(int Ticks)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The formula below produces the periodic sequence:
|
||||||
|
* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
|
||||||
|
* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
|
||||||
|
* ...
|
||||||
|
*/
|
||||||
|
int div10 = (Ticks % 20) / 10;
|
||||||
|
int mod10 = Ticks % 10;
|
||||||
|
int mdv10 = 1 - div10;
|
||||||
|
int mmd10 = 10 - mod10;
|
||||||
|
return mdv10 * mod10 + div10 * mmd10;
|
||||||
|
}
|
||||||
|
private int FileCount()
|
||||||
|
{
|
||||||
|
int Ticks = Thread.VolatileRead(ref _Ticks);
|
||||||
|
return CountFromTicks(Ticks);
|
||||||
|
}
|
||||||
|
private int FileLookup(String FileName)
|
||||||
|
{
|
||||||
|
FileName = FileName.Substring(1);
|
||||||
|
if ("" == FileName)
|
||||||
|
return 0; /* root */
|
||||||
|
int Count = FileCount();
|
||||||
|
Boolean Valid = int.TryParse(FileName, out int Index);
|
||||||
|
if (!Valid || 0 >= Index || Index > Count)
|
||||||
|
return -1; /* not found */
|
||||||
|
return Index; /* regular file named 1, 2, ..., Count */
|
||||||
|
}
|
||||||
|
private static Byte[] FileContents(int Index)
|
||||||
|
{
|
||||||
|
if (0 == Index)
|
||||||
|
return EmptyByteArray;
|
||||||
|
return Encoding.UTF8.GetBytes(String.Format("{0}\n", Index));
|
||||||
|
}
|
||||||
|
private static void FillFileInfo(int Index, out FileInfo FileInfo)
|
||||||
|
{
|
||||||
|
FileInfo = default(FileInfo);
|
||||||
|
FileInfo.FileAttributes = 0 == Index ? (UInt32)System.IO.FileAttributes.Directory : 0;
|
||||||
|
FileInfo.FileSize = (UInt64)FileContents(Index).Length;
|
||||||
|
FileInfo.AllocationSize = (FileInfo.FileSize + ALLOCATION_UNIT - 1)
|
||||||
|
/ ALLOCATION_UNIT * ALLOCATION_UNIT;
|
||||||
|
FileInfo.CreationTime =
|
||||||
|
FileInfo.LastAccessTime =
|
||||||
|
FileInfo.LastWriteTime =
|
||||||
|
FileInfo.ChangeTime = (UInt64)DateTime.Now.ToFileTimeUtc();
|
||||||
|
}
|
||||||
|
private void Tick(Object Context)
|
||||||
|
{
|
||||||
|
int Ticks = Interlocked.Increment(ref _Ticks);
|
||||||
|
int OldCount = CountFromTicks(Ticks - 1);
|
||||||
|
int NewCount = CountFromTicks(Ticks);
|
||||||
|
NotifyInfo[] NotifyInfo = new NotifyInfo[1];
|
||||||
|
|
||||||
|
if (OldCount < NewCount)
|
||||||
|
{
|
||||||
|
NotifyInfo[0].FileName = String.Format("\\{0}", NewCount);
|
||||||
|
NotifyInfo[0].Action = NotifyAction.Added;
|
||||||
|
NotifyInfo[0].Filter = NotifyFilter.ChangeFileName;
|
||||||
|
Console.Error.WriteLine("CREATE \\{0}", NewCount);
|
||||||
|
}
|
||||||
|
else if (OldCount > NewCount)
|
||||||
|
{
|
||||||
|
NotifyInfo[0].FileName = String.Format("\\{0}", OldCount);
|
||||||
|
NotifyInfo[0].Action = NotifyAction.Removed;
|
||||||
|
NotifyInfo[0].Filter = NotifyFilter.ChangeFileName;
|
||||||
|
Console.Error.WriteLine("REMOVE \\{0}", OldCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OldCount != NewCount)
|
||||||
|
{
|
||||||
|
if (STATUS_SUCCESS == _Host.NotifyBegin(500))
|
||||||
|
{
|
||||||
|
_Host.Notify(NotifyInfo);
|
||||||
|
_Host.NotifyEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Notifyfs()
|
||||||
|
{
|
||||||
|
RawSecurityDescriptor RootSecurityDescriptor = new RawSecurityDescriptor(
|
||||||
|
"O:BAG:BAD:P(A;;FA;;;SY)(A;;FA;;;BA)(A;;FA;;;WD)");
|
||||||
|
DefaultSecurity = new Byte[RootSecurityDescriptor.BinaryLength];
|
||||||
|
RootSecurityDescriptor.GetBinaryForm(DefaultSecurity, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private const int ALLOCATION_UNIT = 4096;
|
||||||
|
private static readonly Byte[] EmptyByteArray = new Byte[0];
|
||||||
|
private static readonly Byte[] DefaultSecurity;
|
||||||
|
private FileSystemHost _Host;
|
||||||
|
private Timer _Timer;
|
||||||
|
private int _Ticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
class NotifyfsService : Service
|
||||||
|
{
|
||||||
|
private class CommandLineUsageException : Exception
|
||||||
|
{
|
||||||
|
public CommandLineUsageException(String Message = null) : base(Message)
|
||||||
|
{
|
||||||
|
HasMessage = null != Message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
private const String PROGNAME = "notifyfs-dotnet";
|
||||||
|
|
||||||
|
public NotifyfsService() : base("NotifyfsService")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnStart(String[] Args)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String VolumePrefix = null;
|
||||||
|
String MountPoint = null;
|
||||||
|
FileSystemHost Host = null;
|
||||||
|
Notifyfs Notifyfs = null;
|
||||||
|
int I;
|
||||||
|
|
||||||
|
for (I = 1; Args.Length > I; I++)
|
||||||
|
{
|
||||||
|
String Arg = Args[I];
|
||||||
|
if ('-' != Arg[0])
|
||||||
|
break;
|
||||||
|
switch (Arg[1])
|
||||||
|
{
|
||||||
|
case '?':
|
||||||
|
throw new CommandLineUsageException();
|
||||||
|
case 'm':
|
||||||
|
argtos(Args, ref I, ref MountPoint);
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
argtos(Args, ref I, ref VolumePrefix);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new CommandLineUsageException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Args.Length > I)
|
||||||
|
throw new CommandLineUsageException();
|
||||||
|
|
||||||
|
if (null == MountPoint)
|
||||||
|
throw new CommandLineUsageException();
|
||||||
|
|
||||||
|
FileSystemHost.SetDebugLogFile("-");
|
||||||
|
|
||||||
|
Host = new FileSystemHost(Notifyfs = new Notifyfs());
|
||||||
|
Host.Prefix = VolumePrefix;
|
||||||
|
if (0 > Host.Mount(MountPoint))
|
||||||
|
throw new IOException("cannot mount file system");
|
||||||
|
MountPoint = Host.MountPoint();
|
||||||
|
_Host = Host;
|
||||||
|
|
||||||
|
Log(EVENTLOG_INFORMATION_TYPE, String.Format("{0}{1}{2} -m {3}",
|
||||||
|
PROGNAME,
|
||||||
|
null != VolumePrefix && 0 < VolumePrefix.Length ? " -u " : "",
|
||||||
|
null != VolumePrefix && 0 < VolumePrefix.Length ? VolumePrefix : "",
|
||||||
|
MountPoint));
|
||||||
|
}
|
||||||
|
catch (CommandLineUsageException ex)
|
||||||
|
{
|
||||||
|
Log(EVENTLOG_ERROR_TYPE, String.Format(
|
||||||
|
"{0}" +
|
||||||
|
"usage: {1} OPTIONS\n" +
|
||||||
|
"\n" +
|
||||||
|
"options:\n" +
|
||||||
|
" -u \\Server\\Share [UNC prefix (single backslash)]\n" +
|
||||||
|
" -m MountPoint [X:|*|directory]\n",
|
||||||
|
ex.HasMessage ? ex.Message + "\n" : "",
|
||||||
|
PROGNAME));
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log(EVENTLOG_ERROR_TYPE, String.Format("{0}", ex.Message));
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected override void OnStop()
|
||||||
|
{
|
||||||
|
_Host.Unmount();
|
||||||
|
_Host = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void argtos(String[] Args, ref int I, ref String V)
|
||||||
|
{
|
||||||
|
if (Args.Length > ++I)
|
||||||
|
V = Args[I];
|
||||||
|
else
|
||||||
|
throw new CommandLineUsageException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private FileSystemHost _Host;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
Environment.ExitCode = new NotifyfsService().Run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
77
tst/notifyfs-dotnet/notifyfs-dotnet.csproj
Normal file
77
tst/notifyfs-dotnet/notifyfs-dotnet.csproj
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{DA7C383A-D10F-4FB0-BDCB-E7A7C5D068AA}</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<RootNamespace>notifyfs</RootNamespace>
|
||||||
|
<AssemblyName>notifyfs-dotnet</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
<Deterministic>true</Deterministic>
|
||||||
|
<PublishUrl>publish\</PublishUrl>
|
||||||
|
<Install>true</Install>
|
||||||
|
<InstallFrom>Disk</InstallFrom>
|
||||||
|
<UpdateEnabled>false</UpdateEnabled>
|
||||||
|
<UpdateMode>Foreground</UpdateMode>
|
||||||
|
<UpdateInterval>7</UpdateInterval>
|
||||||
|
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||||
|
<UpdatePeriodically>false</UpdatePeriodically>
|
||||||
|
<UpdateRequired>false</UpdateRequired>
|
||||||
|
<MapFileExtensions>true</MapFileExtensions>
|
||||||
|
<ApplicationRevision>0</ApplicationRevision>
|
||||||
|
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||||
|
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||||
|
<UseApplicationTrust>false</UseApplicationTrust>
|
||||||
|
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
|
||||||
|
<BaseIntermediateOutputPath>$(SolutionDir)build\$(ProjectName).build\</BaseIntermediateOutputPath>
|
||||||
|
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
|
||||||
|
<BaseIntermediateOutputPath>$(SolutionDir)build\$(ProjectName).build\</BaseIntermediateOutputPath>
|
||||||
|
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Program.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="winfsp-msil">
|
||||||
|
<HintPath>$(MSBuildProgramFiles32)\WinFsp\bin\winfsp-msil.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<BootstrapperPackage Include=".NETFramework,Version=v4.5.2">
|
||||||
|
<Visible>False</Visible>
|
||||||
|
<ProductName>Microsoft .NET Framework 4.5.2 %28x86 and x64%29</ProductName>
|
||||||
|
<Install>true</Install>
|
||||||
|
</BootstrapperPackage>
|
||||||
|
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||||
|
<Visible>False</Visible>
|
||||||
|
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||||
|
<Install>false</Install>
|
||||||
|
</BootstrapperPackage>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
</Project>
|
25
tst/notifyfs-dotnet/notifyfs-dotnet.sln
Normal file
25
tst/notifyfs-dotnet/notifyfs-dotnet.sln
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 16
|
||||||
|
VisualStudioVersion = 16.0.30717.126
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "notifyfs-dotnet", "notifyfs-dotnet.csproj", "{DA7C383A-D10F-4FB0-BDCB-E7A7C5D068AA}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{DA7C383A-D10F-4FB0-BDCB-E7A7C5D068AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{DA7C383A-D10F-4FB0-BDCB-E7A7C5D068AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{DA7C383A-D10F-4FB0-BDCB-E7A7C5D068AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{DA7C383A-D10F-4FB0-BDCB-E7A7C5D068AA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {18D87005-09CA-40CF-9B51-139B486AB8D0}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
Loading…
x
Reference in New Issue
Block a user