Skip to content

Commit 5a535f0

Browse files
committed
fix(copy): crash on clipboard access from non-focused window
1 parent 517d5f8 commit 5a535f0

4 files changed

Lines changed: 123 additions & 52 deletions

File tree

SharpFM.App/MainPage.xaml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
<Grid DataContext="{Binding}">
1616
<Grid.ColumnDefinitions>
1717
<ColumnDefinition Width="*" />
18-
<ColumnDefinition Width="350" />
1918
</Grid.ColumnDefinitions>
2019

2120
<controls:MasterDetailsView
@@ -101,7 +100,7 @@
101100

102101
</controls:MasterDetailsView>
103102

104-
<StackPanel Grid.Column="1" Width="350" Height="Auto" DataContext="{Binding}">
103+
<!--<StackPanel Grid.Column="1" Width="350" Height="Auto" DataContext="{Binding}">
105104
<ComboBox x:Name="LayoutPickerComboBox"
106105
HorizontalAlignment="Stretch"
107106
ItemsSource="{Binding Layouts}"
@@ -116,10 +115,10 @@
116115
</TextBlock>
117116
118117
119-
<!--<monaco:CodeEditor x:Name="XamlCodeRendererCsharp"
118+
--><!--<monaco:CodeEditor x:Name="XamlCodeRendererCsharp"
120119
CodeLanguage="csharp"
121-
Text="{ Binding SelectedClip.XmlData, Mode=OneWay}" />-->
122-
</StackPanel>
120+
Text="{ Binding SelectedClip.XmlData, Mode=OneWay}" />--><!--
121+
</StackPanel>-->
123122

124123
</Grid>
125124
</Page>

SharpFM.App/MainPage.xaml.cs

Lines changed: 60 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Threading.Tasks;
99
using Windows.ApplicationModel.DataTransfer;
1010
using Windows.Storage.Streams;
11+
using Windows.UI.Core;
1112
using Windows.UI.Popups;
1213
using Windows.UI.Xaml;
1314
using Windows.UI.Xaml.Controls;
@@ -32,10 +33,15 @@ public sealed partial class MainPage : Page
3233

3334
public string SelectedClipAsCsharp { get; set; }
3435

36+
CoreWindow window;
37+
3538
public MainPage()
3639
{
3740
InitializeComponent();
3841

42+
window = CoreWindow.GetForCurrentThread();
43+
window.Activated += Window_Activated;
44+
3945
Keys = new ObservableCollection<FileMakerClip>();
4046
Layouts = new ObservableCollection<FileMakerClip>();
4147

@@ -51,57 +57,75 @@ public MainPage()
5157
Clipboard.ContentChanged += Clipboard_ContentChanged;
5258
}
5359

54-
private async void Clipboard_ContentChanged(object sender, object e)
60+
private async Task ProcessClipboard()
5561
{
56-
var clip = Clipboard.GetContent();
57-
58-
var formats = clip.AvailableFormats.Where(f => f.StartsWith("Mac-", StringComparison.CurrentCultureIgnoreCase)).Distinct();
62+
try
63+
{
64+
var clip = Clipboard.GetContent();
5965

60-
Debug.WriteLine($"Formats: {formats.Count()}");
66+
var formats = clip.AvailableFormats.Where(f => f.StartsWith("Mac-", StringComparison.CurrentCultureIgnoreCase)).Distinct();
6167

62-
foreach (var format in formats)
63-
{
64-
object clipData = null;
68+
Debug.WriteLine($"Formats: {formats.Count()}");
6569

66-
try
70+
foreach (var format in formats)
6771
{
68-
if (format.Equals("bitmap", StringComparison.CurrentCultureIgnoreCase))
72+
object clipData = null;
73+
74+
try
6975
{
70-
clipData = await clip.GetBitmapAsync();
76+
if (format.Equals("bitmap", StringComparison.CurrentCultureIgnoreCase))
77+
{
78+
clipData = await clip.GetBitmapAsync();
79+
}
80+
clipData = await clip.GetDataAsync(format);
7181
}
72-
clipData = await clip.GetDataAsync(format);
73-
}
7482
#pragma warning disable CA1031 // Do not catch general exception types
75-
catch (Exception ex)
83+
catch (Exception ex)
7684
#pragma warning restore CA1031 // Do not catch general exception types
77-
{
78-
Debug.WriteLine(ex.Message);
79-
}
85+
{
86+
Debug.WriteLine(ex.Message);
87+
}
8088

81-
if (!(clipData is IRandomAccessStream dataObj))
82-
{
83-
// this is some type of clipboard data this program can't handle
84-
continue;
85-
}
89+
if (!(clipData is IRandomAccessStream dataObj))
90+
{
91+
// this is some type of clipboard data this program can't handle
92+
continue;
93+
}
8694

87-
var stream = dataObj.GetInputStreamAt(0);
88-
IBuffer buff = new Windows.Storage.Streams.Buffer((uint)dataObj.Size);
89-
await stream.ReadAsync(buff, (uint)dataObj.Size, InputStreamOptions.None);
90-
var buffArray = buff.ToArray();
95+
var stream = dataObj.GetInputStreamAt(0);
96+
IBuffer buff = new Windows.Storage.Streams.Buffer((uint)dataObj.Size);
97+
await stream.ReadAsync(buff, (uint)dataObj.Size, InputStreamOptions.None);
98+
var buffArray = buff.ToArray();
9199

92-
var fmclip = new FileMakerClip("new-clip", format, buffArray);
100+
var fmclip = new FileMakerClip("new-clip", format, buffArray);
93101

94-
// don't bother adding a duplicate. For some reason entries were getting entered twice per clip
95-
// this is not the most efficient method to detect it, but it works well enough for now
96-
if (Keys.Any(k => k.XmlData == fmclip.XmlData))
97-
{
98-
continue;
99-
}
102+
// don't bother adding a duplicate. For some reason entries were getting entered twice per clip
103+
// this is not the most efficient method to detect it, but it works well enough for now
104+
if (Keys.Any(k => k.XmlData == fmclip.XmlData))
105+
{
106+
continue;
107+
}
100108

101-
Keys.Add(fmclip);
109+
Keys.Add(fmclip);
110+
}
111+
}
112+
catch (Exception ex)
113+
{
114+
var md = new MessageDialog(ex.Message + "\r\n" + ex.StackTrace);
115+
await md.ShowAsync();
102116
}
103117
}
104118

119+
private async void Window_Activated(CoreWindow sender, WindowActivatedEventArgs args)
120+
{
121+
await ProcessClipboard();
122+
}
123+
124+
private void Clipboard_ContentChanged(object sender, object e)
125+
{
126+
window.Activate();
127+
}
128+
105129
private void Button_Click_1(object sender, RoutedEventArgs e)
106130
{
107131
var dp = new DataPackage();
@@ -146,6 +170,8 @@ private async void asModelAppBarButton_Click(object sender, RoutedEventArgs e)
146170
if (pickerResult == ContentDialogResult.Primary)
147171
{
148172
// regenerate using the layout picker
173+
SelectedLayout = picker.DialogResult;
174+
149175
var classString = data.CreateClass(SelectedLayout);
150176
var dp = new DataPackage();
151177
dp.SetText(classString);

SharpFM.App/SharpFM.App.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
<AssemblyName>SharpFM.App</AssemblyName>
1212
<DefaultLanguage>en-US</DefaultLanguage>
1313
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
14-
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.17134.0</TargetPlatformVersion>
15-
<TargetPlatformMinVersion>10.0.16299.0</TargetPlatformMinVersion>
14+
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.18362.0</TargetPlatformVersion>
15+
<TargetPlatformMinVersion>10.0.18362.0</TargetPlatformMinVersion>
1616
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
1717
<FileAlignment>512</FileAlignment>
1818
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>

SharpFM.Core/FileMakerClipExtensions.cs

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.Collections.Generic;
66
using System.Linq;
7+
using System.Text.RegularExpressions;
78

89
namespace SharpFM.Core
910
{
@@ -42,26 +43,54 @@ public static string CreateClass(this FileMakerClip _clip, IEnumerable<string> f
4243

4344
// Add System using statement: (using System)
4445
@namespace = @namespace.AddUsings(SyntaxFactory.UsingDirective(SyntaxFactory.ParseName("System")));
46+
@namespace = @namespace.AddUsings(SyntaxFactory.UsingDirective(SyntaxFactory.ParseName("System.Runtime.Serialization")));
47+
48+
var dataContractAttribute = SyntaxFactory.Attribute(SyntaxFactory.ParseName("DataContract"));
4549

4650
// Create a class: (class [_clip.Name])
4751
var classDeclaration = SyntaxFactory.ClassDeclaration(_clip.Name);
4852

4953
// Add the public modifier: (public class [_clip.Name])
5054
classDeclaration = classDeclaration.AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword));
55+
classDeclaration = classDeclaration.AddAttributeLists(SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(dataContractAttribute)));
5156

5257
// add each field from the underling _clip as a public property with the data member attribute
53-
List<PropertyDeclarationSyntax> fieldsToBeAddedAsProperties = new List<PropertyDeclarationSyntax>(_clip.Fields.Count());
58+
List <PropertyDeclarationSyntax> fieldsToBeAddedAsProperties = new List<PropertyDeclarationSyntax>(_clip.Fields.Count());
5459
// include the field projection
5560
foreach (var field in _clip.Fields.Where(fmF => fieldProjectionList.Contains(fmF.Name)))
5661
{
5762
// filemaker to C# data type mapping
58-
var propertyTypeCSharp = field.DataType
59-
.Replace("Text", "string")
60-
.Replace("Number", "int")
61-
.Replace("Binary", "byte[]")
62-
.Replace("Date", "DateTime")
63-
.Replace("Time", "TimeStamp")
64-
.Replace("TimeStamp", "DateTime");
63+
var propertyTypeCSharp = string.Empty;
64+
65+
switch (field.DataType)
66+
{
67+
case "Text":
68+
propertyTypeCSharp = "string";
69+
break;
70+
case "Number":
71+
propertyTypeCSharp = "int";
72+
break;
73+
case "Binary":
74+
propertyTypeCSharp = "byte[]";
75+
break;
76+
case "Date":
77+
propertyTypeCSharp = "DateTime";
78+
break;
79+
case "Time":
80+
propertyTypeCSharp = "TimeSpan";
81+
break;
82+
case "TimeStamp":
83+
propertyTypeCSharp = "DateTime";
84+
break;
85+
default:
86+
propertyTypeCSharp = "string";
87+
break;
88+
}
89+
90+
if(field.NotEmpty == false && propertyTypeCSharp != "string")
91+
{
92+
propertyTypeCSharp += "?";
93+
}
6594

6695
var propertyTypeSyntax = SyntaxFactory.ParseTypeName(propertyTypeCSharp);
6796

@@ -72,8 +101,9 @@ public static string CreateClass(this FileMakerClip _clip, IEnumerable<string> f
72101
.AddAccessorListAccessors(
73102
SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)),
74103
SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)))
75-
.NormalizeWhitespace()
76-
.AddAttributeLists(SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(dataMemberAttribute)));
104+
.NormalizeWhitespace(indentation: "", eol: " ")
105+
.AddAttributeLists(SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(dataMemberAttribute)))
106+
.NormalizeWhitespace();
77107

78108
fieldsToBeAddedAsProperties.Add(propertyDeclaration);
79109
}
@@ -85,10 +115,26 @@ public static string CreateClass(this FileMakerClip _clip, IEnumerable<string> f
85115
@namespace = @namespace.AddMembers(classDeclaration);
86116

87117
// Normalize and get code as string.
88-
var code = @namespace.NormalizeWhitespace().ToFullString();
118+
var code = @namespace.NormalizeWhitespace().ToFullString().FormatAutoPropertiesOnOneLine();
89119

90120
// Output new code to the console.
91121
return code;
92122
}
123+
124+
125+
/// <summary>
126+
/// https://stackoverflow.com/a/52339795/86860
127+
/// </summary>
128+
private static readonly Regex AutoPropRegex = new Regex(@"\s*\{\s*get;\s*set;\s*}\s");
129+
130+
/// <summary>
131+
/// https://stackoverflow.com/a/52339795/86860
132+
/// </summary>
133+
/// <param name="str">Code string to format.</param>
134+
/// <returns>The code string with auto properties formatted to a single line</returns>
135+
private static string FormatAutoPropertiesOnOneLine(this string str)
136+
{
137+
return AutoPropRegex.Replace(str, " { get; set; }");
138+
}
93139
}
94140
}

0 commit comments

Comments
 (0)