diff --git a/PartPreviewWindow/View3DTransfromPart.cs b/PartPreviewWindow/View3DTransfromPart.cs index d1e6a8bf5..d0f754639 100644 --- a/PartPreviewWindow/View3DTransfromPart.cs +++ b/PartPreviewWindow/View3DTransfromPart.cs @@ -325,7 +325,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow { UiThread.RunOnIdle((state) => { - EnterEdit(); + EnterEditAndCreateSelectionData(); OpenFileDialogParams openParams = new OpenFileDialogParams(ApplicationSettings.OpenDesignFileParams, multiSelect: true); @@ -337,7 +337,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow Button enterEdittingButton = textImageButtonFactory.Generate(LocalizedString.Get("Edit")); enterEdittingButton.Click += (sender, e) => { - EnterEdit(); + EnterEditAndCreateSelectionData(); }; enterEditButtonsContainer.AddChild(enterEdittingButton); @@ -485,7 +485,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow { UiThread.RunOnIdle((state) => { - EnterEdit(); + EnterEditAndCreateSelectionData(); }); } @@ -983,9 +983,92 @@ namespace MatterHackers.MatterControl.PartPreviewWindow } } + void EnterEditAndCreateSelectionData() + { + if (enterEditButtonsContainer.Visible == true) + { + enterEditButtonsContainer.Visible = false; + } + + if (MeshGroups.Count > 0) + { + processingProgressControl.Visible = true; + LockEditControls(); + viewIsInEditModePreLock = true; + + BackgroundWorker createSelectionDataBackgroundWorker = null; + createSelectionDataBackgroundWorker = new BackgroundWorker(); + createSelectionDataBackgroundWorker.WorkerReportsProgress = true; + + createSelectionDataBackgroundWorker.ProgressChanged += new ProgressChangedEventHandler(BackgroundWorker_ProgressChanged); + createSelectionDataBackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(createSelectionDataBackgroundWorker_RunWorkerCompleted); + createSelectionDataBackgroundWorker.DoWork += new DoWorkEventHandler(createSelectionDataBackgroundWorker_DoWork); + + createSelectionDataBackgroundWorker.RunWorkerAsync(); + } + } + + void createSelectionDataBackgroundWorker_DoWork(object sender, DoWorkEventArgs e) + { + Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; + BackgroundWorker backgroundWorker = (BackgroundWorker)sender; + + asynchPlatingDataList.Clear(); + asynchMeshGroupTransforms.Clear(); + for (int i = 0; i < asynchMeshGroupsList.Count; i++) + { + PlatingMeshGroupData newInfo = new PlatingMeshGroupData(); + asynchPlatingDataList.Add(newInfo); + + MeshGroup meshGroup = asynchMeshGroupsList[i]; + + // remember where it is now + AxisAlignedBoundingBox startingBounds = meshGroup.GetAxisAlignedBoundingBox(asynchMeshGroupTransforms[i].TotalTransform); + Vector3 startingCenter = (startingBounds.maxXYZ + startingBounds.minXYZ) / 2; + + ScaleRotateTranslate meshTransform = asynchMeshGroupTransforms[i]; + + // move the mesh to be centered on the origin + AxisAlignedBoundingBox meshBounds = meshGroup.GetAxisAlignedBoundingBox(); + Vector3 meshCenter = (meshBounds.maxXYZ + meshBounds.minXYZ) / 2; + meshTransform.centering = Matrix4X4.CreateTranslation(-meshCenter); + + // set the transform to position it where it was + meshTransform.translation = Matrix4X4.CreateTranslation(startingCenter); + asynchMeshGroupTransforms[i] = meshTransform; + PlatingHelper.PlaceMeshGroupOnBed(asynchMeshGroupsList, asynchMeshGroupTransforms, i, false); + + // and create selection info + PlatingHelper.CreateITraceableForMeshGroup(asynchPlatingDataList, asynchMeshGroupsList, i); + if (asynchMeshGroupsList.Count > 1) + { + backgroundWorker.ReportProgress(50 + i * 50 / (asynchMeshGroupsList.Count - 1)); + } + } + } + + void createSelectionDataBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) + { + if (WidgetHasBeenClosed) + { + return; + } + // remove the original mesh and replace it with these new meshes + PullMeshGroupDataFromAsynchLists(); + + UnlockEditControls(); + + if (pendingPartsToLoad.Count > 0) + { + LoadAndAddPartsToPlate(pendingPartsToLoad.ToArray()); + } + + Invalidate(); + } + void createDiscreteMeshesBackgroundWorker_DoWork(object sender, DoWorkEventArgs e) { - throw new NotImplementedException(); + throw new NotImplementedException(); #if false Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; BackgroundWorker backgroundWorker = (BackgroundWorker)sender; @@ -1029,20 +1112,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow #endif } - void EnterEdit() - { - if (enterEditButtonsContainer.Visible == true) - { - enterEditButtonsContainer.Visible = false; - } - if (pendingPartsToLoad.Count > 0) - { - LoadAndAddPartsToPlate(pendingPartsToLoad.ToArray()); - } - viewControls3D.PartSelectVisible = true; - doEdittingButtonsContainer.Visible = true; - } - void createDiscreteMeshesBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (WidgetHasBeenClosed) @@ -1586,7 +1655,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow bool enterEditModeBeforeAddingParts = enterEditButtonsContainer.Visible == true; if (enterEditModeBeforeAddingParts) { - EnterEdit(); + EnterEditAndCreateSelectionData(); } else { diff --git a/PrinterCommunication/RemotingLite/BuildProcessTemplates/DefaultTemplate.11.1.xaml b/PrinterCommunication/RemotingLite/BuildProcessTemplates/DefaultTemplate.11.1.xaml new file mode 100644 index 000000000..bf54edfd9 --- /dev/null +++ b/PrinterCommunication/RemotingLite/BuildProcessTemplates/DefaultTemplate.11.1.xaml @@ -0,0 +1,543 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + [New Microsoft.TeamFoundation.Build.Workflow.Activities.BuildSettings()] + [False] + [New Microsoft.TeamFoundation.Build.Workflow.Activities.TestSpecList(New Microsoft.TeamFoundation.Build.Workflow.Activities.AgileTestPlatformSpec("**\*test*.dll"))] + ["$(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.r)"] + [False] + [True] + [True] + [Microsoft.TeamFoundation.Build.Workflow.Activities.CleanWorkspaceOption.All] + + + + [Microsoft.TeamFoundation.Build.Workflow.Activities.CodeAnalysisOption.AsConfigured] + [True] + [Microsoft.TeamFoundation.Build.Workflow.Activities.ToolPlatform.Auto] + [True] + [New Microsoft.TeamFoundation.Build.Workflow.Activities.SourceAndSymbolServerSettings(True, Nothing)] + [True] + + + + [New Microsoft.TeamFoundation.Build.Workflow.Activities.AgentSettings() With {.MaxWaitTime = New System.TimeSpan(4, 0, 0), .MaxExecutionTime = New System.TimeSpan(0, 0, 0), .TagComparison = Microsoft.TeamFoundation.Build.Workflow.Activities.TagComparison.MatchExactly }] + [Microsoft.TeamFoundation.Build.Workflow.BuildVerbosity.Normal] + + + + + + + All + 11.0 + Assembly references and imported namespaces serialized as XML namespaces + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/PrinterCommunication/RemotingLite/BuildProcessTemplates/DefaultTemplate.xaml b/PrinterCommunication/RemotingLite/BuildProcessTemplates/DefaultTemplate.xaml new file mode 100644 index 000000000..12cc6241d --- /dev/null +++ b/PrinterCommunication/RemotingLite/BuildProcessTemplates/DefaultTemplate.xaml @@ -0,0 +1,602 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Assembly references and imported namespaces serialized as XML namespaces + + + True + + + + + + + + + True + + + + + + + True + + + + + + + + + + + True + + + + + + + + + + + + + + + + + + + + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + + + + + + + + + + + + + + + + + + + True + + + + + + + + + + + + True + + + + + + + + + + + + + + True + + + + + + + + + + + + + + + + + + + True + + + + + + + + + + + + + + + + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + + + + + + + + + + + + + + + + + + + + + + True + + + + + + + + + True + + + + + + + + + + + + + + + True + + + + + + True + + + + + + + + + + + + + + + + + + + + + + + + + True + + + + + + + + + + + + + + + + + + False + + + + + + + + + + True + + + + + + + + + + + + + + + + + + + + + + + + + + True + + + + + + + + + + + + + + + + + + + + + True + + + + + + + + + + + + + + + + + + True + + + + + + + + + + + + + + + True + + + + + + + + + + + + + + + + + + + + + False + + + + + + + + + + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + + + + + + + + + + + + + + + + + + + + + + + + + False + + + + + + + + + + + + + + + + + + + + + + + + + + False + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PrinterCommunication/RemotingLite/BuildProcessTemplates/LabDefaultTemplate.11.xaml b/PrinterCommunication/RemotingLite/BuildProcessTemplates/LabDefaultTemplate.11.xaml new file mode 100644 index 000000000..9e1fb0b51 --- /dev/null +++ b/PrinterCommunication/RemotingLite/BuildProcessTemplates/LabDefaultTemplate.11.xaml @@ -0,0 +1,208 @@ + + + + + + + + + + + + + + + 11.0 + + + + + + 920,3702 + Assembly references and imported namespaces serialized as XML namespaces + + + + + + + + + + + + + + + + + + + + + True + + + + + + + [LabWorkflowParameters.BuildDetails.BuildUri] + + + [ChildBuildDetail.Uri] + + + + + + + + + + + + [BuildLocation] + + + [If(LabWorkflowParameters.BuildDetails.Configuration Is Nothing, BuildLocation, If(LabWorkflowParameters.BuildDetails.Configuration.IsEmpty Or (SelectedBuildDetail.Information.GetNodesByType(Microsoft.TeamFoundation.Build.Common.InformationTypes.ConfigurationSummary, True)).Count = 1, BuildLocation, If(LabWorkflowParameters.BuildDetails.Configuration.IsPlatformEmptyOrAnyCpu, BuildLocation + "\" + LabWorkflowParameters.BuildDetails.Configuration.Configuration, BuildLocation + "\" + LabWorkflowParameters.BuildDetails.Configuration.Platform + "\" + LabWorkflowParameters.BuildDetails.Configuration.Configuration)))] + + + + + + + + + + + + [LabEnvironmentUri] + + + [LabWorkflowParameters.EnvironmentDetails.LabEnvironmentUri.ToString()] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [PostDeploymentSnapshotName] + + + [If(LabWorkflowParameters.BuildDetails.IsTeamSystemBuild = True,String.Format("{0}_{1}_{2}", LabWorkflowParameters.DeploymentDetails.PostDeploymentSnapshotName, BuildNumber,BuildDetail.BuildNumber),String.Format("{0}_{1}", LabWorkflowParameters.DeploymentDetails.PostDeploymentSnapshotName, BuildDetail.BuildNumber))] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [BuildStatus] + + + [Microsoft.TeamFoundation.Build.Client.BuildStatus.PartiallySucceeded] + + + + + + + [BuildStatus] + + + [Microsoft.TeamFoundation.Build.Client.BuildStatus.Failed] + + + + + + + + + + + + \ No newline at end of file diff --git a/PrinterCommunication/RemotingLite/BuildProcessTemplates/UpgradeTemplate.xaml b/PrinterCommunication/RemotingLite/BuildProcessTemplates/UpgradeTemplate.xaml new file mode 100644 index 000000000..166acb22c --- /dev/null +++ b/PrinterCommunication/RemotingLite/BuildProcessTemplates/UpgradeTemplate.xaml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + [New Microsoft.TeamFoundation.Build.Workflow.Activities.AgentSettings() With {.MaxWaitTime = New System.TimeSpan(4, 0, 0), .MaxExecutionTime = New System.TimeSpan(0, 0, 0), .TagComparison = Microsoft.TeamFoundation.Build.Workflow.Activities.TagComparison.MatchExactly }] + + + + [Microsoft.TeamFoundation.Build.Workflow.Activities.ToolPlatform.Auto] + [False] + [False] + + + + + + + + + + [Microsoft.TeamFoundation.VersionControl.Client.RecursionType.OneLevel] + [Microsoft.TeamFoundation.Build.Workflow.BuildVerbosity.Normal] + + + + All + Assembly references and imported namespaces serialized as XML namespaces + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PrinterCommunication/RemotingLite/Example/CommonTypes/CommonTypes.csproj b/PrinterCommunication/RemotingLite/Example/CommonTypes/CommonTypes.csproj new file mode 100644 index 000000000..f8dd5f7f6 --- /dev/null +++ b/PrinterCommunication/RemotingLite/Example/CommonTypes/CommonTypes.csproj @@ -0,0 +1,87 @@ + + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {04B850F0-5A39-4157-A227-A574064110D2} + Library + Properties + CommonTypes + CommonTypes + v4.0 + + + 2.0 + + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + \ No newline at end of file diff --git a/PrinterCommunication/RemotingLite/Example/CommonTypes/IService.cs b/PrinterCommunication/RemotingLite/Example/CommonTypes/IService.cs new file mode 100644 index 000000000..e3692b86b --- /dev/null +++ b/PrinterCommunication/RemotingLite/Example/CommonTypes/IService.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CommonTypes +{ + public interface IService + { + /// + /// An example with two integer arguments + /// + /// + /// + /// + int Sum(int a, int b); + + /// + /// An example with a variable number of arguments + /// + /// + /// + int Sum(params int[] values); + + /// + /// An example with a return value + /// + /// + /// + string ToUpper(string str); + + /// + /// An example with a ref argument + /// + /// + void MakeStringUpperCase(ref string str); + + /// + /// An example with an out argument + /// + /// + /// + void MakeStringLowerCase(string str, out string lowerCaseString); + + /// + /// An example which alters a user defined type. In the current version you + /// have to pass the value by reference in order to alter the object. + /// + /// + void CalculateArea(ref Rectangle rectangle); + + void Square(long a, out long b); + } +} diff --git a/PrinterCommunication/RemotingLite/Example/CommonTypes/Properties/AssemblyInfo.cs b/PrinterCommunication/RemotingLite/Example/CommonTypes/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..8b3888622 --- /dev/null +++ b/PrinterCommunication/RemotingLite/Example/CommonTypes/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CommonTypes")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CommonTypes")] +[assembly: AssemblyCopyright("Copyright © 2008")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c564b05d-1138-4417-8410-58622ceb142e")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PrinterCommunication/RemotingLite/Example/CommonTypes/Rectangle.cs b/PrinterCommunication/RemotingLite/Example/CommonTypes/Rectangle.cs new file mode 100644 index 000000000..0caa35746 --- /dev/null +++ b/PrinterCommunication/RemotingLite/Example/CommonTypes/Rectangle.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CommonTypes +{ + /// + /// A naive user defined type which we will use in the remoting example. + /// Remember that all types used must be serializable. + /// + [Serializable] + public class Rectangle + { + private int _width; + private int _height; + private int _area; + + public Rectangle(int height, int width) + { + _height = height; + _width = width; + _area = -1; //let the service calculate this + } + + public int Area + { + get { return _area; } + set { _area = value; } + } + + public int Height + { + get { return _height; } + } + + public int Width + { + get { return _width; } + } + } +} diff --git a/PrinterCommunication/RemotingLite/Example/RemotingLiteExample.sln b/PrinterCommunication/RemotingLite/Example/RemotingLiteExample.sln new file mode 100644 index 000000000..b57d64b3d --- /dev/null +++ b/PrinterCommunication/RemotingLite/Example/RemotingLiteExample.sln @@ -0,0 +1,50 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RemotingLiteExampleClient", "RemotingLiteExampleClient\RemotingLiteExampleClient.csproj", "{275568A0-7E5E-4151-8960-E54665FF5DF7}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RemotingLiteExampleServer", "RemotingLiteExampleServer\RemotingLiteExampleServer.csproj", "{EFBE44D0-1F61-42CF-9489-EED99AA1887F}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommonTypes", "CommonTypes\CommonTypes.csproj", "{04B850F0-5A39-4157-A227-A574064110D2}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RemotingLite", "..\src\RemotingLite.csproj", "{0AFFA4EB-EDEA-43CC-8045-C7D1FE557803}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {275568A0-7E5E-4151-8960-E54665FF5DF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {275568A0-7E5E-4151-8960-E54665FF5DF7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {275568A0-7E5E-4151-8960-E54665FF5DF7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {275568A0-7E5E-4151-8960-E54665FF5DF7}.Release|Any CPU.Build.0 = Release|Any CPU + {EFBE44D0-1F61-42CF-9489-EED99AA1887F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EFBE44D0-1F61-42CF-9489-EED99AA1887F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EFBE44D0-1F61-42CF-9489-EED99AA1887F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EFBE44D0-1F61-42CF-9489-EED99AA1887F}.Release|Any CPU.Build.0 = Release|Any CPU + {04B850F0-5A39-4157-A227-A574064110D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {04B850F0-5A39-4157-A227-A574064110D2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {04B850F0-5A39-4157-A227-A574064110D2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {04B850F0-5A39-4157-A227-A574064110D2}.Release|Any CPU.Build.0 = Release|Any CPU + {0AFFA4EB-EDEA-43CC-8045-C7D1FE557803}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0AFFA4EB-EDEA-43CC-8045-C7D1FE557803}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0AFFA4EB-EDEA-43CC-8045-C7D1FE557803}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0AFFA4EB-EDEA-43CC-8045-C7D1FE557803}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleClient/ClientProxyImpl.cs b/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleClient/ClientProxyImpl.cs new file mode 100644 index 000000000..02270bd8d --- /dev/null +++ b/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleClient/ClientProxyImpl.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Text; +using CommonTypes; +using RemotingLite; +using System.Net; + +namespace RemotingLiteExampleClient +{ + /// + /// This class is an example of how to subclass ClientBase in order to provide more + /// control over the calls. + /// Notice that any class inheriting from ClientBase has a Proxy-property, which + /// is a proxy of the interface specified. This proxy is generated with RemotingLite.ProxyFactory + /// and provides the contact to the host. + /// + /// Note the constructor! + /// + public class ClientProxyImpl : ClientBase, IService + { + /// + /// The class inheriting from ClientBase must define a constructor which takes + /// an end point to the host. You have to call the base constructor. + /// + /// + public ClientProxyImpl(IPEndPoint endpoint) + : base(endpoint) + { + } + + #region IService Members + + public int Sum(int a, int b) + { + return Proxy.Sum(a, b); + } + + public int Sum(params int[] values) + { + return Proxy.Sum(values); + } + + public string ToUpper(string str) + { + return Proxy.ToUpper(str); + } + + public void MakeStringUpperCase(ref string str) + { + Proxy.MakeStringUpperCase(ref str); + } + + public void MakeStringLowerCase(string str, out string lowerCaseString) + { + Proxy.MakeStringLowerCase(str, out lowerCaseString); + } + + public void CalculateArea(ref Rectangle rectangle) + { + Proxy.CalculateArea(ref rectangle); + } + + public void Square(long a, out long b) + { + Proxy.Square(a, out b); + } + + #endregion + } +} diff --git a/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleClient/ExampleUsingClientProxyImpl.cs b/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleClient/ExampleUsingClientProxyImpl.cs new file mode 100644 index 000000000..c70ba7c8f --- /dev/null +++ b/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleClient/ExampleUsingClientProxyImpl.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Net; +using System.Net.Sockets; +using CommonTypes; + +namespace RemotingLiteExampleClient +{ + /// + /// This class shows an example of how to use our own client proxy implementation + /// that inherits from ClientBase. + /// + public class ExampleUsingClientProxyImpl + { + public void Start(int port) + { + // This is an example that connects to the local host. See MSDN documentation. + // This will work if you run both client and host on the same machine. +#if true + IPAddress[] addressList = Dns.GetHostEntry(Dns.GetHostName()).AddressList; + IPAddress address = null; + foreach (var a in addressList) + if (a.AddressFamily == AddressFamily.InterNetwork) + { + address = a; + break; + } + IPEndPoint endpoint = new IPEndPoint(address, port); +#else + IPEndPoint endpoint = new IPEndPoint(Dns.GetHostEntry(Dns.GetHostName()).AddressList[0], 8000); +#endif + + // When using our own implementation we can use the "using" construct since ClientBase (and + // thus our implementation) implements IDisposable. + using (ClientProxyImpl client = new ClientProxyImpl(endpoint)) + { + + //make a few calls to the host + Console.WriteLine(client.Sum(2, 3)); + Console.WriteLine(client.Sum(2, 3, 4, 5, 6, 7, 8, 9)); + Console.WriteLine(client.ToUpper("this string used to be lower case")); + string str = "this was a lower case string"; + client.MakeStringUpperCase(ref str); + Console.WriteLine(str); + string lowerCaseString; + client.MakeStringLowerCase("THIS WAS AN UPPER CASE STRING", out lowerCaseString); + Console.WriteLine(lowerCaseString); + Rectangle rect = new Rectangle(30, 40); + Console.WriteLine(String.Format("Area before call : {0}", rect.Area)); + client.CalculateArea(ref rect); + Console.WriteLine(String.Format("Area after call : {0}", rect.Area)); + + long b; + client.Square(123, out b); + Console.WriteLine(string.Format("123 squared is {0}", b)); + } + } + } +} diff --git a/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleClient/ExampleUsingProxyFactory.cs b/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleClient/ExampleUsingProxyFactory.cs new file mode 100644 index 000000000..d51423086 --- /dev/null +++ b/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleClient/ExampleUsingProxyFactory.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Text; +using CommonTypes; +using RemotingLite; +using System.Net.Sockets; +using System.Net; + +namespace RemotingLiteExampleClient +{ + /// + /// This is an example of how to use ProxyFactory directly. + /// + public class ExampleUsingProxyFactory + { + public void Start(int port) + { + // This is an example that connects to the local host. See MSDN documentation. + // This will work if you run both client and host on the same machine. +#if true + IPAddress[] addressList = Dns.GetHostEntry(Dns.GetHostName()).AddressList; + IPAddress address = null; + foreach (var a in addressList) + if (a.AddressFamily == AddressFamily.InterNetwork) + { + address = a; + break; + } + IPEndPoint endpoint = new IPEndPoint(address, port); +#else + IPEndPoint endpoint = new IPEndPoint(Dns.GetHostEntry(Dns.GetHostName()).AddressList[0], 8000); +#endif + + // When using the proxy factory we do not need to write any client side code for the + // proxy. This might be usefull if you: + // 1) Want more control of when the connection is closed. This is done when the object is + // disposed. + // 2) Are lazy :-) + + //create the proxy + IService client = ProxyFactory.CreateProxy(endpoint); + + //make a few calls to the host + Console.WriteLine(client.Sum(2, 3)); + Console.WriteLine(client.Sum(2, 3, 4, 5, 6, 7, 8, 9)); + Console.WriteLine(client.ToUpper("this string used to be lower case")); + string str = "this was a lower case string"; + client.MakeStringUpperCase(ref str); + Console.WriteLine(str); + string lowerCaseString; + client.MakeStringLowerCase("THIS WAS AN UPPER CASE STRING", out lowerCaseString); + Console.WriteLine(lowerCaseString); + Rectangle rect = new Rectangle(30, 40); + Console.WriteLine(String.Format("Area before call : {0}", rect.Area)); + client.CalculateArea(ref rect); + Console.WriteLine(String.Format("Area after call : {0}", rect.Area)); + + long b; + client.Square(123, out b); + Console.WriteLine(string.Format("123 squared is {0}", b)); + + // You can either dispose (and thus close the connection) the object yourself, or wait + // for the garbage collector to do it for you when going out of scope of this method. + // Here we dispose it explicitly, + ((IDisposable)client).Dispose(); + } + } +} diff --git a/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleClient/Program.cs b/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleClient/Program.cs new file mode 100644 index 000000000..90ca9a10a --- /dev/null +++ b/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleClient/Program.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace RemotingLiteExampleClient +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Using our own implementation that inherits from ClientBase<>\n"); + ExampleUsingClientProxyImpl example1 = new ExampleUsingClientProxyImpl(); + example1.Start(8000); + + Console.WriteLine("\nUsing ProxyFactory to create a proxy directly.\n"); + ExampleUsingProxyFactory example2 = new ExampleUsingProxyFactory(); + example2.Start(8000); + + Console.ReadLine(); + } + } +} diff --git a/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleClient/Properties/AssemblyInfo.cs b/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleClient/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..f8adbc513 --- /dev/null +++ b/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleClient/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("RemotingLiteExampleClient")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("RemotingLiteExampleClient")] +[assembly: AssemblyCopyright("Copyright © 2008")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("400c12e2-5f51-4aec-b3f3-6a636d9d66c3")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleClient/RemotingLiteExampleClient.csproj b/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleClient/RemotingLiteExampleClient.csproj new file mode 100644 index 000000000..e057f8f98 --- /dev/null +++ b/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleClient/RemotingLiteExampleClient.csproj @@ -0,0 +1,102 @@ + + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {275568A0-7E5E-4151-8960-E54665FF5DF7} + Exe + Properties + RemotingLiteExampleClient + RemotingLiteExampleClient + v4.0 + + + 2.0 + + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + {0AFFA4EB-EDEA-43CC-8045-C7D1FE557803} + RemotingLite + + + {04B850F0-5A39-4157-A227-A574064110D2} + CommonTypes + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + \ No newline at end of file diff --git a/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleClient/app.config b/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleClient/app.config new file mode 100644 index 000000000..e36560333 --- /dev/null +++ b/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleClient/app.config @@ -0,0 +1,3 @@ + + + diff --git a/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleServer/Program.cs b/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleServer/Program.cs new file mode 100644 index 000000000..b8446da28 --- /dev/null +++ b/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleServer/Program.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; +using RemotingLite; + +namespace RemotingLiteExampleServer +{ + class Program + { + static void Main(string[] args) + { + using (ServiceHost host = new ServiceHost(typeof(ServiceImpl), 8000)) + { + host.UseThreadPool = true; + host.Open(); + + Console.WriteLine("Host is running. Press to terminate."); + Console.WriteLine(String.Format("Address is {0}", host.EndPoint.Address)); + Console.WriteLine("Press to terminate."); + Console.ReadLine(); + } + } + } +} diff --git a/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleServer/Properties/AssemblyInfo.cs b/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleServer/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..8abe256dd --- /dev/null +++ b/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleServer/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("RemotingLiteExampleServer")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("RemotingLiteExampleServer")] +[assembly: AssemblyCopyright("Copyright © 2008")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("fdee2604-d0ea-4f5d-a9c6-34ea06545b29")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleServer/RemotingLiteExampleServer.csproj b/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleServer/RemotingLiteExampleServer.csproj new file mode 100644 index 000000000..bd8fdc723 --- /dev/null +++ b/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleServer/RemotingLiteExampleServer.csproj @@ -0,0 +1,100 @@ + + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {EFBE44D0-1F61-42CF-9489-EED99AA1887F} + Exe + Properties + RemotingLiteExampleServer + RemotingLiteExampleServer + v4.0 + + + 2.0 + + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + {0AFFA4EB-EDEA-43CC-8045-C7D1FE557803} + RemotingLite + + + {04B850F0-5A39-4157-A227-A574064110D2} + CommonTypes + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + \ No newline at end of file diff --git a/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleServer/ServiceImpl.cs b/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleServer/ServiceImpl.cs new file mode 100644 index 000000000..92ec4fff6 --- /dev/null +++ b/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleServer/ServiceImpl.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Text; +using CommonTypes; + +namespace RemotingLiteExampleServer +{ + public class ServiceImpl : IService + { + #region IService Members + + public int Sum(int a, int b) + { + return a + b; + } + + public int Sum(params int[] values) + { + int sum = 0; + foreach (int value in values) + sum += value; + return sum; + } + + public string ToUpper(string str) + { + return str.ToUpper(); + } + + public void MakeStringUpperCase(ref string str) + { + str = str.ToUpper(); + } + + public void MakeStringLowerCase(string str, out string lowerCaseString) + { + lowerCaseString = str.ToLower(); + } + + public void CalculateArea(ref Rectangle rectangle) + { + rectangle.Area = rectangle.Width * rectangle.Height; + } + + public void Square(long a, out long b) + { + b = a * a; + } + + #endregion + } +} diff --git a/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleServer/app.config b/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleServer/app.config new file mode 100644 index 000000000..e36560333 --- /dev/null +++ b/PrinterCommunication/RemotingLite/Example/RemotingLiteExampleServer/app.config @@ -0,0 +1,3 @@ + + + diff --git a/PrinterCommunication/RemotingLite/Example/deps/Licence - RemotingLite.txt b/PrinterCommunication/RemotingLite/Example/deps/Licence - RemotingLite.txt new file mode 100644 index 000000000..cf5a42c24 --- /dev/null +++ b/PrinterCommunication/RemotingLite/Example/deps/Licence - RemotingLite.txt @@ -0,0 +1,26 @@ +RemotingLite licence + +Copyright (c) 2008, Frank Thomsen - http://sector0.dk +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of 'RemotingLite' nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY Frank Thomsen ``AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Frank Thomsen BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/PrinterCommunication/RemotingLite/Example/deps/RemotingLite.dll b/PrinterCommunication/RemotingLite/Example/deps/RemotingLite.dll new file mode 100644 index 000000000..672ca5950 Binary files /dev/null and b/PrinterCommunication/RemotingLite/Example/deps/RemotingLite.dll differ diff --git a/PrinterCommunication/RemotingLite/src/Channel.cs b/PrinterCommunication/RemotingLite/src/Channel.cs new file mode 100644 index 000000000..f414bd84a --- /dev/null +++ b/PrinterCommunication/RemotingLite/src/Channel.cs @@ -0,0 +1,161 @@ +/************************************************************************************************* + * RemotingLite + * ------ + * A light framework for making remote method invocations using TCP/IP. It is based loosely on + * Windows Communication Foundation, and is meant to provide programmers with the same API + * regardless of whether they write software for the Microsoft .NET platform or the Mono .NET + * platform. + * Consult the documentation and example applications for information about how to use this API. + * + * Author : Frank Thomsen + * http : http://sector0.dk + * Concact : http://sector0.dk/?q=contact + * Information : http://sector0.dk/?q=node/27 + * Licence : Free. If you use this, please let me know. + * + * Please feel free to contact me with ideas, bugs or improvements. + *************************************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Net; +using System.Net.Sockets; +using System.Runtime.Serialization.Formatters.Binary; +using System.IO; +using System.Reflection; +using System.Diagnostics; +using System.Runtime.Serialization; + +namespace RemotingLite +{ + public class Channel : IDisposable + { + private TcpClient _client; + private NetworkStream _stream; + private BinaryReader _binReader; + private BinaryWriter _binWriter; + private BinaryFormatter _formatter; + private ParameterTransferHelper _parameterTransferHelper = new ParameterTransferHelper(); + private List _syncInfos; + + /// + /// Creates a connection to the concrete object handling method calls on the server side + /// + /// + public Channel(IPEndPoint endpoint) + { + _client = new TcpClient(AddressFamily.InterNetwork); + _client.Connect(endpoint); + _client.NoDelay = true; + _stream = _client.GetStream(); + _binReader = new BinaryReader(_stream); + _binWriter = new BinaryWriter(_stream); + _formatter = new BinaryFormatter(); + SyncInterface(); + } + + /// + /// This method asks the server for a list of identifiers paired with method + /// names and -parameter types. This is used when invoking methods server side. + /// + private void SyncInterface() + { + //write the message type + _binWriter.Write((int)MessageType.SyncInterface); + + //read sync data + var ms = new MemoryStream(_binReader.ReadBytes(_binReader.ReadInt32())); + _syncInfos = (List)_formatter.Deserialize(ms); + } + + /// + /// Closes the connection to the server + /// + public void Close() + { + Dispose(); + } + + /// + /// Invokes the method with the specified parameters. + /// + /// The name of the method + /// Parameters for the method call + /// An array of objects containing the return value (index 0) and the parameters used to call + /// the method, including any marked as "ref" or "out" + protected object[] InvokeMethod(params object[] parameters) + { + //write the message type + _binWriter.Write((int)MessageType.MethodInvocation); + + //find the mathing server side method ident + var callingMethod = (new StackFrame(1)).GetMethod(); + var methodName = callingMethod.Name; + var methodParams = callingMethod.GetParameters(); + var ident = -1; + foreach (var si in _syncInfos) + { + //first of all the method names must match + if (si.MethodName == methodName) + { + //second of all the parameter types and -count must match + if (methodParams.Length == si.ParameterTypes.Length) + { + var matchingParameterTypes = true; + for (int i = 0; i < methodParams.Length; i++) + if (!methodParams[i].ParameterType.FullName.Equals(si.ParameterTypes[i].FullName)) + { + matchingParameterTypes = false; + break; + } + if (matchingParameterTypes) + { + ident = si.MethodIdent; + break; + } + } + } + } + + if (ident < 0) + throw new Exception(string.Format("Cannot match method '{0}' to its server side equivalent", callingMethod.Name)); + + //write the method ident to the server + _binWriter.Write(ident); + + //send the parameters + _parameterTransferHelper.SendParameters(_binWriter, parameters); + + _binWriter.Flush(); + _stream.Flush(); + + // Read the result of the invocation. + MessageType messageType = (MessageType)_binReader.ReadInt32(); + if (messageType == MessageType.UnknownMethod) + throw new Exception("Unknown method."); + + object[] outParams = _parameterTransferHelper.ReceiveParameters(_binReader); + + if (messageType == MessageType.ThrowException) + throw (Exception)outParams[0]; + + return outParams; + } + + #region IDisposable Members + + public void Dispose() + { + _binWriter.Write((int)MessageType.TerminateConnection); + _binWriter.Flush(); + _binWriter.Close(); + _binReader.Close(); + _stream.Flush(); + _stream.Close(); + _client.Close(); + } + + #endregion + } +} diff --git a/PrinterCommunication/RemotingLite/src/ClientBase.cs b/PrinterCommunication/RemotingLite/src/ClientBase.cs new file mode 100644 index 000000000..963beb573 --- /dev/null +++ b/PrinterCommunication/RemotingLite/src/ClientBase.cs @@ -0,0 +1,46 @@ +/************************************************************************************************* + * RemotingLite + * ------ + * A light framework for making remote method invocations using TCP/IP. It is based loosely on + * Windows Communication Foundation, and is meant to provide programmers with the same API + * regardless of whether they write software for the Microsoft .NET platform or the Mono .NET + * platform. + * Consult the documentation and example applications for information about how to use this API. + * + * Author : Frank Thomsen + * http : http://sector0.dk + * Concact : http://sector0.dk/?q=contact + * Information : http://sector0.dk/?q=node/27 + * Licence : Free. If you use this, please let me know. + * + * Please feel free to contact me with ideas, bugs or improvements. + *************************************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Net; + +namespace RemotingLite +{ + public abstract class ClientBase : IDisposable where TInterface : class + { + private TInterface _proxy; + + public TInterface Proxy { get { return _proxy; } } + + public ClientBase(IPEndPoint endpoint) + { + _proxy = ProxyFactory.CreateProxy(endpoint); + } + + #region IDisposable Members + + public void Dispose() + { + (_proxy as Channel).Dispose(); + } + + #endregion + } +} diff --git a/PrinterCommunication/RemotingLite/src/Licence - RemotingLite.txt b/PrinterCommunication/RemotingLite/src/Licence - RemotingLite.txt new file mode 100644 index 000000000..cf5a42c24 --- /dev/null +++ b/PrinterCommunication/RemotingLite/src/Licence - RemotingLite.txt @@ -0,0 +1,26 @@ +RemotingLite licence + +Copyright (c) 2008, Frank Thomsen - http://sector0.dk +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of 'RemotingLite' nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY Frank Thomsen ``AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Frank Thomsen BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/PrinterCommunication/RemotingLite/src/MessageType.cs b/PrinterCommunication/RemotingLite/src/MessageType.cs new file mode 100644 index 000000000..144a16f10 --- /dev/null +++ b/PrinterCommunication/RemotingLite/src/MessageType.cs @@ -0,0 +1,34 @@ +/************************************************************************************************* + * RemotingLite + * ------ + * A light framework for making remote method invocations using TCP/IP. It is based loosely on + * Windows Communication Foundation, and is meant to provide programmers with the same API + * regardless of whether they write software for the Microsoft .NET platform or the Mono .NET + * platform. + * Consult the documentation and example applications for information about how to use this API. + * + * Author : Frank Thomsen + * http : http://sector0.dk + * Concact : http://sector0.dk/?q=contact + * Information : http://sector0.dk/?q=node/27 + * Licence : Free. If you use this, please let me know. + * + * Please feel free to contact me with ideas, bugs or improvements. + *************************************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace RemotingLite +{ + internal enum MessageType + { + TerminateConnection = 0, + MethodInvocation = 1, + ReturnValues = 2, + UnknownMethod = 3, + ThrowException = 4, + SyncInterface = 5 + }; +} diff --git a/PrinterCommunication/RemotingLite/src/ParameterTransferHelper.cs b/PrinterCommunication/RemotingLite/src/ParameterTransferHelper.cs new file mode 100644 index 000000000..b3fdab43e --- /dev/null +++ b/PrinterCommunication/RemotingLite/src/ParameterTransferHelper.cs @@ -0,0 +1,241 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; +using System.Runtime.Serialization.Formatters.Binary; + +namespace RemotingLite +{ + internal sealed class ParameterTypes + { + internal const byte Unknown = 0x00; + internal const byte Bool = 0x01; + internal const byte Byte = 0x02; + internal const byte SByte = 0x03; + internal const byte Char = 0x04; + internal const byte Decimal = 0x05; + internal const byte Double = 0x06; + internal const byte Float = 0x07; + internal const byte Int = 0x08; + internal const byte UInt = 0x09; + internal const byte Long = 0x0A; + internal const byte ULong = 0x0B; + internal const byte Short = 0x0C; + internal const byte UShort = 0x0D; + internal const byte String = 0x0E; + internal const byte ByteArray = 0x0F; + internal const byte CharArray = 0x10; + internal const byte Null = 0x11; + internal const byte Type = 0x12; + } + + internal sealed class ParameterTransferHelper + { + private Dictionary _parameterTypes; + + internal ParameterTransferHelper() + { + _parameterTypes = new Dictionary(); + _parameterTypes.Add(typeof(bool), ParameterTypes.Bool); + _parameterTypes.Add(typeof(byte), ParameterTypes.Byte); + _parameterTypes.Add(typeof(sbyte), ParameterTypes.SByte); + _parameterTypes.Add(typeof(char), ParameterTypes.Char); + _parameterTypes.Add(typeof(decimal), ParameterTypes.Decimal); + _parameterTypes.Add(typeof(double), ParameterTypes.Double); + _parameterTypes.Add(typeof(float), ParameterTypes.Float); + _parameterTypes.Add(typeof(int), ParameterTypes.Int); + _parameterTypes.Add(typeof(uint), ParameterTypes.UInt); + _parameterTypes.Add(typeof(long), ParameterTypes.Long); + _parameterTypes.Add(typeof(ulong), ParameterTypes.ULong); + _parameterTypes.Add(typeof(short), ParameterTypes.Short); + _parameterTypes.Add(typeof(ushort), ParameterTypes.UShort); + _parameterTypes.Add(typeof(string), ParameterTypes.String); + _parameterTypes.Add(typeof(byte[]), ParameterTypes.ByteArray); + _parameterTypes.Add(typeof(char[]), ParameterTypes.CharArray); + _parameterTypes.Add(typeof(Type), ParameterTypes.Type); + } + + internal void SendParameters(BinaryWriter writer, params object[] parameters) + { + MemoryStream ms; + BinaryFormatter formatter = new BinaryFormatter(); + //write how many parameters are coming + writer.Write(parameters.Length); + //write data for each parameter + foreach (object parameter in parameters) + { + if (parameter != null) + { + Type type = parameter.GetType(); + byte typeByte = GetParameterType(type); + //write the type byte + writer.Write(typeByte); + //write the parameter + switch (typeByte) + { + case ParameterTypes.Bool: + writer.Write((bool)parameter); + break; + case ParameterTypes.Byte: + writer.Write((byte)parameter); + break; + case ParameterTypes.ByteArray: + byte[] byteArray = (byte[])parameter; + writer.Write(byteArray.Length); + writer.Write(byteArray); + break; + case ParameterTypes.Char: + writer.Write((char)parameter); + break; + case ParameterTypes.CharArray: + char[] charArray = (char[])parameter; + writer.Write(charArray.Length); + writer.Write(charArray); + break; + case ParameterTypes.Decimal: + writer.Write((decimal)parameter); + break; + case ParameterTypes.Double: + writer.Write((double)parameter); + break; + case ParameterTypes.Float: + writer.Write((float)parameter); + break; + case ParameterTypes.Int: + writer.Write((int)parameter); + break; + case ParameterTypes.Long: + writer.Write((long)parameter); + break; + case ParameterTypes.SByte: + writer.Write((sbyte)parameter); + break; + case ParameterTypes.Short: + writer.Write((short)parameter); + break; + case ParameterTypes.String: + writer.Write((string)parameter); + break; + case ParameterTypes.UInt: + writer.Write((uint)parameter); + break; + case ParameterTypes.ULong: + writer.Write((ulong)parameter); + break; + case ParameterTypes.UShort: + writer.Write((ushort)parameter); + break; + case ParameterTypes.Type: + writer.Write(((Type)parameter).FullName); + break; + case ParameterTypes.Unknown: + ms = new MemoryStream(); + formatter.Serialize(ms, parameter); + ms.Seek(0, SeekOrigin.Begin); + //write length of data + writer.Write((int)ms.Length); + //write data + writer.Write(ms.ToArray()); + break; + default: + throw new Exception(string.Format("Unknown type byte '0x{0:X}'", typeByte)); + } + } + else + writer.Write(ParameterTypes.Null); + } + } + + internal object[] ReceiveParameters(BinaryReader reader) + { + int parameterCount = reader.ReadInt32(); + object[] parameters = new object[parameterCount]; + MemoryStream ms; + BinaryFormatter formatter = new BinaryFormatter(); + for (int i = 0; i < parameterCount; i++) + { + //read type byte + byte typeByte = reader.ReadByte(); + if (typeByte == ParameterTypes.Null) + parameters[i] = null; + else + { + int count; + switch (typeByte) + { + case ParameterTypes.Bool: + parameters[i] = reader.ReadBoolean(); + break; + case ParameterTypes.Byte: + parameters[i] = reader.ReadByte(); + break; + case ParameterTypes.ByteArray: + count = reader.ReadInt32(); + parameters[i] = reader.ReadBytes(count); + break; + case ParameterTypes.Char: + parameters[i] = reader.ReadChar(); + break; + case ParameterTypes.CharArray: + count = reader.ReadInt32(); + parameters[i] = reader.ReadChars(count); + break; + case ParameterTypes.Decimal: + parameters[i] = reader.ReadDecimal(); + break; + case ParameterTypes.Double: + parameters[i] = reader.ReadDouble(); + break; + case ParameterTypes.Float: + parameters[i] = reader.ReadSingle(); + break; + case ParameterTypes.Int: + parameters[i] = reader.ReadInt32(); + break; + case ParameterTypes.Long: + parameters[i] = reader.ReadInt64(); + break; + case ParameterTypes.SByte: + parameters[i] = reader.ReadSByte(); + break; + case ParameterTypes.Short: + parameters[i] = reader.ReadInt16(); + break; + case ParameterTypes.String: + parameters[i] = reader.ReadString(); + break; + case ParameterTypes.UInt: + parameters[i] = reader.ReadUInt32(); + break; + case ParameterTypes.ULong: + parameters[i] = reader.ReadUInt64(); + break; + case ParameterTypes.UShort: + parameters[i] = reader.ReadUInt16(); + break; + case ParameterTypes.Type: + var typeName = reader.ReadString(); + parameters[i] = Type.GetType(typeName); + break; + case ParameterTypes.Unknown: + ms = new MemoryStream(reader.ReadBytes(reader.ReadInt32())); + //deserialize the parameter array + parameters[i] = formatter.Deserialize(ms); + break; + default: + throw new Exception(string.Format("Unknown type byte '0x{0:X}'", typeByte)); + } + } + } + return parameters; + } + + private byte GetParameterType(Type type) + { + if (_parameterTypes.ContainsKey(type)) + return _parameterTypes[type]; + else + return ParameterTypes.Unknown; + } + } +} diff --git a/PrinterCommunication/RemotingLite/src/Properties/AssemblyInfo.cs b/PrinterCommunication/RemotingLite/src/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..65909c68f --- /dev/null +++ b/PrinterCommunication/RemotingLite/src/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("RemotingLite")] +[assembly: AssemblyDescription("A light framework for remote method invocation")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("http://sector0.dk")] +[assembly: AssemblyProduct("RemotingLite")] +[assembly: AssemblyCopyright("Copyright © 2008 Frank Thomsen")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("0a4da926-e000-4481-955e-f8723aa69962")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.3.0.0")] +[assembly: AssemblyFileVersion("1.3.0.0")] diff --git a/PrinterCommunication/RemotingLite/src/ProxyFactory.cs b/PrinterCommunication/RemotingLite/src/ProxyFactory.cs new file mode 100644 index 000000000..5cbe0bb73 --- /dev/null +++ b/PrinterCommunication/RemotingLite/src/ProxyFactory.cs @@ -0,0 +1,212 @@ +/************************************************************************************************* + * RemotingLite + * ------ + * A light framework for making remote method invocations using TCP/IP. It is based loosely on + * Windows Communication Foundation, and is meant to provide programmers with the same API + * regardless of whether they write software for the Microsoft .NET platform or the Mono .NET + * platform. + * Consult the documentation and example applications for information about how to use this API. + * + * Author : Frank Thomsen + * http : http://sector0.dk + * Concact : http://sector0.dk/?q=contact + * Information : http://sector0.dk/?q=node/27 + * Licence : Free. If you use this, please let me know. + * + * Please feel free to contact me with ideas, bugs or improvements. + *************************************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Net; +using System.Reflection.Emit; +using System.Reflection; +using System.Threading; + +namespace RemotingLite +{ + public sealed class ProxyFactory + { + public static TInterface CreateProxy(IPEndPoint endpoint) where TInterface : class + { + AppDomain domain = Thread.GetDomain(); + // create a new assembly for the proxy + AssemblyBuilder assemblyBuilder = domain.DefineDynamicAssembly(new AssemblyName("ProxyAssembly"), AssemblyBuilderAccess.Run); + + // create a new module for the proxy + ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("ProxyModule", true); + + // Set the class to be public and sealed + TypeAttributes typeAttributes = TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed; + + // Construct the type builder + TypeBuilder typeBuilder = moduleBuilder.DefineType(typeof(TInterface).Name + "Proxy", typeAttributes, typeof(Channel)); + List allInterfaces = new List(typeof(TInterface).GetInterfaces()); + allInterfaces.Add(typeof(TInterface)); + + //add the interface + typeBuilder.AddInterfaceImplementation(typeof(TInterface)); + + //construct the constructor + Type[] ctorArgTypes = new Type[] { typeof(IPEndPoint) }; + CreateConstructor(typeBuilder, ctorArgTypes); + + //construct the type maps + Dictionary ldindOpCodeTypeMap = new Dictionary(); + ldindOpCodeTypeMap.Add(typeof(Boolean), OpCodes.Ldind_I1); + ldindOpCodeTypeMap.Add(typeof(Byte), OpCodes.Ldind_U1); + ldindOpCodeTypeMap.Add(typeof(SByte), OpCodes.Ldind_I1); + ldindOpCodeTypeMap.Add(typeof(Int16), OpCodes.Ldind_I2); + ldindOpCodeTypeMap.Add(typeof(UInt16), OpCodes.Ldind_U2); + ldindOpCodeTypeMap.Add(typeof(Int32), OpCodes.Ldind_I4); + ldindOpCodeTypeMap.Add(typeof(UInt32), OpCodes.Ldind_U4); + ldindOpCodeTypeMap.Add(typeof(Int64), OpCodes.Ldind_I8); + ldindOpCodeTypeMap.Add(typeof(UInt64), OpCodes.Ldind_I8); + ldindOpCodeTypeMap.Add(typeof(Char), OpCodes.Ldind_U2); + ldindOpCodeTypeMap.Add(typeof(Double), OpCodes.Ldind_R8); + ldindOpCodeTypeMap.Add(typeof(Single), OpCodes.Ldind_R4); + Dictionary stindOpCodeTypeMap = new Dictionary(); + stindOpCodeTypeMap.Add(typeof(Boolean), OpCodes.Stind_I1); + stindOpCodeTypeMap.Add(typeof(Byte), OpCodes.Stind_I1); + stindOpCodeTypeMap.Add(typeof(SByte), OpCodes.Stind_I1); + stindOpCodeTypeMap.Add(typeof(Int16), OpCodes.Stind_I2); + stindOpCodeTypeMap.Add(typeof(UInt16), OpCodes.Stind_I2); + stindOpCodeTypeMap.Add(typeof(Int32), OpCodes.Stind_I4); + stindOpCodeTypeMap.Add(typeof(UInt32), OpCodes.Stind_I4); + stindOpCodeTypeMap.Add(typeof(Int64), OpCodes.Stind_I8); + stindOpCodeTypeMap.Add(typeof(UInt64), OpCodes.Stind_I8); + stindOpCodeTypeMap.Add(typeof(Char), OpCodes.Stind_I2); + stindOpCodeTypeMap.Add(typeof(Double), OpCodes.Stind_R8); + stindOpCodeTypeMap.Add(typeof(Single), OpCodes.Stind_R4); + + //construct the method builders from the method infos defined in the interface + List methods = GetAllMethods(allInterfaces); + foreach (MethodInfo methodInfo in methods) + { + MethodBuilder methodBuilder = ConstructMethod(methodInfo, typeBuilder, ldindOpCodeTypeMap, stindOpCodeTypeMap); + typeBuilder.DefineMethodOverride(methodBuilder, methodInfo); + } + + //create the type and construct an instance + Type t = typeBuilder.CreateType(); + TInterface instance = (TInterface)t.GetConstructor(ctorArgTypes).Invoke(new object[] { endpoint }); + + return instance; + } + + private static List GetAllMethods(List allInterfaces) + { + List methods = new List(); + foreach (Type interfaceType in allInterfaces) + methods.AddRange(interfaceType.GetMethods()); + return methods; + } + + private static void CreateConstructor(TypeBuilder typeBuilder, Type[] ctorArgTypes) + { + ConstructorBuilder ctor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, ctorArgTypes); + ConstructorInfo baseCtor = typeof(Channel).GetConstructor(ctorArgTypes); + + ILGenerator ctorIL = ctor.GetILGenerator(); + ctorIL.Emit(OpCodes.Ldarg_0); //load "this" + ctorIL.Emit(OpCodes.Ldarg_1); //load "endpoint" + ctorIL.Emit(OpCodes.Call, baseCtor); //call "base(...)" + ctorIL.Emit(OpCodes.Ret); + } + + private static MethodBuilder ConstructMethod(MethodInfo methodInfo, TypeBuilder typeBuilder, Dictionary ldindOpCodeTypeMap, Dictionary stindOpCodeTypeMap) + { + ParameterInfo[] paramInfos = methodInfo.GetParameters(); + int nofParams = paramInfos.Length; + Type[] parameterTypes = new Type[nofParams]; + for (int i = 0; i < nofParams; i++) + parameterTypes[i] = paramInfos[i].ParameterType; + Type returnType = methodInfo.ReturnType; + MethodBuilder methodBuilder = typeBuilder.DefineMethod(methodInfo.Name, MethodAttributes.Public | MethodAttributes.Virtual, returnType, parameterTypes); + + ILGenerator mIL = methodBuilder.GetILGenerator(); + GenerateILCodeForMethod(mIL, parameterTypes, methodBuilder.ReturnType, ldindOpCodeTypeMap, stindOpCodeTypeMap); + return methodBuilder; + } + + private static void GenerateILCodeForMethod(ILGenerator mIL, Type[] inputArgTypes, Type returnType, Dictionary ldindOpCodeTypeMap, Dictionary stindOpCodeTypeMap) + { + int nofArgs = inputArgTypes.Length; + //get the MethodInfo for InvokeMethod + MethodInfo invokeMethodMI = typeof(Channel).GetMethod("InvokeMethod", BindingFlags.Instance | BindingFlags.NonPublic); + //declare local variables + LocalBuilder resultLB = mIL.DeclareLocal(typeof(object[])); // object[] result + + mIL.Emit(OpCodes.Ldarg_0); //load "this" + mIL.Emit(OpCodes.Ldc_I4, nofArgs); //push the number of arguments + mIL.Emit(OpCodes.Newarr, typeof(object)); //create an array of objects + + //store every input argument in the args array + for (int i = 0; i < nofArgs; i++) + { + Type inputType = inputArgTypes[i].IsByRef ? inputArgTypes[i].GetElementType() : inputArgTypes[i]; + + mIL.Emit(OpCodes.Dup); + mIL.Emit(OpCodes.Ldc_I4, i); //push the index onto the stack + mIL.Emit(OpCodes.Ldarg, i + 1); //load the i'th argument. This might be an address + if (inputArgTypes[i].IsByRef) + { + if (inputType.IsValueType) + { + mIL.Emit(ldindOpCodeTypeMap[inputType]); + mIL.Emit(OpCodes.Box, inputType); + } + else + mIL.Emit(OpCodes.Ldind_Ref); + } + else + { + if (inputArgTypes[i].IsValueType) + mIL.Emit(OpCodes.Box, inputArgTypes[i]); + } + mIL.Emit(OpCodes.Stelem_Ref); //store the reference in the args array + } + mIL.Emit(OpCodes.Call, invokeMethodMI); + mIL.Emit(OpCodes.Stloc, resultLB.LocalIndex); //store the result + //store the results in the arguments + for (int i = 0; i < nofArgs; i++) + { + if (inputArgTypes[i].IsByRef) + { + Type inputType = inputArgTypes[i].GetElementType(); + mIL.Emit(OpCodes.Ldarg, i + 1); //load the address of the argument + mIL.Emit(OpCodes.Ldloc, resultLB.LocalIndex); //load the result array + mIL.Emit(OpCodes.Ldc_I4, i + 1); //load the index into the result array + mIL.Emit(OpCodes.Ldelem_Ref); //load the value in the index of the array + if (inputType.IsValueType) + { + mIL.Emit(OpCodes.Unbox, inputArgTypes[i].GetElementType()); + mIL.Emit(ldindOpCodeTypeMap[inputArgTypes[i].GetElementType()]); + mIL.Emit(stindOpCodeTypeMap[inputArgTypes[i].GetElementType()]); + } + else + { + mIL.Emit(OpCodes.Castclass, inputArgTypes[i].GetElementType()); + mIL.Emit(OpCodes.Stind_Ref); //store the unboxed value at the argument address + } + } + } + if (returnType != typeof(void)) + { + mIL.Emit(OpCodes.Ldloc, resultLB.LocalIndex); //load the result array + mIL.Emit(OpCodes.Ldc_I4, 0); //load the index of the return value. Alway 0 + mIL.Emit(OpCodes.Ldelem_Ref); //load the value in the index of the array + + if (returnType.IsValueType) + { + mIL.Emit(OpCodes.Unbox, returnType); //unbox it + mIL.Emit(ldindOpCodeTypeMap[returnType]); + } + else + mIL.Emit(OpCodes.Castclass, returnType); + } + mIL.Emit(OpCodes.Ret); + } + } +} diff --git a/PrinterCommunication/RemotingLite/src/Release Notes.txt b/PrinterCommunication/RemotingLite/src/Release Notes.txt new file mode 100644 index 000000000..1512d2a72 --- /dev/null +++ b/PrinterCommunication/RemotingLite/src/Release Notes.txt @@ -0,0 +1,45 @@ +1.2.4 -> 1.2.5 +o Fixed error with exceptions. When an exception is thrown server side it will now be rethrown at the client. + Thanks to Pierre Chalamet for the patch. + +1.2.3 -> 1.2.4 +=============== +o Forced the TcpClient used in communication to use IP v. 4. This will enable the framework to run on Windows Vista, where + the default protocol seems to be IP v. 6, preventing the framework from working properly. + Thanks to Maneesak Pimsarn for providing the solution. + +1.2.2 -> 1.2.3 +=============== +o Further optimized the serialization if the parameters of the method being invoked are one of the following simple + types: bool, byte, sbyte, char, decimal, double, float, int, uint, long, ulong, short, ushort, string, byte[], char[] + This gives a performance gain of up to 33% if the parameters are all one of the simple types. + +1.2.1 -> 1.2.2 +=============== +o Fixed problem with out-parameters. The wrong opcodes where generated for the IL-code of the proxies, and the wrong type parameter was + checked for when assigning ref- and out-parameter values. + +1.2 -> 1.2.1 +=============== +o Fixed the Mono incompatibility problem with the proxies generated by ProxyFactory. + +1.1 -> 1.2 +=============== +o Significant performance improvements by a factor of 70-100 when communicating on network. + - Better and more efficient serialization and deserialization. + - A bit of transport protocol tuning. + - Only sending argument values back to the client when the argument is by reference. +o It is now possible to let the service host use thread pool threads instead of regular background threads. + + +Version 1.1.0 +============== +o RemotingHost renamed to ServiceHost +o Added the property "EndPoint" to ServiceHost that specifies the end point the host is accepting incoming connections on. +o Renamed RemotingClientBase to ClientBase, and made it internal +o Added ProxyFactory which constructs proxies based on an interface. The instance coming out inherits from ClientBase. + This eliminates the need to write your own implementations of the proxies, and with all the type casting that was + necessary in version 1.0. This is automatically handled in the proxy. +o Added ClientBase. Subclass this when you want more control over what happens when invoking the host. This is also + necessary if you are implementing with the "using" keyword, since the instance needs to be castable to IDisposable. +o Added support for exceptions. \ No newline at end of file diff --git a/PrinterCommunication/RemotingLite/src/RemotingLite.csproj b/PrinterCommunication/RemotingLite/src/RemotingLite.csproj new file mode 100644 index 000000000..7299aa4c4 --- /dev/null +++ b/PrinterCommunication/RemotingLite/src/RemotingLite.csproj @@ -0,0 +1,102 @@ + + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {0AFFA4EB-EDEA-43CC-8045-C7D1FE557803} + Library + Properties + RemotingLite + RemotingLite + v4.0 + + + 2.0 + + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AllRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + + + + + + + + + + + + + + + + + + + + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + \ No newline at end of file diff --git a/PrinterCommunication/RemotingLite/src/RemotingLite.sln b/PrinterCommunication/RemotingLite/src/RemotingLite.sln new file mode 100644 index 000000000..7c9ea85ec --- /dev/null +++ b/PrinterCommunication/RemotingLite/src/RemotingLite.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RemotingLite", "RemotingLite.csproj", "{0AFFA4EB-EDEA-43CC-8045-C7D1FE557803}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0AFFA4EB-EDEA-43CC-8045-C7D1FE557803}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0AFFA4EB-EDEA-43CC-8045-C7D1FE557803}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0AFFA4EB-EDEA-43CC-8045-C7D1FE557803}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0AFFA4EB-EDEA-43CC-8045-C7D1FE557803}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/PrinterCommunication/RemotingLite/src/ServiceHost.cs b/PrinterCommunication/RemotingLite/src/ServiceHost.cs new file mode 100644 index 000000000..abf15c0ac --- /dev/null +++ b/PrinterCommunication/RemotingLite/src/ServiceHost.cs @@ -0,0 +1,342 @@ +/************************************************************************************************* + * RemotingLite + * ------ + * A light framework for making remote method invocations using TCP/IP. It is based loosely on + * Windows Communication Foundation, and is meant to provide programmers with the same API + * regardless of whether they write software for the Microsoft .NET platform or the Mono .NET + * platform. + * Consult the documentation and example applications for information about how to use this API. + * + * Author : Frank Thomsen + * http : http://sector0.dk + * Concact : http://sector0.dk/?q=contact + * Information : http://sector0.dk/?q=node/27 + * Licence : Free. If you use this, please let me know. + * + * Please feel free to contact me with ideas, bugs or improvements. + *************************************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Net.Sockets; +using System.Net; +using System.Threading; +using System.Reflection; +using System.IO; +using System.Runtime.Serialization.Formatters.Binary; +using System.Reflection.Emit; +using System.IO.Compression; + +namespace RemotingLite +{ + [Serializable] + internal class MethodSyncInfo + { + public int MethodIdent { get; set; } + public string MethodName { get; set; } + public Type[] ParameterTypes { get; set; } + } + + public class ServiceHost : IDisposable + { + private bool _isOpen = false; + private TcpListener _listener; + private List _clients; + private bool _continueListening; + private object _continueListeningLock = new object(); + private object _singletonInstance; + private IPEndPoint _endPoint; + private bool _useThreadPool = false; + private Dictionary _interfaceMethods; + private Dictionary _methodParametersByRef; + private ParameterTransferHelper _parameterTransferHelper = new ParameterTransferHelper(); + + private bool Continue + { + get + { + lock (_continueListeningLock) + { + return _continueListening; + } + } + set + { + lock (_continueListeningLock) + { + _continueListening = value; + } + } + } + + /// + /// Get or set whether the host should use regular or thread pool threads. + /// + public bool UseThreadPool + { + get { return _useThreadPool; } + set + { + if (_isOpen) + throw new Exception("The host is already open"); + _useThreadPool = value; + } + } + + /// + /// Constructs an instance of the host and starts listening for incoming connections. + /// All listener threads are regular background threads. + /// + /// NOTE: the instance created from the specified type is not automatically thread safe! + /// + /// The remoted type. This must have a default constructor + /// The port number for incoming requests + public ServiceHost(Type remotedType, int port) + : this(Activator.CreateInstance(remotedType), port) + { + } + + /// + /// Constructs an instance of the host and starts listening for incoming connections. + /// All listener threads are regular background threads. + /// + /// NOTE: the instance is not automatically thread safe! + /// + /// The singleton instance of the service + /// The port number for incoming requests + public ServiceHost(object singletonInstance, int port) + { + IPAddress[] addressList = Dns.GetHostEntry(Dns.GetHostName()).AddressList; + IPAddress address = null; + foreach (var a in addressList) + if (a.AddressFamily == AddressFamily.InterNetwork) + { + address = a; + break; + } + _endPoint = new IPEndPoint(address, port); + _listener = new TcpListener(_endPoint); + _clients = new List(); + _continueListening = true; + _singletonInstance = singletonInstance; + CreateMethodMap(); + } + + /// + /// Loads all methods from interfaces and assigns an identifier + /// to each. These are later synchronized with the client. + /// + private void CreateMethodMap() + { + var interfaces = _singletonInstance.GetType().GetInterfaces(); + _interfaceMethods = new Dictionary(); + _methodParametersByRef = new Dictionary(); + var currentMethodIdent = 0; + foreach (var interfaceType in interfaces) + { + var methodInfos = interfaceType.GetMethods(); + foreach (var mi in methodInfos) + { + _interfaceMethods.Add(currentMethodIdent, mi); + var parameterInfos = mi.GetParameters(); + var isByRef = new bool[parameterInfos.Length]; + for (int i = 0; i < isByRef.Length; i++) + isByRef[i] = parameterInfos[i].ParameterType.IsByRef; + _methodParametersByRef.Add(currentMethodIdent, isByRef); + currentMethodIdent++; + } + } + } + + /// + /// Gets the end point this host is listening on + /// + public IPEndPoint EndPoint + { + get { return _endPoint; } + } + + /// + /// Opens the host and starts a listener thread. This listener thread spawns a new thread (or uses a + /// thread pool thread) for each incoming connection. + /// + public void Open() + { + //start listening in the background + if (_useThreadPool) + ThreadPool.QueueUserWorkItem(ListenerThreadProc); + else + { + Thread t = new Thread(ListenerThreadProc); + t.IsBackground = true; + t.Start(); + } + _isOpen = true; + } + + /// + /// Closes the host and calls Dispose(). + /// + public void Close() + { + Dispose(); + } + + /// + /// Listens for incoming requests. + /// + /// This method runs in a separate thread + /// + /// + private void ListenerThreadProc(object state) + { + _listener.Start(); + while (Continue) + { + try + { + TcpClient client = _listener.AcceptTcpClient(); + _clients.Add(client); + + if (_useThreadPool) + ThreadPool.QueueUserWorkItem(ClientThreadProc, client); + else + { + Thread t = new Thread(ClientThreadProc); + t.IsBackground = true; + t.Start(client); + } + } + catch (SocketException) //this is normal since the thread is a background thread + { + Continue = false; + } + } + } + + /// + /// This method handles all requests from a single client. + /// + /// There is one thread running this method for each connected client. + /// + /// + private void ClientThreadProc(object state) + { + TcpClient client = (TcpClient)state; + client.NoDelay = true; + Stream stream = client.GetStream(); + BinaryReader binReader = new BinaryReader(stream); + BinaryWriter binWriter = new BinaryWriter(stream); + bool doContinue = true; + do + { + try + { + MemoryStream ms; + BinaryFormatter formatter = new BinaryFormatter(); + //read message type + MessageType messageType = (MessageType)binReader.ReadInt32(); + switch (messageType) + { + case MessageType.SyncInterface: + //Create a list of sync infos from the dictionary + var syncInfos = new List(); + foreach(var kvp in _interfaceMethods) + { + var parameters = kvp.Value.GetParameters(); + var parameterTypes = new Type[parameters.Length]; + for (var i = 0; i < parameters.Length; i++) + parameterTypes[i] = parameters[i].ParameterType; + syncInfos.Add(new MethodSyncInfo { MethodIdent = kvp.Key, MethodName = kvp.Value.Name, ParameterTypes = parameterTypes }); + } + + //send the sync data back to the client + ms = new MemoryStream(); + formatter.Serialize(ms, syncInfos); + ms.Seek(0, SeekOrigin.Begin); + binWriter.Write((int)ms.Length); + binWriter.Write(ms.ToArray()); + binWriter.Flush(); + stream.Flush(); + break; + case MessageType.MethodInvocation: + //read the method identifier + int methodHashCode = binReader.ReadInt32(); + if (_interfaceMethods.ContainsKey(methodHashCode)) + { + var method = _interfaceMethods[methodHashCode]; + var isByRef = _methodParametersByRef[methodHashCode]; + + //read parameter data + var parameters = _parameterTransferHelper.ReceiveParameters(binReader); + + //invoke the method + object[] returnParameters; + var returnMessageType = MessageType.ReturnValues; + try + { + object returnValue = method.Invoke(_singletonInstance, parameters); + //the result to the client is the return value (null if void) and the input parameters + returnParameters = new object[1 + parameters.Length]; + returnParameters[0] = returnValue; + for (int i = 0; i < parameters.Length; i++) + returnParameters[i + 1] = isByRef[i] ? parameters[i] : null; + } + catch (Exception ex) + { + //an exception was caught. Rethrow it client side + returnParameters = new object[] { ex }; + returnMessageType = MessageType.ThrowException; + } + + //send the result back to the client + // (1) write the message type + binWriter.Write((int)returnMessageType); + // (2) write the return parameters + _parameterTransferHelper.SendParameters(binWriter, returnParameters); + } + else + binWriter.Write((int)MessageType.UnknownMethod); + + //flush + binWriter.Flush(); + stream.Flush(); + break; + case MessageType.TerminateConnection: + doContinue = false; + break; + default: + break; + } + } + catch (Exception) //do not resume operation on this thread if any errors are unhandled. + { + doContinue = false; + } + } + while (doContinue); + + client.Close(); + binReader.Close(); + stream.Close(); + lock (_clients) + { + _clients.Remove(client); + } + } + + #region IDisposable Members + + public void Dispose() + { + _isOpen = false; + Continue = false; + _listener.Stop(); + foreach (TcpClient client in _clients) + client.Close(); + } + + #endregion + } +} diff --git a/PrinterCommunication/RemotingLite/src/mono_build.bat b/PrinterCommunication/RemotingLite/src/mono_build.bat new file mode 100644 index 000000000..889f7120f --- /dev/null +++ b/PrinterCommunication/RemotingLite/src/mono_build.bat @@ -0,0 +1 @@ +call gmcs Properties\AssemblyInfo.cs *.cs -optimize+ -target:library -out:RemotingLite.dll diff --git a/StaticData/Translations/Master.txt b/StaticData/Translations/Master.txt index 9ffae789e..1da91b6b6 100644 --- a/StaticData/Translations/Master.txt +++ b/StaticData/Translations/Master.txt @@ -2642,3 +2642,6 @@ Translated:Search Library English:My Library Translated:My Library +English:Add to Library +Translated:Add to Library +