Wine-Devel
By thread
wine-devel@list.winehq.org
By month
Messages by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
June 2018
- 68 participants
- 1149 messages
[PATCH 2/7] testbot/web: Let LogUtils build the list of task reports and logs.
by Francois Gouget
Signed-off-by: Francois Gouget <fgouget(a)codeweavers.com>
---
testbot/lib/WineTestBot/LogUtils.pm | 55 ++++++++++++++++++++++++++++-
testbot/web/JobDetails.pl | 20 ++++-------
2 files changed, 60 insertions(+), 15 deletions(-)
diff --git a/testbot/lib/WineTestBot/LogUtils.pm b/testbot/lib/WineTestBot/LogUtils.pm
index daa9c0bd8..3dfd7c5e7 100644
--- a/testbot/lib/WineTestBot/LogUtils.pm
+++ b/testbot/lib/WineTestBot/LogUtils.pm
@@ -27,7 +27,7 @@ WineTestBot::LogUtils - Provides functions to parse task logs
use Exporter 'import';
-our @EXPORT = qw(GetLogLineCategory ParseTaskLog);
+our @EXPORT = qw(GetLogFileNames GetLogLabel GetLogLineCategory ParseTaskLog);
#
@@ -133,4 +133,57 @@ sub GetLogLineCategory($)
return "none";
}
+=pod
+=over 12
+
+=item C<GetLogFileNames()>
+
+Scans the directory for test reports and task logs and returns their filenames.
+The filenames are returned in the order in which the logs are meant to be
+presented.
+
+=back
+=cut
+
+sub GetLogFileNames($;$)
+{
+ my ($Dir, $IncludeOld) = @_;
+
+ my @Candidates = ("exe32.report", "exe64.report",
+ "log", "err");
+ push @Candidates, "log.old", "err.old" if ($IncludeOld);
+
+ my @Logs;
+ foreach my $FileName (@Candidates)
+ {
+ push @Logs, $FileName if (-f "$Dir/$FileName" and !-z "$Dir/$FileName");
+ }
+ return \@Logs;
+}
+
+my %_LogFileLabels = (
+ "exe32.report" => "32 bit Windows report",
+ "exe64.report" => "64 bit Windows report",
+ "err" => "task errors",
+ "log" => "task log",
+ "err.old" => "old task errors",
+ "log.old" => "old logs",
+);
+
+=pod
+=over 12
+
+=item C<GetLogLabel()>
+
+Returns a user-friendly description of the content of the specified log file.
+
+=back
+=cut
+
+sub GetLogLabel($)
+{
+ my ($LogFileName) = @_;
+ return $_LogFileLabels{$LogFileName};
+}
+
1;
diff --git a/testbot/web/JobDetails.pl b/testbot/web/JobDetails.pl
index 07924f4e6..e5f792929 100644
--- a/testbot/web/JobDetails.pl
+++ b/testbot/web/JobDetails.pl
@@ -261,14 +261,6 @@ sub GetHtmlLine($$$)
return $Html;
}
-my @MILogFiles = qw(exe32.report exe64.report log log.old);
-my %MILogLabels = (
- "exe32.report" => "32 bit Windows report",
- "exe64.report" => "64 bit Windows report",
- "log" => "task log",
- "log.old" => "old logs",
-);
-
sub InitMoreInfo($)
{
my ($self) = @_;
@@ -282,15 +274,15 @@ sub InitMoreInfo($)
my $Value = $self->GetParam("f$Key");
my $TaskDir = $StepTask->GetTaskDir();
- foreach my $Log (@MILogFiles)
+ foreach my $Log (@{GetLogFileNames($TaskDir, 1)})
{
- if (!-f "$TaskDir/$Log" or -z "$TaskDir/$Log")
+ if ($Log =~ s/^err/log/)
{
- my $Err = $Log;
- next if ($Err !~ s/^log/err/ or !-f "$TaskDir/$Err" or -z "$TaskDir/$Err");
+ # We don't want separate entries for log* and err* but we also want a
+ # log* entry even if only err* exists.
+ next if (($More->{$Key}->{Logs}->[-1] || "") eq $Log);
}
push @{$More->{$Key}->{Logs}}, $Log;
-
$More->{$Key}->{Full} = $Log if (uri_escape($Log) eq $Value);
}
$More->{$Key}->{Full} ||= "";
@@ -385,7 +377,7 @@ sub GenerateBody($)
foreach my $Log (@{$MoreInfo->{Logs}})
{
- $self->GenerateMoreInfoLink($Key, $MILogLabels{$Log}, "Full", $Log);
+ $self->GenerateMoreInfoLink($Key, GetLogLabel($Log), "Full", $Log);
}
print "</div>\n";
--
2.18.0
June 26, 2018
[PATCH 1/7] testbot: Move log line categorization to LogUtils and simplify line highlighting.
by Francois Gouget
GetLogLineCategory() identifies log lines of interest which makes it
possible to decide how to display them.
Signed-off-by: Francois Gouget <fgouget(a)codeweavers.com>
---
This makes it reusable in WineSendLog.pl.
testbot/lib/WineTestBot/LogUtils.pm | 61 +++++++++++++++++++++-
testbot/web/JobDetails.pl | 78 +++++++++++------------------
2 files changed, 88 insertions(+), 51 deletions(-)
diff --git a/testbot/lib/WineTestBot/LogUtils.pm b/testbot/lib/WineTestBot/LogUtils.pm
index 3e40fbc35..daa9c0bd8 100644
--- a/testbot/lib/WineTestBot/LogUtils.pm
+++ b/testbot/lib/WineTestBot/LogUtils.pm
@@ -27,7 +27,7 @@ WineTestBot::LogUtils - Provides functions to parse task logs
use Exporter 'import';
-our @EXPORT = qw(ParseTaskLog);
+our @EXPORT = qw(GetLogLineCategory ParseTaskLog);
#
@@ -74,4 +74,63 @@ sub ParseTaskLog($$)
return "nolog:Unable to open the task log for reading: $!";
}
+
+#
+# Log querying and formatting
+#
+
+=pod
+=over 12
+
+=item C<GetLogLineCategory()>
+
+Identifies the category of the given log line: an error message, a todo, just
+an informational message or none of these. The category can then be used to
+decide whether to hide the line or, on the contrary, highlight it.
+
+=back
+=cut
+
+sub GetLogLineCategory($)
+{
+ my ($Line) = @_;
+
+ if ($Line =~ /: Test marked todo: /)
+ {
+ return "todo";
+ }
+ if ($Line =~ /: Tests skipped: / or
+ $Line =~ /^\w+:\w+ skipped /)
+ {
+ return "skip";
+ }
+ if ($Line =~ /: Test (?:failed|succeeded inside todo block): / or
+ $Line =~ /Fatal: test .* does not exist/ or
+ $Line =~ / done \(258\)/ or
+ $Line =~ /: unhandled exception [0-9a-fA-F]{8} at / or
+ $Line =~ /^Unhandled exception: / or
+ # Git errors
+ $Line =~ /^CONFLICT / or
+ $Line =~ /^error: patch failed:/ or
+ $Line =~ /^error: corrupt patch / or
+ # Build errors
+ $Line =~ /: error: / or
+ $Line =~ /^Makefile:[0-9]+: recipe for target .* failed$/ or
+ $Line =~ /^(?:Build|Reconfig|Task): (?!ok)/ or
+ # Typical perl errors
+ $Line =~ /^Use of uninitialized value/)
+ {
+ return "error";
+ }
+ if ($Line =~ /^\+ \S/ or
+ $Line =~ /^\w+:\w+ start / or
+ # Build messages
+ $Line =~ /^(?:Build|Reconfig|Task): ok/)
+ {
+ return "info";
+ }
+
+ return "none";
+}
+
1;
diff --git a/testbot/web/JobDetails.pl b/testbot/web/JobDetails.pl
index f05c0f62e..07924f4e6 100644
--- a/testbot/web/JobDetails.pl
+++ b/testbot/web/JobDetails.pl
@@ -28,6 +28,7 @@ use URI::Escape;
use WineTestBot::Config;
use WineTestBot::Jobs;
+use WineTestBot::LogUtils;
use WineTestBot::StepsTasks;
use WineTestBot::Engine::Notify;
@@ -228,59 +229,36 @@ sub GeneratePage($)
$self->SUPER::GeneratePage();
}
+=pod
+=over 12
+
+=item C<GetHtmlLine()>
+
+Determines if the log line should be shown, how, and escapes it so it is valid
+HTML.
+
+When not showing the full log, returns undef except for error messages which
+are the only lines tha should be shown.
+When showing the full log error messages and other lines of interest are
+highlighted to make the log more readable.
+
+=back
+=cut
+
sub GetHtmlLine($$$)
{
my ($self, $FullLog, $Line) = @_;
- $Line = $self->escapeHTML($Line);
- if ($Line =~ /: Test marked todo: /)
- {
- return (undef, $Line) if (!$FullLog);
- my $Html = $Line;
- $Html =~ s~^(.*\S)\s*\r?$~<span class='log-todo'>$1</span>~;
- return ($Html, $Line);
- }
- if ($Line =~ /: Tests skipped: / or
- $Line =~ /^\w+:\w+ skipped /)
- {
- return (undef, $Line) if (!$FullLog);
- my $Html = $Line;
- $Html =~ s~^(.*\S)\s*\r?$~<span class='log-skip'>$1</span>~;
- return ($Html, $Line);
- }
- if ($Line =~ /: Test (?:failed|succeeded inside todo block): / or
- $Line =~ /Fatal: test .* does not exist/ or
- $Line =~ / done \(258\)/ or
- $Line =~ /: unhandled exception [0-9a-fA-F]{8} at / or
- $Line =~ /^Unhandled exception: / or
- # Git errors
- $Line =~ /^CONFLICT / or
- $Line =~ /^error: patch failed:/ or
- $Line =~ /^error: corrupt patch / or
- # Build errors
- $Line =~ /: error: / or
- $Line =~ /^Makefile:[0-9]+: recipe for target .* failed$/ or
- $Line =~ /^(?:Build|Reconfig|Task): (?!ok)/ or
- # Typical perl errors
- $Line =~ /^Use of uninitialized value/)
- {
- return ($Line, $Line) if (!$FullLog);
- my $Html = $Line;
- $Html =~ s~^(.*\S)\s*\r?$~<span class='log-error'>$1</span>~;
- return ($Html, $Line);
- }
- if ($FullLog &&
- ($Line =~ /^\+ \S/ or
- $Line =~ /^\w+:\w+ start / or
- # Build messages
- $Line =~ /^(?:Build|Reconfig|Task): ok/))
+ my $Category = GetLogLineCategory($Line);
+ return undef if ($Category ne "error" and !$FullLog);
+
+ my $Html = $self->escapeHTML($Line);
+ if ($FullLog and $Category ne "none")
{
- my $Html = $Line;
- $Html =~ s~^(.*\S)\s*\r?$~<span class='log-info'>$1</span>~;
- return ($Html, $Line);
+ # Highlight all line categories in the full log
+ $Html =~ s~^(.*\S)\s*\r?$~<span class='log-$Category'>$1</span>~;
}
-
- return (undef, $Line);
+ return $Html;
}
my @MILogFiles = qw(exe32.report exe64.report log log.old);
@@ -429,8 +407,8 @@ sub GenerateBody($)
{
$CurrentDll = $1;
}
- my ($Highlight, $Plain) = $self->GetHtmlLine($MoreInfo->{Full}, $Line);
- next if (!$MoreInfo->{Full} and !defined $Highlight);
+ my $Html = $self->GetHtmlLine($MoreInfo->{Full}, $Line);
+ next if (!defined $Html);
if ($PrintedDll ne $CurrentDll && !$MoreInfo->{Full})
{
@@ -451,7 +429,7 @@ sub GenerateBody($)
}
else
{
- print(($Highlight || $Plain), "\n");
+ print "$Html\n";
}
}
close($LogFile);
--
2.18.0
June 26, 2018
Re: [PATCH 2/2] msvcp120: Add test for Concurrent_vector_grow_to_at_least_with_result.
by Piotr Caban
Signed-off-by: Piotr Caban <piotr(a)codeweavers.com>
June 26, 2018
Re: [PATCH 1/2] msvcp120: Add test for Concurrent_vector_grow_by.
by Piotr Caban
Signed-off-by: Piotr Caban <piotr(a)codeweavers.com>
June 26, 2018
[PATCH 2/2] msvcp120: Add test for Concurrent_vector_grow_to_at_least_with_result.
by Hua Meng
Signed-off-by: Hua meng <161220092(a)smail.nju.edu.cn>
---
dlls/msvcp120/tests/msvcp120.c | 46 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/dlls/msvcp120/tests/msvcp120.c b/dlls/msvcp120/tests/msvcp120.c
index b5e470cba3..2974482ec1 100644
--- a/dlls/msvcp120/tests/msvcp120.c
+++ b/dlls/msvcp120/tests/msvcp120.c
@@ -420,6 +420,8 @@ static void* (__thiscall *p_vector_base_v4__Internal_compact)(
void (__cdecl*)(void*, const void*, size_t));
static size_t (__thiscall *p_vector_base_v4__Internal_grow_by)(
vector_base_v4*, size_t, size_t, void (__cdecl*)(void*, const void*, size_t), const void *);
+static size_t (__thiscall *p_vector_base_v4__Internal_grow_to_at_least_with_result)(
+ vector_base_v4*, size_t, size_t, void (__cdecl*)(void*, const void*, size_t), const void *);
static HMODULE msvcp;
#define SETNOFAIL(x,y) x = (void*)GetProcAddress(msvcp,y)
@@ -572,6 +574,8 @@ static BOOL init(void)
"?_Internal_compact(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IEAAPEAX_KPEAXP6AX10(a)ZP6AX1PEBX0@Z(a)Z");
SET(p_vector_base_v4__Internal_grow_by,
"?_Internal_grow_by(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IEAA_K_K0P6AXPEAXPEBX0(a)Z2@Z");
+ SET(p_vector_base_v4__Internal_grow_to_at_least_with_result,
+ "?_Internal_grow_to_at_least_with_result(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IEAA_K_K0P6AXPEAXPEBX0(a)Z2@Z");
} else {
SET(p_tr2_sys__File_size,
"?_File_size(a)sys@tr2(a)std@@YA_KPBD(a)Z");
@@ -693,6 +697,8 @@ static BOOL init(void)
"?_Internal_compact(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IAEPAXIPAXP6AX0I(a)ZP6AX0PBXI@Z(a)Z");
SET(p_vector_base_v4__Internal_grow_by,
"?_Internal_grow_by(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IAEIIIP6AXPAXPBXI(a)Z1@Z");
+ SET(p_vector_base_v4__Internal_grow_to_at_least_with_result,
+ "?_Internal_grow_to_at_least_with_result(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IAEIIIP6AXPAXPBXI(a)Z1@Z");
#else
SET(p__Thrd_current,
"_Thrd_current");
@@ -742,6 +748,8 @@ static BOOL init(void)
"?_Internal_compact(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IAAPAXIPAXP6AX0I(a)ZP6AX0PBXI@Z(a)Z");
SET(p_vector_base_v4__Internal_grow_by,
"?_Internal_grow_by(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IAAIIIP6AXPAXPBXI(a)Z1@Z");
+ SET(p_vector_base_v4__Internal_grow_to_at_least_with_result,
+ "?_Internal_grow_to_at_least_with_result(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IAAIIIP6AXPAXPBXI(a)Z1@Z");
#endif
}
SET(p__Thrd_equal,
@@ -3036,6 +3044,44 @@ static void test_vector_base_v4(void)
CHECK_CALLED(concurrent_vector_int_destroy);
concurrent_vector_int_dtor(&v2);
+ /* test for Internal_grow_to_at_least_with_result */
+ concurrent_vector_int_ctor(&v2);
+ SET_EXPECT(concurrent_vector_int_alloc);
+ data = call_func3(p_vector_base_v4__Internal_push_back, &v2, sizeof(int), &idx);
+ CHECK_CALLED(concurrent_vector_int_alloc);
+ ok(data != NULL, "_Internal_push_back returned NULL\n");
+ data = call_func3(p_vector_base_v4__Internal_push_back, &v2, sizeof(int), &idx);
+ ok(data != NULL, "_Internal_push_back returned NULL\n");
+ vector_elem_count += 2;
+ ok(v2.first_block == 1, "v2.first_block got %ld expected 1\n", (long)v2.first_block);
+ ok(v2.early_size == 2, "v2.early_size got %ld expected 2\n", (long)v2.early_size);
+ i = 0;
+ SET_EXPECT(concurrent_vector_int_alloc);
+ SET_EXPECT(concurrent_vector_int_copy);
+ idx = (size_t)call_func5(p_vector_base_v4__Internal_grow_to_at_least_with_result,
+ &v2, 3, sizeof(int), concurrent_vector_int_copy, &i);
+ CHECK_CALLED(concurrent_vector_int_alloc);
+ CHECK_CALLED(concurrent_vector_int_copy);
+ ok(idx == 2, "_Internal_grow_to_at_least_with_result returned %ld expected 2\n", (long)idx);
+ ok(v2.first_block == 1, "v2.first_block got %ld expected 1\n", (long)v2.first_block);
+ ok(v2.early_size == 3, "v2.early_size got %ld expected 3\n", (long)v2.early_size);
+ i = 0;
+ SET_EXPECT(concurrent_vector_int_alloc);
+ SET_EXPECT(concurrent_vector_int_copy);
+ idx = (size_t)call_func5(p_vector_base_v4__Internal_grow_to_at_least_with_result,
+ &v2, 5, sizeof(int), concurrent_vector_int_copy, &i);
+ CHECK_CALLED(concurrent_vector_int_alloc);
+ CHECK_CALLED(concurrent_vector_int_copy);
+ ok(idx == 3, "_Internal_grow_to_at_least_with_result returned %ld expected 3\n", (long)idx);
+ ok(v2.first_block == 1, "v2.first_block got %ld expected 1\n", (long)v2.first_block);
+ ok(v2.early_size == 5, "v2.early_size got %ld expected 5\n", (long)v2.early_size);
+ SET_EXPECT(concurrent_vector_int_destroy);
+ size = (size_t)call_func2(p_vector_base_v4__Internal_clear,
+ &v2, concurrent_vector_int_destroy);
+ ok(size == 3, "_Internal_clear returned %ld expected 3\n", (long)size);
+ CHECK_CALLED(concurrent_vector_int_destroy);
+ concurrent_vector_int_dtor(&v2);
+
SET_EXPECT(concurrent_vector_int_destroy);
size = (size_t)call_func2(p_vector_base_v4__Internal_clear,
&vector, concurrent_vector_int_destroy);
--
2.11.0
June 26, 2018
[PATCH 1/2] msvcp120: Add test for Concurrent_vector_grow_by.
by Hua Meng
Signed-off-by: Hua meng <161220092(a)smail.nju.edu.cn>
---
dlls/msvcp120/tests/msvcp120.c | 46 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 45 insertions(+), 1 deletion(-)
diff --git a/dlls/msvcp120/tests/msvcp120.c b/dlls/msvcp120/tests/msvcp120.c
index 0ec9fbd3b1..b5e470cba3 100644
--- a/dlls/msvcp120/tests/msvcp120.c
+++ b/dlls/msvcp120/tests/msvcp120.c
@@ -418,6 +418,8 @@ static void (__thiscall *p_vector_base_v4__Internal_swap)(
static void* (__thiscall *p_vector_base_v4__Internal_compact)(
vector_base_v4*, size_t, void*, void (__cdecl*)(void*, size_t),
void (__cdecl*)(void*, const void*, size_t));
+static size_t (__thiscall *p_vector_base_v4__Internal_grow_by)(
+ vector_base_v4*, size_t, size_t, void (__cdecl*)(void*, const void*, size_t), const void *);
static HMODULE msvcp;
#define SETNOFAIL(x,y) x = (void*)GetProcAddress(msvcp,y)
@@ -568,6 +570,8 @@ static BOOL init(void)
"?_Internal_swap(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IEAAXAEAV123@@Z");
SET(p_vector_base_v4__Internal_compact,
"?_Internal_compact(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IEAAPEAX_KPEAXP6AX10(a)ZP6AX1PEBX0@Z(a)Z");
+ SET(p_vector_base_v4__Internal_grow_by,
+ "?_Internal_grow_by(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IEAA_K_K0P6AXPEAXPEBX0(a)Z2@Z");
} else {
SET(p_tr2_sys__File_size,
"?_File_size(a)sys@tr2(a)std@@YA_KPBD(a)Z");
@@ -687,6 +691,8 @@ static BOOL init(void)
"?_Internal_swap(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IAEXAAV123@@Z");
SET(p_vector_base_v4__Internal_compact,
"?_Internal_compact(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IAEPAXIPAXP6AX0I(a)ZP6AX0PBXI@Z(a)Z");
+ SET(p_vector_base_v4__Internal_grow_by,
+ "?_Internal_grow_by(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IAEIIIP6AXPAXPBXI(a)Z1@Z");
#else
SET(p__Thrd_current,
"_Thrd_current");
@@ -734,7 +740,8 @@ static BOOL init(void)
"?_Internal_swap(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IAAXAAV123@@Z");
SET(p_vector_base_v4__Internal_compact,
"?_Internal_compact(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IAAPAXIPAXP6AX0I(a)ZP6AX0PBXI@Z(a)Z");
-
+ SET(p_vector_base_v4__Internal_grow_by,
+ "?_Internal_grow_by(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IAAIIIP6AXPAXPBXI(a)Z1@Z");
#endif
}
SET(p__Thrd_equal,
@@ -2992,6 +2999,43 @@ static void test_vector_base_v4(void)
CHECK_CALLED(concurrent_vector_int_destroy);
concurrent_vector_int_dtor(&v2);
+ /* test for Internal_grow_by */
+ concurrent_vector_int_ctor(&v2);
+ SET_EXPECT(concurrent_vector_int_alloc);
+ data = call_func3(p_vector_base_v4__Internal_push_back, &v2, sizeof(int), &idx);
+ CHECK_CALLED(concurrent_vector_int_alloc);
+ ok(data != NULL, "_Internal_push_back returned NULL\n");
+ data = call_func3(p_vector_base_v4__Internal_push_back, &v2, sizeof(int), &idx);
+ ok(data != NULL, "_Internal_push_back returned NULL\n");
+ vector_elem_count += 2;
+ ok(v2.first_block == 1, "v2.first_block got %ld expected 1\n", (long)v2.first_block);
+ ok(v2.early_size == 2, "v2.early_size got %ld expected 2\n", (long)v2.early_size);
+ i = 0;
+ SET_EXPECT(concurrent_vector_int_alloc);
+ SET_EXPECT(concurrent_vector_int_copy);
+ idx = (size_t)call_func5(p_vector_base_v4__Internal_grow_by,
+ &v2, 1, sizeof(int), concurrent_vector_int_copy, &i);
+ CHECK_CALLED(concurrent_vector_int_alloc);
+ CHECK_CALLED(concurrent_vector_int_copy);
+ ok(idx == 2, "_Internal_grow_by returned %ld expected 2\n", (long)idx);
+ ok(v2.first_block == 1, "v2.first_block got %ld expected 1\n", (long)v2.first_block);
+ ok(v2.early_size == 3, "v2.early_size got %ld expected 3\n", (long)v2.early_size);
+ SET_EXPECT(concurrent_vector_int_alloc);
+ SET_EXPECT(concurrent_vector_int_copy);
+ idx = (size_t)call_func5(p_vector_base_v4__Internal_grow_by,
+ &v2, 2, sizeof(int), concurrent_vector_int_copy, &i);
+ CHECK_CALLED(concurrent_vector_int_alloc);
+ CHECK_CALLED(concurrent_vector_int_copy);
+ ok(idx == 3, "_Internal_grow_by returned %ld expected 3\n", (long)idx);
+ ok(v2.first_block == 1, "v2.first_block got %ld expected 1\n", (long)v2.first_block);
+ ok(v2.early_size == 5, "v2.early_size got %ld expected 5\n", (long)v2.early_size);
+ SET_EXPECT(concurrent_vector_int_destroy);
+ size = (size_t)call_func2(p_vector_base_v4__Internal_clear,
+ &v2, concurrent_vector_int_destroy);
+ ok(size == 3, "_Internal_clear returned %ld expected 3\n", (long)size);
+ CHECK_CALLED(concurrent_vector_int_destroy);
+ concurrent_vector_int_dtor(&v2);
+
SET_EXPECT(concurrent_vector_int_destroy);
size = (size_t)call_func2(p_vector_base_v4__Internal_clear,
&vector, concurrent_vector_int_destroy);
--
2.11.0
June 26, 2018
Re: [PATCH] gdi32/tests: Use the available ARRAY_SIZE() macro
by Huw Davies
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
June 26, 2018
[PATCH 2/2] testbot/Janitor: Clean up the latest directory too.
by Francois Gouget
Signed-off-by: Francois Gouget <fgouget(a)codeweavers.com>
---
testbot/bin/Janitor.pl | 46 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/testbot/bin/Janitor.pl b/testbot/bin/Janitor.pl
index 9252efa65..a9cdd52cd 100755
--- a/testbot/bin/Janitor.pl
+++ b/testbot/bin/Janitor.pl
@@ -299,6 +299,52 @@ else
Error "Unable to open '$DataDir/staging': $!";
}
+# Check the content of the latest directory
+if (opendir(my $dh, "$DataDir/latest"))
+{
+ # We will be deleting files so read the directory in one go
+ my @Entries = readdir($dh);
+ close($dh);
+
+ my $AllVMs = $VMs->Clone();
+ foreach my $Entry (@Entries)
+ {
+ next if ($Entry eq "." or $Entry eq "..");
+ $Entry =~ m%^([^/]+)$%;
+ my $FileName = "$DataDir/latest/$1";
+ my $Age = int((-M $FileName) + 0.5);
+
+ if ($Entry =~ /^(.*)_[a-z0-9]+\.(?:err|log)$/)
+ {
+ # Keep the reference WineTest reports for all VMs even if they are
+ # retired or scheduled for deletion.
+ my $VMName = $1;
+ next if ($AllVMs->GetItem($VMName));
+ }
+ elsif ($Entry =~ /^(?:TestLauncher[0-9]*\.exe|winefiles.txt|winetest[0-9]*-latest\.exe)$/)
+ {
+ next;
+ }
+
+ Trace "Found a suspicious latest file: $Entry\n";
+ if ($JobPurgeDays != 0)
+ {
+ if ($Age >= $JobPurgeDays + 7)
+ {
+ DeletePath($FileName);
+ }
+ elsif ($Age > $JobPurgeDays)
+ {
+ Trace "'$FileName' will be deleted in ", $JobPurgeDays + 7 - $Age, " day(s).\n";
+ }
+ }
+ }
+}
+else
+{
+ Error "Unable to open '$DataDir/latest': $!";
+}
+
# Delete obsolete record groups
if ($JobPurgeDays != 0)
{
--
2.18.0
June 26, 2018
[PATCH 1/2] testbot/Janitor: Add DeletePath() to simplify deleting file/directories.
by Francois Gouget
Signed-off-by: Francois Gouget <fgouget(a)codeweavers.com>
---
testbot/bin/Janitor.pl | 25 ++++++++++++++-----------
1 file changed, 14 insertions(+), 11 deletions(-)
diff --git a/testbot/bin/Janitor.pl b/testbot/bin/Janitor.pl
index 9fb38efde..9252efa65 100755
--- a/testbot/bin/Janitor.pl
+++ b/testbot/bin/Janitor.pl
@@ -116,6 +116,17 @@ if (defined $Usage)
# Main
#
+sub DeletePath($)
+{
+ my ($Path) = @_;
+
+ Trace "Deleting '$Path'\n";
+ if (!$DryRun and !rmtree($Path))
+ {
+ Error "Could not delete '$Path': $!\n";
+ }
+}
+
# Delete obsolete Jobs
if ($JobPurgeDays != 0)
{
@@ -268,11 +279,7 @@ if (opendir(my $dh, "$DataDir/staging"))
{
if ($Age >= $JobPurgeDays + 7)
{
- Trace "Deleting '$FileName'\n";
- if (!$DryRun and !rmtree($FileName))
- {
- Error "Could not delete '$FileName': $!\n";
- }
+ DeletePath($FileName);
}
elsif ($Age > $JobPurgeDays)
{
@@ -282,12 +289,8 @@ if (opendir(my $dh, "$DataDir/staging"))
}
elsif ($Age >= 1)
{
- Trace "Deleting '$FileName'\n";
- if (!$DryRun and !unlink $FileName)
- {
- # The user abandoned the submit procedure half-way through
- Error "Could not delete '$FileName': $!\n";
- }
+ # The user abandoned the submit procedure half-way through
+ DeletePath($FileName);
}
}
}
--
2.18.0
June 26, 2018
[PATCH 2/2] crypt32: Fix string arguments tracing.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/crypt32/base64.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/dlls/crypt32/base64.c b/dlls/crypt32/base64.c
index 4a904d41cc..2ba8055961 100644
--- a/dlls/crypt32/base64.c
+++ b/dlls/crypt32/base64.c
@@ -622,7 +622,7 @@ static LONG Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString,
if (!(headerBegins = strstr(pszString, header)))
{
- TRACE("Can't find %s in %s.\n", header, pszString);
+ TRACE("Can't find %s in %s.\n", header, debugstr_an(pszString, cchString));
return ERROR_INVALID_DATA;
}
@@ -746,7 +746,7 @@ BOOL WINAPI CryptStringToBinaryA(LPCSTR pszString,
StringToBinaryAFunc decoder;
LONG ret;
- TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_a(pszString),
+ TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_an(pszString, cchString ? cchString : -1),
cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
if (!pszString)
@@ -833,7 +833,7 @@ static LONG Base64WithHeaderAndTrailerToBinaryW(LPCWSTR pszString,
if (!(headerBegins = strstrW(pszString, header)))
{
- TRACE("Can't find %s in %s.\n", debugstr_w(header), debugstr_w(pszString));
+ TRACE("Can't find %s in %s.\n", debugstr_w(header), debugstr_wn(pszString, cchString));
return ERROR_INVALID_DATA;
}
@@ -957,7 +957,7 @@ BOOL WINAPI CryptStringToBinaryW(LPCWSTR pszString,
StringToBinaryWFunc decoder;
LONG ret;
- TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_w(pszString),
+ TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_wn(pszString, cchString ? cchString : -1),
cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
if (!pszString)
--
2.18.0
June 26, 2018
[PATCH 1/2] crypt32: Implement verification of ECDSA signatures.
by Nikolay Sivov
From: Michael Müller <michael(a)fds-team.de>
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
Modifications from original patch:
- few renames to make it closer to existing code;
- removed unrelated formatting changes in existing code;
- new BCrypt path is rearranged to match existing order : import -> hash -> verify.
dlls/crypt32/Makefile.in | 2 +-
dlls/crypt32/cert.c | 260 +++++++++++++++++++++++++++++++++++++--
2 files changed, 250 insertions(+), 12 deletions(-)
diff --git a/dlls/crypt32/Makefile.in b/dlls/crypt32/Makefile.in
index d3a409fcae..0934222119 100644
--- a/dlls/crypt32/Makefile.in
+++ b/dlls/crypt32/Makefile.in
@@ -1,7 +1,7 @@
EXTRADEFS = -D_CRYPT32_
MODULE = crypt32.dll
IMPORTLIB = crypt32
-IMPORTS = user32 advapi32
+IMPORTS = user32 advapi32 bcrypt
DELAYIMPORTS = cryptnet
EXTRALIBS = $(SECURITY_LIBS)
diff --git a/dlls/crypt32/cert.c b/dlls/crypt32/cert.c
index 83aac5d8f4..1667b42b0b 100644
--- a/dlls/crypt32/cert.c
+++ b/dlls/crypt32/cert.c
@@ -21,9 +21,14 @@
#include <stdarg.h>
#define NONAMELESSUNION
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
#include "windef.h"
#include "winbase.h"
+#include "winternl.h"
+#define CRYPT_OID_INFO_HAS_EXTRA_FIELDS
#include "wincrypt.h"
+#include "bcrypt.h"
#include "winnls.h"
#include "rpc.h"
#include "wine/debug.h"
@@ -2408,22 +2413,13 @@ BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV_LEGACY hCryptProv,
CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL);
}
-static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv,
- DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pubKeyInfo,
- const CERT_SIGNED_CONTENT_INFO *signedCert)
+static BOOL CRYPT_VerifySignature(HCRYPTPROV_LEGACY hCryptProv, DWORD dwCertEncodingType,
+ CERT_PUBLIC_KEY_INFO *pubKeyInfo, const CERT_SIGNED_CONTENT_INFO *signedCert, const CRYPT_OID_INFO *info)
{
BOOL ret;
HCRYPTKEY key;
- PCCRYPT_OID_INFO info;
ALG_ID pubKeyID, hashID;
- info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
- signedCert->SignatureAlgorithm.pszObjId, 0);
- if (!info || info->dwGroupId != CRYPT_SIGN_ALG_OID_GROUP_ID)
- {
- SetLastError(NTE_BAD_ALGID);
- return FALSE;
- }
hashID = info->u.Algid;
if (info->ExtraInfo.cbData >= sizeof(ALG_ID))
pubKeyID = *(ALG_ID *)info->ExtraInfo.pbData;
@@ -2453,6 +2449,248 @@ static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV_LEGACY hCryptP
return ret;
}
+static BOOL CNG_CalcHash(const WCHAR *algorithm, const CERT_SIGNED_CONTENT_INFO *signedCert,
+ BYTE **hash_value, DWORD *hash_len)
+{
+ BCRYPT_HASH_HANDLE hash = NULL;
+ BCRYPT_ALG_HANDLE alg = NULL;
+ NTSTATUS status;
+ DWORD size;
+
+ if ((status = BCryptOpenAlgorithmProvider(&alg, algorithm, NULL, 0)))
+ goto done;
+
+ if ((status = BCryptCreateHash(alg, &hash, NULL, 0, NULL, 0, 0)))
+ goto done;
+
+ if ((status = BCryptHashData(hash, signedCert->ToBeSigned.pbData, signedCert->ToBeSigned.cbData, 0)))
+ goto done;
+
+ if ((status = BCryptGetProperty(hash, BCRYPT_HASH_LENGTH, (BYTE *)hash_len, sizeof(*hash_len), &size, 0)))
+ goto done;
+
+ if (!(*hash_value = CryptMemAlloc(*hash_len)))
+ {
+ status = STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ if ((status = BCryptFinishHash(hash, *hash_value, *hash_len, 0)))
+ {
+ CryptMemFree(*hash_value);
+ goto done;
+ }
+
+done:
+ if (hash) BCryptDestroyHash(hash);
+ if (alg) BCryptCloseAlgorithmProvider(alg, 0);
+ if (status) SetLastError(RtlNtStatusToDosError(status));
+ return status == 0;
+}
+
+static BOOL CNG_ImportECCPubKey(CERT_PUBLIC_KEY_INFO *pubKeyInfo, BCRYPT_KEY_HANDLE *key)
+{
+ DWORD blob_magic, ecckey_len, size;
+ BCRYPT_ALG_HANDLE alg = NULL;
+ BCRYPT_ECCKEY_BLOB *ecckey;
+ const WCHAR *sign_algo;
+ char **ecc_curve;
+ NTSTATUS status;
+
+ if (!pubKeyInfo->PublicKey.cbData)
+ {
+ SetLastError(NTE_BAD_ALGID);
+ return FALSE;
+ }
+
+ if (pubKeyInfo->PublicKey.pbData[0] != 0x4)
+ {
+ FIXME("Compressed ECC curves (%02x) not yet supported\n", pubKeyInfo->PublicKey.pbData[0]);
+ SetLastError(NTE_BAD_ALGID);
+ return FALSE;
+ }
+
+ if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_OBJECT_IDENTIFIER, pubKeyInfo->Algorithm.Parameters.pbData,
+ pubKeyInfo->Algorithm.Parameters.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &ecc_curve, &size))
+ return FALSE;
+
+ if (!strcmp(*ecc_curve, szOID_ECC_CURVE_P256))
+ {
+ sign_algo = BCRYPT_ECDSA_P256_ALGORITHM;
+ blob_magic = BCRYPT_ECDSA_PUBLIC_P256_MAGIC;
+ }
+ else if (!strcmp(*ecc_curve, szOID_ECC_CURVE_P384))
+ {
+ sign_algo = BCRYPT_ECDSA_P384_ALGORITHM;
+ blob_magic = BCRYPT_ECDSA_PUBLIC_P384_MAGIC;
+ }
+ else
+ {
+ FIXME("Unsupported ecc curve type: %s\n", *ecc_curve);
+ sign_algo = NULL;
+ blob_magic = 0;
+ }
+ LocalFree(ecc_curve);
+
+ if (!sign_algo)
+ {
+ SetLastError(NTE_BAD_ALGID);
+ return FALSE;
+ }
+
+ if ((status = BCryptOpenAlgorithmProvider(&alg, sign_algo, NULL, 0)))
+ goto done;
+
+ ecckey_len = sizeof(BCRYPT_ECCKEY_BLOB) + pubKeyInfo->PublicKey.cbData - 1;
+ if (!(ecckey = CryptMemAlloc(ecckey_len)))
+ {
+ status = STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ ecckey->dwMagic = blob_magic;
+ ecckey->cbKey = (pubKeyInfo->PublicKey.cbData - 1) / 2;
+ memcpy(ecckey + 1, pubKeyInfo->PublicKey.pbData + 1, pubKeyInfo->PublicKey.cbData - 1);
+
+ status = BCryptImportKeyPair(alg, NULL, BCRYPT_ECCPUBLIC_BLOB, key, (BYTE*)ecckey, ecckey_len, 0);
+
+done:
+ if (alg) BCryptCloseAlgorithmProvider(alg, 0);
+ if (status) SetLastError(RtlNtStatusToDosError(status));
+ return !status;
+}
+
+static BOOL CNG_ImportPubKey(CERT_PUBLIC_KEY_INFO *pubKeyInfo, BCRYPT_KEY_HANDLE *key)
+{
+ if (!strcmp(pubKeyInfo->Algorithm.pszObjId, szOID_ECC_PUBLIC_KEY))
+ return CNG_ImportECCPubKey(pubKeyInfo, key);
+
+ FIXME("Unsupported public key type: %s\n", debugstr_a(pubKeyInfo->Algorithm.pszObjId));
+ SetLastError(NTE_BAD_ALGID);
+ return FALSE;
+}
+
+static BOOL CNG_PrepareSignatureECC(BYTE *encoded_sig, DWORD encoded_size, BYTE **sig_value, DWORD *sig_len)
+{
+ CERT_ECC_SIGNATURE *ecc_sig;
+ DWORD size;
+ int i;
+
+ if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ECC_SIGNATURE, encoded_sig, encoded_size,
+ CRYPT_DECODE_ALLOC_FLAG, NULL, &ecc_sig, &size))
+ return FALSE;
+
+ if (!ecc_sig->r.cbData || !ecc_sig->s.cbData)
+ {
+ LocalFree(ecc_sig);
+ SetLastError(ERROR_INVALID_DATA);
+ return FALSE;
+ }
+
+ *sig_len = ecc_sig->r.cbData + ecc_sig->s.cbData;
+ if (!(*sig_value = CryptMemAlloc(*sig_len)))
+ {
+ LocalFree(ecc_sig);
+ SetLastError(ERROR_OUTOFMEMORY);
+ return FALSE;
+ }
+
+ for (i = 0; i < ecc_sig->r.cbData; i++)
+ (*sig_value)[i] = ecc_sig->r.pbData[ecc_sig->r.cbData - i - 1];
+ for (i = 0; i < ecc_sig->s.cbData; i++)
+ (*sig_value)[ecc_sig->r.cbData + i] = ecc_sig->s.pbData[ecc_sig->s.cbData - i - 1];
+
+ LocalFree(ecc_sig);
+ return TRUE;
+}
+
+static BOOL CNG_PrepareSignature(CERT_PUBLIC_KEY_INFO *pubKeyInfo, const CERT_SIGNED_CONTENT_INFO *signedCert,
+ BYTE **sig_value, DWORD *sig_len)
+{
+ BYTE *encoded_sig;
+ BOOL ret = FALSE;
+ int i;
+
+ if (!signedCert->Signature.cbData)
+ {
+ SetLastError(ERROR_INVALID_DATA);
+ return FALSE;
+ }
+
+ if (!(encoded_sig = CryptMemAlloc(signedCert->Signature.cbData)))
+ {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return FALSE;
+ }
+
+ for (i = 0; i < signedCert->Signature.cbData; i++)
+ encoded_sig[i] = signedCert->Signature.pbData[signedCert->Signature.cbData - i - 1];
+
+ if (!strcmp(pubKeyInfo->Algorithm.pszObjId, szOID_ECC_PUBLIC_KEY))
+ ret = CNG_PrepareSignatureECC(encoded_sig, signedCert->Signature.cbData, sig_value, sig_len);
+ else
+ {
+ FIXME("Unsupported public key type: %s\n", debugstr_a(pubKeyInfo->Algorithm.pszObjId));
+ SetLastError(NTE_BAD_ALGID);
+ }
+
+ CryptMemFree(encoded_sig);
+ return ret;
+}
+
+static BOOL CNG_VerifySignature(HCRYPTPROV_LEGACY hCryptProv, DWORD dwCertEncodingType,
+ CERT_PUBLIC_KEY_INFO *pubKeyInfo, const CERT_SIGNED_CONTENT_INFO *signedCert, const CRYPT_OID_INFO *info)
+{
+ BCRYPT_KEY_HANDLE key = NULL;
+ BYTE *hash_value = NULL, *sig_value;
+ DWORD hash_len, sig_len;
+ NTSTATUS status;
+ BOOL ret;
+
+ ret = CNG_ImportPubKey(pubKeyInfo, &key);
+ if (ret)
+ {
+ ret = CNG_CalcHash(info->pwszCNGAlgid, signedCert, &hash_value, &hash_len);
+ if (ret)
+ {
+ ret = CNG_PrepareSignature(pubKeyInfo, signedCert, &sig_value, &sig_len);
+ if (ret)
+ {
+ status = BCryptVerifySignature(key, NULL, hash_value, hash_len, sig_value, sig_len, 0);
+ if (status)
+ {
+ FIXME("Failed to verify signature: %08x\n", status);
+ SetLastError(RtlNtStatusToDosError(status));
+ ret = FALSE;
+ }
+ CryptMemFree(sig_value);
+ }
+ CryptMemFree(hash_value);
+ }
+ BCryptDestroyKey(key);
+ }
+
+ return ret;
+}
+
+static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv, DWORD dwCertEncodingType,
+ CERT_PUBLIC_KEY_INFO *pubKeyInfo, const CERT_SIGNED_CONTENT_INFO *signedCert)
+{
+ CCRYPT_OID_INFO *info;
+
+ info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, signedCert->SignatureAlgorithm.pszObjId, 0);
+ if (!info || info->dwGroupId != CRYPT_SIGN_ALG_OID_GROUP_ID)
+ {
+ SetLastError(NTE_BAD_ALGID);
+ return FALSE;
+ }
+
+ if (info->u.Algid == CALG_OID_INFO_CNG_ONLY)
+ return CNG_VerifySignature(hCryptProv, dwCertEncodingType, pubKeyInfo, signedCert, info);
+ else
+ return CRYPT_VerifySignature(hCryptProv, dwCertEncodingType, pubKeyInfo, signedCert, info);
+}
+
BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV_LEGACY hCryptProv,
DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject,
DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved)
--
2.18.0
June 26, 2018
[PATCH] msi: Remove checks for negative value.
by Hans Leidekker
From: Andrey Gusev <andrey.goosev(a)gmail.com>
Signed-off-by: Andrey Gusev <andrey.goosev(a)gmail.com>
Signed-off-by: Hans Leidekker <hans(a)codeweavers.com>
---
dlls/msi/format.c | 2 +-
dlls/msi/string.c | 5 ++---
dlls/msi/table.c | 4 +---
3 files changed, 4 insertions(+), 7 deletions(-)
diff --git a/dlls/msi/format.c b/dlls/msi/format.c
index 9356c9e30d..d32afb2a60 100644
--- a/dlls/msi/format.c
+++ b/dlls/msi/format.c
@@ -242,7 +242,7 @@ static WCHAR *deformat_file( FORMAT *format, FORMSTR *str, BOOL shortname, int *
if ((ret = strdupW( file->TargetPath ))) len = strlenW( ret );
goto done;
}
- if ((len = GetShortPathNameW(file->TargetPath, NULL, 0)) <= 0)
+ if (!(len = GetShortPathNameW(file->TargetPath, NULL, 0)))
{
if ((ret = strdupW( file->TargetPath ))) len = strlenW( ret );
goto done;
diff --git a/dlls/msi/string.c b/dlls/msi/string.c
index f094a53c9e..7383fddbed 100644
--- a/dlls/msi/string.c
+++ b/dlls/msi/string.c
@@ -233,7 +233,7 @@ static void set_st_entry( string_table *st, UINT n, WCHAR *str, int len, USHORT
static UINT string2id( const string_table *st, const char *buffer, UINT *id )
{
- DWORD sz;
+ int sz;
UINT r = ERROR_INVALID_PARAMETER;
LPWSTR str;
@@ -245,8 +245,7 @@ static UINT string2id( const string_table *st, const char *buffer, UINT *id )
return ERROR_SUCCESS;
}
- sz = MultiByteToWideChar( st->codepage, 0, buffer, -1, NULL, 0 );
- if( sz <= 0 )
+ if (!(sz = MultiByteToWideChar( st->codepage, 0, buffer, -1, NULL, 0 )))
return r;
str = msi_alloc( sz*sizeof(WCHAR) );
if( !str )
diff --git a/dlls/msi/table.c b/dlls/msi/table.c
index 45a181445a..e046c5c9e2 100644
--- a/dlls/msi/table.c
+++ b/dlls/msi/table.c
@@ -1279,9 +1279,7 @@ static UINT get_table_value_from_record( MSITABLEVIEW *tv, MSIRECORD *rec, UINT
UINT r;
int ival;
- if ( (iField <= 0) ||
- (iField > tv->num_cols) ||
- MSI_RecordIsNull( rec, iField ) )
+ if (!iField || iField > tv->num_cols || MSI_RecordIsNull( rec, iField ))
return ERROR_FUNCTION_FAILED;
columninfo = tv->columns[ iField - 1 ];
--
2.11.0
June 26, 2018
[PATCH] shell32: use characters as arguments to GetTempPathW and GetLongPathNameW
by Marcus Meissner
Signed-off-by: Marcus Meissner <marcus(a)jet.franken.de>
---
dlls/shell32/tests/shlfolder.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/shell32/tests/shlfolder.c b/dlls/shell32/tests/shlfolder.c
index 6460fd9381..bb303f66e4 100644
--- a/dlls/shell32/tests/shlfolder.c
+++ b/dlls/shell32/tests/shlfolder.c
@@ -244,8 +244,8 @@ todo_wine_if(parse_tests[i].todo)
CoTaskMemFree(pidl);
/* Relative paths are interpreted relative to the desktop. */
- GetTempPathW(sizeof(buffer), buffer);
- GetLongPathNameW(buffer, buffer, sizeof(buffer));
+ GetTempPathW(ARRAY_SIZE(buffer), buffer);
+ GetLongPathNameW(buffer, buffer, ARRAY_SIZE(buffer));
SetCurrentDirectoryW(buffer);
CreateDirectoryW(testdirW, NULL);
--
2.17.1
June 26, 2018
Re: [PATCH 5/5] include: Make fil_data.idl a common header.
by Marvin
Hi,
While running your changed tests on Windows, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at
https://testbot.winehq.org/JobDetails.pl?Key=39362
Your paranoid android.
=== w2008s64 (64 bit referenceclock) ===
TestBot process got stuck or died unexpectedly
The previous 1 run(s) terminated abnormally
June 26, 2018
[PATCH 5/5] include: Make fil_data.idl a common header.
by Zebediah Figura
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/devenum/Makefile.in | 3 +-
dlls/devenum/createdevenum.c | 2 +-
dlls/devenum/fil_data.idl | 47 --------------------------
dlls/dxdiagn/Makefile.in | 3 +-
dlls/dxdiagn/provider.c | 2 +-
dlls/quartz/Makefile.in | 1 -
dlls/quartz/fil_data.idl | 52 -----------------------------
dlls/quartz/filtermapper.c | 2 +-
dlls/quartz/tests/Makefile.in | 1 -
dlls/quartz/tests/fil_data.idl | 52 -----------------------------
dlls/quartz/tests/filtermapper.c | 2 +-
include/Makefile.in | 1 +
{dlls/dxdiagn => include/wine}/fil_data.idl | 21 ++----------
13 files changed, 10 insertions(+), 179 deletions(-)
delete mode 100644 dlls/devenum/fil_data.idl
delete mode 100644 dlls/quartz/fil_data.idl
delete mode 100644 dlls/quartz/tests/fil_data.idl
rename {dlls/dxdiagn => include/wine}/fil_data.idl (67%)
diff --git a/dlls/devenum/Makefile.in b/dlls/devenum/Makefile.in
index d1407a9..2760eed 100644
--- a/dlls/devenum/Makefile.in
+++ b/dlls/devenum/Makefile.in
@@ -9,7 +9,6 @@ C_SRCS = \
parsedisplayname.c
IDL_SRCS = \
- devenum_classes.idl \
- fil_data.idl
+ devenum_classes.idl
RC_SRCS = devenum.rc
diff --git a/dlls/devenum/createdevenum.c b/dlls/devenum/createdevenum.c
index 8275c99..c138cb7 100644
--- a/dlls/devenum/createdevenum.c
+++ b/dlls/devenum/createdevenum.c
@@ -37,7 +37,7 @@
#include "mmddk.h"
#include "initguid.h"
-#include "fil_data.h"
+#include "wine/fil_data.h"
WINE_DEFAULT_DEBUG_CHANNEL(devenum);
diff --git a/dlls/devenum/fil_data.idl b/dlls/devenum/fil_data.idl
deleted file mode 100644
index 7e37a75..0000000
--- a/dlls/devenum/fil_data.idl
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2009 Vitaliy Margolen
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#pragma makedep header
-
-import "objidl.idl";
-import "strmif.idl";
-import "unknwn.idl";
-
-
-/*****************************************************************************
- * IAMFilterData interface
- */
-[
- object,
- uuid(97f7c4d4-547b-4a5f-8332-536430ad2e4d),
- pointer_default(unique)
-]
-interface IAMFilterData : IUnknown
-{
- typedef [unique] IAMFilterData *LPIAMFILTERDATA;
-
- HRESULT ParseFilterData(
- [in] BYTE * rgbFilterData,
- [in] ULONG cb,
- [out] BYTE ** prgbRegFilter2);
-
- HRESULT CreateFilterData(
- [in] REGFILTER2 * prf2,
- [out] BYTE ** prgbFilterData,
- [out] ULONG * pcb);
-}
diff --git a/dlls/dxdiagn/Makefile.in b/dlls/dxdiagn/Makefile.in
index 3a1017e..c16396e 100644
--- a/dlls/dxdiagn/Makefile.in
+++ b/dlls/dxdiagn/Makefile.in
@@ -9,5 +9,4 @@ C_SRCS = \
RC_SRCS = dxdiagn.rc
IDL_SRCS = \
- dxdiagn.idl \
- fil_data.idl
+ dxdiagn.idl
diff --git a/dlls/dxdiagn/provider.c b/dlls/dxdiagn/provider.c
index 4f964ad..1fdab5e 100644
--- a/dlls/dxdiagn/provider.c
+++ b/dlls/dxdiagn/provider.c
@@ -35,7 +35,7 @@
#include "d3d9.h"
#include "strmif.h"
#include "initguid.h"
-#include "fil_data.h"
+#include "wine/fil_data.h"
#include "psapi.h"
#include "wbemcli.h"
diff --git a/dlls/quartz/Makefile.in b/dlls/quartz/Makefile.in
index e938865..5eb8d44 100644
--- a/dlls/quartz/Makefile.in
+++ b/dlls/quartz/Makefile.in
@@ -30,7 +30,6 @@ RC_SRCS = version.rc
IDL_SRCS = \
control_tlb.idl \
- fil_data.idl \
quartz_strmif.idl
dlldata_EXTRADEFS = -DENTRY_PREFIX=QUARTZ_ -DPROXY_DELEGATION -DWINE_REGISTER_DLL
diff --git a/dlls/quartz/fil_data.idl b/dlls/quartz/fil_data.idl
deleted file mode 100644
index ab93499..0000000
--- a/dlls/quartz/fil_data.idl
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2009 Vitaliy Margolen
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#pragma makedep header
-
-import "objidl.idl";
-import "strmif.idl";
-import "unknwn.idl";
-
-
-/*****************************************************************************
- * IAMFilterData interface
- *
- * Notes:
- * - This interface is deprecated and IFilterMapper2 should be used instead.
- * - There is no full replacement for IAMFilterData::ParseFilterData short of manually
- * parsing out the REGFILTER2 struct from the binary blob.
- */
-[
- object,
- uuid(97f7c4d4-547b-4a5f-8332-536430ad2e4d),
- pointer_default(unique)
-]
-interface IAMFilterData : IUnknown
-{
- typedef [unique] IAMFilterData *LPIAMFILTERDATA;
-
- HRESULT ParseFilterData(
- [in] BYTE * rgbFilterData,
- [in] ULONG cb,
- [out] BYTE ** prgbRegFilter2);
-
- HRESULT CreateFilterData(
- [in] REGFILTER2 * prf2,
- [out] BYTE ** prgbFilterData,
- [out] ULONG * pcb);
-}
diff --git a/dlls/quartz/filtermapper.c b/dlls/quartz/filtermapper.c
index 20c7e3a..d78f643 100644
--- a/dlls/quartz/filtermapper.c
+++ b/dlls/quartz/filtermapper.c
@@ -37,7 +37,7 @@
#include "wine/unicode.h"
#include "uuids.h"
#include "initguid.h"
-#include "fil_data.h"
+#include "wine/fil_data.h"
#include "wine/debug.h"
diff --git a/dlls/quartz/tests/Makefile.in b/dlls/quartz/tests/Makefile.in
index 4f54666..6b880c3 100644
--- a/dlls/quartz/tests/Makefile.in
+++ b/dlls/quartz/tests/Makefile.in
@@ -12,7 +12,6 @@ C_SRCS = \
referenceclock.c \
videorenderer.c
-IDL_SRCS = fil_data.idl
RC_SRCS = \
rsrc.rc
diff --git a/dlls/quartz/tests/fil_data.idl b/dlls/quartz/tests/fil_data.idl
deleted file mode 100644
index ab93499..0000000
--- a/dlls/quartz/tests/fil_data.idl
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2009 Vitaliy Margolen
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#pragma makedep header
-
-import "objidl.idl";
-import "strmif.idl";
-import "unknwn.idl";
-
-
-/*****************************************************************************
- * IAMFilterData interface
- *
- * Notes:
- * - This interface is deprecated and IFilterMapper2 should be used instead.
- * - There is no full replacement for IAMFilterData::ParseFilterData short of manually
- * parsing out the REGFILTER2 struct from the binary blob.
- */
-[
- object,
- uuid(97f7c4d4-547b-4a5f-8332-536430ad2e4d),
- pointer_default(unique)
-]
-interface IAMFilterData : IUnknown
-{
- typedef [unique] IAMFilterData *LPIAMFILTERDATA;
-
- HRESULT ParseFilterData(
- [in] BYTE * rgbFilterData,
- [in] ULONG cb,
- [out] BYTE ** prgbRegFilter2);
-
- HRESULT CreateFilterData(
- [in] REGFILTER2 * prf2,
- [out] BYTE ** prgbFilterData,
- [out] ULONG * pcb);
-}
diff --git a/dlls/quartz/tests/filtermapper.c b/dlls/quartz/tests/filtermapper.c
index 5a43785..7b6a018 100644
--- a/dlls/quartz/tests/filtermapper.c
+++ b/dlls/quartz/tests/filtermapper.c
@@ -26,7 +26,7 @@
#include "dshow.h"
#include "winternl.h"
-#include "fil_data.h"
+#include "wine/fil_data.h"
DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
diff --git a/include/Makefile.in b/include/Makefile.in
index 39f2691..995544a 100644
--- a/include/Makefile.in
+++ b/include/Makefile.in
@@ -664,6 +664,7 @@ SOURCES = \
windowsx.h \
wine/debug.h \
wine/exception.h \
+ wine/fil_data.idl \
wine/itss.idl \
wine/library.h \
wine/svcctl.idl \
diff --git a/dlls/dxdiagn/fil_data.idl b/include/wine/fil_data.idl
similarity index 67%
rename from dlls/dxdiagn/fil_data.idl
rename to include/wine/fil_data.idl
index 7e37a75..19dfa8a 100644
--- a/dlls/dxdiagn/fil_data.idl
+++ b/include/wine/fil_data.idl
@@ -16,16 +16,9 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
-#pragma makedep header
-
-import "objidl.idl";
-import "strmif.idl";
import "unknwn.idl";
+import "strmif.idl";
-
-/*****************************************************************************
- * IAMFilterData interface
- */
[
object,
uuid(97f7c4d4-547b-4a5f-8332-536430ad2e4d),
@@ -33,15 +26,7 @@ import "unknwn.idl";
]
interface IAMFilterData : IUnknown
{
- typedef [unique] IAMFilterData *LPIAMFILTERDATA;
+ HRESULT ParseFilterData( [in] BYTE *data, [in] ULONG size, [out] BYTE **regfilter );
- HRESULT ParseFilterData(
- [in] BYTE * rgbFilterData,
- [in] ULONG cb,
- [out] BYTE ** prgbRegFilter2);
-
- HRESULT CreateFilterData(
- [in] REGFILTER2 * prf2,
- [out] BYTE ** prgbFilterData,
- [out] ULONG * pcb);
+ HRESULT CreateFilterData( [in] REGFILTER2 *regfilter, [out] BYTE **data, [out] ULONG *size );
}
--
2.7.4
June 26, 2018
[PATCH 4/5] devenum: Remove an unused typedef.
by Zebediah Figura
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/devenum/devenum_main.c | 7 -------
1 file changed, 7 deletions(-)
diff --git a/dlls/devenum/devenum_main.c b/dlls/devenum/devenum_main.c
index 98ad1ad..b17bc93 100644
--- a/dlls/devenum/devenum_main.c
+++ b/dlls/devenum/devenum_main.c
@@ -28,13 +28,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(devenum);
DECLSPEC_HIDDEN LONG dll_refs;
static HINSTANCE devenum_instance;
-typedef struct
-{
- REFCLSID clsid;
- LPCWSTR friendly_name;
- BOOL instance;
-} register_info;
-
/***********************************************************************
* DllEntryPoint
*/
--
2.7.4
June 26, 2018
[PATCH 3/5] devenum: Make some variables static.
by Zebediah Figura
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/devenum/createdevenum.c | 14 ++++++--------
dlls/devenum/devenum_main.c | 13 ++++---------
dlls/devenum/devenum_private.h | 4 +---
dlls/devenum/mediacatenum.c | 4 +++-
4 files changed, 14 insertions(+), 21 deletions(-)
diff --git a/dlls/devenum/createdevenum.c b/dlls/devenum/createdevenum.c
index 06c264c..8275c99 100644
--- a/dlls/devenum/createdevenum.c
+++ b/dlls/devenum/createdevenum.c
@@ -41,8 +41,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(devenum);
-extern HINSTANCE DEVENUM_hInstance;
-
static const WCHAR wszFilterKeyName[] = {'F','i','l','t','e','r',0};
static const WCHAR wszMeritName[] = {'M','e','r','i','t',0};
static const WCHAR wszPins[] = {'P','i','n','s',0};
@@ -460,7 +458,7 @@ static void register_legacy_filters(void)
V_VT(&var) = VT_BSTR;
if (!(V_BSTR(&var) = SysAllocString(wszFilterSubkeyName)))
goto cleanup;
- hr = IPropertyBag_Write(prop_bag, clsid_keyname, &var);
+ hr = IPropertyBag_Write(prop_bag, clsidW, &var);
if (FAILED(hr)) goto cleanup;
VariantClear(&var);
@@ -537,7 +535,7 @@ static BOOL CALLBACK register_dsound_devices(GUID *guid, const WCHAR *desc, cons
StringFromGUID2(&CLSID_DSoundRender, clsid, CHARS_IN_GUID);
if (!(V_BSTR(&var) = SysAllocString(clsid)))
goto cleanup;
- hr = IPropertyBag_Write(prop_bag, clsid_keyname, &var);
+ hr = IPropertyBag_Write(prop_bag, clsidW, &var);
if (FAILED(hr)) goto cleanup;
VariantClear(&var);
@@ -620,7 +618,7 @@ static void register_waveout_devices(void)
StringFromGUID2(&CLSID_AudioRender, clsid, CHARS_IN_GUID);
if (!(V_BSTR(&var) = SysAllocString(clsid)))
goto cleanup;
- hr = IPropertyBag_Write(prop_bag, clsid_keyname, &var);
+ hr = IPropertyBag_Write(prop_bag, clsidW, &var);
if (FAILED(hr)) goto cleanup;
VariantClear(&var);
@@ -693,7 +691,7 @@ static void register_wavein_devices(void)
StringFromGUID2(&CLSID_AudioRecord, clsid, CHARS_IN_GUID);
if (!(V_BSTR(&var) = SysAllocString(clsid)))
goto cleanup;
- hr = IPropertyBag_Write(prop_bag, clsid_keyname, &var);
+ hr = IPropertyBag_Write(prop_bag, clsidW, &var);
if (FAILED(hr)) goto cleanup;
VariantClear(&var);
@@ -765,7 +763,7 @@ static void register_midiout_devices(void)
StringFromGUID2(&CLSID_AVIMIDIRender, clsid, CHARS_IN_GUID);
if (!(V_BSTR(&var) = SysAllocString(clsid)))
goto cleanup;
- hr = IPropertyBag_Write(prop_bag, clsid_keyname, &var);
+ hr = IPropertyBag_Write(prop_bag, clsidW, &var);
if (FAILED(hr)) goto cleanup;
VariantClear(&var);
@@ -854,7 +852,7 @@ static void register_vfw_codecs(void)
StringFromGUID2(&CLSID_AVICo, clsid, CHARS_IN_GUID);
if (!(V_BSTR(&var) = SysAllocString(clsid)))
goto cleanup;
- hr = IPropertyBag_Write(prop_bag, clsid_keyname, &var);
+ hr = IPropertyBag_Write(prop_bag, clsidW, &var);
if (FAILED(hr)) goto cleanup;
VariantClear(&var);
diff --git a/dlls/devenum/devenum_main.c b/dlls/devenum/devenum_main.c
index 3499f99..98ad1ad 100644
--- a/dlls/devenum/devenum_main.c
+++ b/dlls/devenum/devenum_main.c
@@ -26,7 +26,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(devenum);
DECLSPEC_HIDDEN LONG dll_refs;
-DECLSPEC_HIDDEN HINSTANCE DEVENUM_hInstance;
+static HINSTANCE devenum_instance;
typedef struct
{
@@ -36,11 +36,6 @@ typedef struct
} register_info;
/***********************************************************************
- * Global string constant definitions
- */
-const WCHAR clsid_keyname[6] = { 'C', 'L', 'S', 'I', 'D', 0 };
-
-/***********************************************************************
* DllEntryPoint
*/
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
@@ -49,7 +44,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
switch(fdwReason) {
case DLL_PROCESS_ATTACH:
- DEVENUM_hInstance = hinstDLL;
+ devenum_instance = hinstDLL;
DisableThreadLibraryCalls(hinstDLL);
break;
}
@@ -166,7 +161,7 @@ HRESULT WINAPI DllRegisterServer(void)
TRACE("\n");
- res = __wine_register_resources( DEVENUM_hInstance );
+ res = __wine_register_resources( devenum_instance );
if (FAILED(res))
return res;
@@ -214,5 +209,5 @@ HRESULT WINAPI DllRegisterServer(void)
HRESULT WINAPI DllUnregisterServer(void)
{
FIXME("stub!\n");
- return __wine_unregister_resources( DEVENUM_hInstance );
+ return __wine_unregister_resources( devenum_instance );
}
diff --git a/dlls/devenum/devenum_private.h b/dlls/devenum/devenum_private.h
index ea4e017..e18c57d 100644
--- a/dlls/devenum/devenum_private.h
+++ b/dlls/devenum/devenum_private.h
@@ -83,7 +83,7 @@ extern IParseDisplayName DEVENUM_ParseDisplayName DECLSPEC_HIDDEN;
*/
static const WCHAR backslashW[] = {'\\',0};
-static const WCHAR clsidW[] = {'C','L','S','I','D','\\',0};
+static const WCHAR clsidW[] = {'C','L','S','I','D',0};
static const WCHAR instanceW[] = {'\\','I','n','s','t','a','n','c','e',0};
static const WCHAR wszActiveMovieKey[] = {'S','o','f','t','w','a','r','e','\\',
'M','i','c','r','o','s','o','f','t','\\',
@@ -93,5 +93,3 @@ static const WCHAR deviceW[] = {'@','d','e','v','i','c','e',':',0};
static const WCHAR dmoW[] = {'d','m','o',':',0};
static const WCHAR swW[] = {'s','w',':',0};
static const WCHAR cmW[] = {'c','m',':',0};
-
-extern const WCHAR clsid_keyname[6] DECLSPEC_HIDDEN;
diff --git a/dlls/devenum/mediacatenum.c b/dlls/devenum/mediacatenum.c
index c4338a2..660e81c 100644
--- a/dlls/devenum/mediacatenum.c
+++ b/dlls/devenum/mediacatenum.c
@@ -347,6 +347,7 @@ static HRESULT create_PropertyBag(MediaCatMoniker *mon, IPropertyBag **ppBag)
else if (rpb->type == DEVICE_FILTER)
{
strcpyW(rpb->path, clsidW);
+ strcatW(rpb->path, backslashW);
if (mon->has_class)
{
StringFromGUID2(&mon->class, rpb->path + strlenW(rpb->path), CHARS_IN_GUID);
@@ -496,7 +497,7 @@ static HRESULT WINAPI DEVENUM_IMediaCatMoniker_BindToObject(IMoniker *iface, IBi
if (SUCCEEDED(res))
{
V_VT(&var) = VT_LPWSTR;
- res = IPropertyBag_Read(pProp, clsid_keyname, &var, NULL);
+ res = IPropertyBag_Read(pProp, clsidW, &var, NULL);
}
if (SUCCEEDED(res))
{
@@ -1027,6 +1028,7 @@ HRESULT create_EnumMoniker(REFCLSID class, IEnumMoniker **ppEnumMoniker)
pEnumMoniker->class = *class;
strcpyW(buffer, clsidW);
+ strcatW(buffer, backslashW);
StringFromGUID2(class, buffer + strlenW(buffer), CHARS_IN_GUID);
strcatW(buffer, instanceW);
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, buffer, 0, KEY_ENUMERATE_SUB_KEYS, &pEnumMoniker->sw_key))
--
2.7.4
June 26, 2018
[PATCH 2/5] devenum: Use separate factories for CLSID_SystemDeviceEnum and CLSID_CDeviceMoniker.
by Zebediah Figura
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/devenum/devenum_main.c | 46 +++++++++++++++++++++++----------------------
1 file changed, 24 insertions(+), 22 deletions(-)
diff --git a/dlls/devenum/devenum_main.c b/dlls/devenum/devenum_main.c
index 7bfc593..3499f99 100644
--- a/dlls/devenum/devenum_main.c
+++ b/dlls/devenum/devenum_main.c
@@ -56,6 +56,17 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
return TRUE;
}
+struct class_factory
+{
+ IClassFactory IClassFactory_iface;
+ IUnknown *obj;
+};
+
+static inline struct class_factory *impl_from_IClassFactory( IClassFactory *iface )
+{
+ return CONTAINING_RECORD( iface, struct class_factory, IClassFactory_iface );
+}
+
static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID iid, void **obj)
{
TRACE("(%p, %s, %p)\n", iface, debugstr_guid(iid), obj);
@@ -87,24 +98,15 @@ static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface,
IUnknown *outer, REFIID iid, void **obj)
{
+ struct class_factory *This = impl_from_IClassFactory( iface );
+
TRACE("(%p, %s, %p)\n", outer, debugstr_guid(iid), obj);
if (!obj) return E_POINTER;
if (outer) return CLASS_E_NOAGGREGATION;
- if (IsEqualGUID(&IID_ICreateDevEnum, iid))
- {
- *obj = &DEVENUM_CreateDevEnum;
- return S_OK;
- }
- if (IsEqualGUID(&IID_IParseDisplayName, iid))
- {
- *obj = &DEVENUM_ParseDisplayName;
- return S_OK;
- }
-
- return CLASS_E_CLASSNOTAVAILABLE;
+ return IUnknown_QueryInterface(This->obj, iid, obj);
}
static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL lock)
@@ -124,24 +126,24 @@ static const IClassFactoryVtbl ClassFactory_vtbl = {
ClassFactory_LockServer
};
-static IClassFactory devenum_cf = { &ClassFactory_vtbl };
+static struct class_factory create_devenum_cf = { { &ClassFactory_vtbl }, (IUnknown *)&DEVENUM_CreateDevEnum };
+static struct class_factory device_moniker_cf = { { &ClassFactory_vtbl }, (IUnknown *)&DEVENUM_ParseDisplayName };
/***********************************************************************
* DllGetClassObject (DEVENUM.@)
*/
-HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
+HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **obj)
{
- TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(iid), ppv);
+ TRACE("(%s, %s, %p)\n", debugstr_guid(clsid), debugstr_guid(iid), obj);
- *ppv = NULL;
+ *obj = NULL;
- /* FIXME: we should really have two class factories.
- * Oh well - works just fine as it is */
- if (IsEqualGUID(rclsid, &CLSID_SystemDeviceEnum) ||
- IsEqualGUID(rclsid, &CLSID_CDeviceMoniker))
- return IClassFactory_QueryInterface(&devenum_cf, iid, ppv);
+ if (IsEqualGUID(clsid, &CLSID_SystemDeviceEnum))
+ return IClassFactory_QueryInterface(&create_devenum_cf.IClassFactory_iface, iid, obj);
+ else if (IsEqualGUID(clsid, &CLSID_CDeviceMoniker))
+ return IClassFactory_QueryInterface(&device_moniker_cf.IClassFactory_iface, iid, obj);
- FIXME("CLSID: %s, IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
+ FIXME("class %s not available\n", debugstr_guid(clsid));
return CLASS_E_CLASSNOTAVAILABLE;
}
--
2.7.4
June 26, 2018
[PATCH 1/5] devenum: Merge factory.c into devenum_main.c.
by Zebediah Figura
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/devenum/Makefile.in | 1 -
dlls/devenum/devenum_main.c | 74 ++++++++++++++++++++++-
dlls/devenum/devenum_private.h | 10 ---
dlls/devenum/factory.c | 134 -----------------------------------------
4 files changed, 72 insertions(+), 147 deletions(-)
delete mode 100644 dlls/devenum/factory.c
diff --git a/dlls/devenum/Makefile.in b/dlls/devenum/Makefile.in
index ae138b6..d1407a9 100644
--- a/dlls/devenum/Makefile.in
+++ b/dlls/devenum/Makefile.in
@@ -5,7 +5,6 @@ DELAYIMPORTS = msvfw32
C_SRCS = \
createdevenum.c \
devenum_main.c \
- factory.c \
mediacatenum.c \
parsedisplayname.c
diff --git a/dlls/devenum/devenum_main.c b/dlls/devenum/devenum_main.c
index cb4b454..7bfc593 100644
--- a/dlls/devenum/devenum_main.c
+++ b/dlls/devenum/devenum_main.c
@@ -1,5 +1,5 @@
/*
- * exported dll functions for devenum.dll
+ * Device Enumeration
*
* Copyright (C) 2002 John K. Hohm
* Copyright (C) 2002 Robert Shearman
@@ -56,6 +56,76 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
return TRUE;
}
+static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID iid, void **obj)
+{
+ TRACE("(%p, %s, %p)\n", iface, debugstr_guid(iid), obj);
+
+ if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IClassFactory))
+ {
+ IClassFactory_AddRef(iface);
+ *obj = iface;
+ return S_OK;
+ }
+
+ *obj = NULL;
+ WARN("no interface for %s\n", debugstr_guid(iid));
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
+{
+ DEVENUM_LockModule();
+ return 2;
+}
+
+static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
+{
+ DEVENUM_UnlockModule();
+ return 1;
+}
+
+static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface,
+ IUnknown *outer, REFIID iid, void **obj)
+{
+ TRACE("(%p, %s, %p)\n", outer, debugstr_guid(iid), obj);
+
+ if (!obj) return E_POINTER;
+
+ if (outer) return CLASS_E_NOAGGREGATION;
+
+ if (IsEqualGUID(&IID_ICreateDevEnum, iid))
+ {
+ *obj = &DEVENUM_CreateDevEnum;
+ return S_OK;
+ }
+ if (IsEqualGUID(&IID_IParseDisplayName, iid))
+ {
+ *obj = &DEVENUM_ParseDisplayName;
+ return S_OK;
+ }
+
+ return CLASS_E_CLASSNOTAVAILABLE;
+}
+
+static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL lock)
+{
+ if (lock)
+ DEVENUM_LockModule();
+ else
+ DEVENUM_UnlockModule();
+ return S_OK;
+}
+
+static const IClassFactoryVtbl ClassFactory_vtbl = {
+ ClassFactory_QueryInterface,
+ ClassFactory_AddRef,
+ ClassFactory_Release,
+ ClassFactory_CreateInstance,
+ ClassFactory_LockServer
+};
+
+static IClassFactory devenum_cf = { &ClassFactory_vtbl };
+
/***********************************************************************
* DllGetClassObject (DEVENUM.@)
*/
@@ -69,7 +139,7 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
* Oh well - works just fine as it is */
if (IsEqualGUID(rclsid, &CLSID_SystemDeviceEnum) ||
IsEqualGUID(rclsid, &CLSID_CDeviceMoniker))
- return IClassFactory_QueryInterface(&DEVENUM_ClassFactory.IClassFactory_iface, iid, ppv);
+ return IClassFactory_QueryInterface(&devenum_cf, iid, ppv);
FIXME("CLSID: %s, IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
return CLASS_E_CLASSNOTAVAILABLE;
diff --git a/dlls/devenum/devenum_private.h b/dlls/devenum/devenum_private.h
index df0080d..ea4e017 100644
--- a/dlls/devenum/devenum_private.h
+++ b/dlls/devenum/devenum_private.h
@@ -51,15 +51,6 @@ extern LONG dll_refs DECLSPEC_HIDDEN;
static inline void DEVENUM_LockModule(void) { InterlockedIncrement(&dll_refs); }
static inline void DEVENUM_UnlockModule(void) { InterlockedDecrement(&dll_refs); }
-
-/**********************************************************************
- * ClassFactory declaration for devenum.dll
- */
-typedef struct
-{
- IClassFactory IClassFactory_iface;
-} ClassFactoryImpl;
-
enum device_type
{
DEVICE_FILTER,
@@ -84,7 +75,6 @@ typedef struct
MediaCatMoniker * DEVENUM_IMediaCatMoniker_Construct(void) DECLSPEC_HIDDEN;
HRESULT create_EnumMoniker(REFCLSID class, IEnumMoniker **enum_mon) DECLSPEC_HIDDEN;
-extern ClassFactoryImpl DEVENUM_ClassFactory DECLSPEC_HIDDEN;
extern ICreateDevEnum DEVENUM_CreateDevEnum DECLSPEC_HIDDEN;
extern IParseDisplayName DEVENUM_ParseDisplayName DECLSPEC_HIDDEN;
diff --git a/dlls/devenum/factory.c b/dlls/devenum/factory.c
deleted file mode 100644
index c808fa5..0000000
--- a/dlls/devenum/factory.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * ClassFactory implementation for DEVENUM.dll
- *
- * Copyright (C) 2002 John K. Hohm
- * Copyright (C) 2002 Robert Shearman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#include "devenum_private.h"
-
-#include "wine/debug.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(devenum);
-
-/**********************************************************************
- * DEVENUM_IClassFactory_QueryInterface (also IUnknown)
- */
-static HRESULT WINAPI DEVENUM_IClassFactory_QueryInterface(IClassFactory *iface, REFIID riid,
- void **ppvObj)
-{
- TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObj);
-
- if (ppvObj == NULL) return E_POINTER;
-
- if (IsEqualGUID(riid, &IID_IUnknown) ||
- IsEqualGUID(riid, &IID_IClassFactory))
- {
- *ppvObj = iface;
- IClassFactory_AddRef(iface);
- return S_OK;
- }
- else if (IsEqualGUID(riid, &IID_IParseDisplayName))
- {
- return IClassFactory_CreateInstance(iface, NULL, riid, ppvObj);
- }
-
- FIXME("- no interface IID: %s\n", debugstr_guid(riid));
- return E_NOINTERFACE;
-}
-
-/**********************************************************************
- * DEVENUM_IClassFactory_AddRef (also IUnknown)
- */
-static ULONG WINAPI DEVENUM_IClassFactory_AddRef(IClassFactory *iface)
-{
- TRACE("\n");
-
- DEVENUM_LockModule();
-
- return 2; /* non-heap based object */
-}
-
-/**********************************************************************
- * DEVENUM_IClassFactory_Release (also IUnknown)
- */
-static ULONG WINAPI DEVENUM_IClassFactory_Release(IClassFactory *iface)
-{
- TRACE("\n");
-
- DEVENUM_UnlockModule();
-
- return 1; /* non-heap based object */
-}
-
-/**********************************************************************
- * DEVENUM_IClassFactory_CreateInstance
- */
-static HRESULT WINAPI DEVENUM_IClassFactory_CreateInstance(IClassFactory *iface,
- IUnknown *pUnkOuter, REFIID riid, void **ppvObj)
-{
- TRACE("(%p)->(%p, %s, %p)\n", iface, pUnkOuter, debugstr_guid(riid), ppvObj);
-
- if (ppvObj == NULL) return E_POINTER;
-
- /* Don't support aggregation (Windows doesn't) */
- if (pUnkOuter != NULL) return CLASS_E_NOAGGREGATION;
-
- if (IsEqualGUID(&IID_ICreateDevEnum, riid))
- {
- *ppvObj = &DEVENUM_CreateDevEnum;
- return S_OK;
- }
- if (IsEqualGUID(&IID_IParseDisplayName, riid))
- {
- *ppvObj = &DEVENUM_ParseDisplayName;
- return S_OK;
- }
-
- return CLASS_E_CLASSNOTAVAILABLE;
-}
-
-/**********************************************************************
- * DEVENUM_IClassFactory_LockServer
- */
-static HRESULT WINAPI DEVENUM_IClassFactory_LockServer(IClassFactory *iface, BOOL fLock)
-{
- TRACE("\n");
-
- if (fLock)
- DEVENUM_LockModule();
- else
- DEVENUM_UnlockModule();
- return S_OK;
-}
-
-/**********************************************************************
- * IClassFactory_Vtbl
- */
-static const IClassFactoryVtbl IClassFactory_Vtbl =
-{
- DEVENUM_IClassFactory_QueryInterface,
- DEVENUM_IClassFactory_AddRef,
- DEVENUM_IClassFactory_Release,
- DEVENUM_IClassFactory_CreateInstance,
- DEVENUM_IClassFactory_LockServer
-};
-
-/**********************************************************************
- * static ClassFactory instance
- */
-ClassFactoryImpl DEVENUM_ClassFactory = { { &IClassFactory_Vtbl } };
--
2.7.4
June 26, 2018
[PATCH v2 3/3] comctl32/taskdialog: Add support for command links.
by Zhiyi Zhang
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/comctl32/taskdialog.c | 62 +++++++++++++++++++++++++++++---
dlls/comctl32/tests/taskdialog.c | 61 +++++++++++++++++--------------
2 files changed, 93 insertions(+), 30 deletions(-)
diff --git a/dlls/comctl32/taskdialog.c b/dlls/comctl32/taskdialog.c
index 207f77b012..42d50a93cb 100644
--- a/dlls/comctl32/taskdialog.c
+++ b/dlls/comctl32/taskdialog.c
@@ -60,6 +60,8 @@ struct taskdialog_info
HWND progress_bar;
HWND *radio_buttons;
INT radio_button_count;
+ HWND *command_links;
+ INT command_link_count;
HWND *buttons;
INT button_count;
HWND default_button;
@@ -184,7 +186,8 @@ static HWND taskdialog_find_button(HWND *buttons, INT count, INT id)
static void taskdialog_enable_button(const struct taskdialog_info *dialog_info, INT id, BOOL enable)
{
- HWND hwnd = taskdialog_find_button(dialog_info->buttons, dialog_info->button_count, id);
+ HWND hwnd = taskdialog_find_button(dialog_info->command_links, dialog_info->command_link_count, id);
+ if (!hwnd) hwnd = taskdialog_find_button(dialog_info->buttons, dialog_info->button_count, id);
if (hwnd) EnableWindow(hwnd, enable);
}
@@ -253,6 +256,11 @@ static BOOL taskdialog_hyperlink_enabled(struct taskdialog_info *dialog_info)
return dialog_info->taskconfig->dwFlags & TDF_ENABLE_HYPERLINKS;
}
+static BOOL taskdialog_use_command_link(struct taskdialog_info *dialog_info)
+{
+ return dialog_info->taskconfig->dwFlags & (TDF_USE_COMMAND_LINKS | TDF_USE_COMMAND_LINKS_NO_ICON);
+}
+
static void taskdialog_get_label_size(struct taskdialog_info *dialog_info, HWND hwnd, LONG max_width, SIZE *size,
BOOL syslink)
{
@@ -486,6 +494,34 @@ static void taskdialog_add_radio_buttons(struct taskdialog_info *dialog_info)
}
}
+static void taskdialog_add_command_links(struct taskdialog_info *dialog_info)
+{
+ const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig;
+ DWORD default_style = BS_MULTILINE | BS_LEFT | BS_TOP | WS_CHILD | WS_VISIBLE | WS_TABSTOP, style;
+ BOOL is_default;
+ WCHAR *textW;
+ INT i;
+
+ if (!taskconfig->cButtons || !taskconfig->pButtons || !taskdialog_use_command_link(dialog_info)) return;
+
+ dialog_info->command_links = Alloc(taskconfig->cButtons * sizeof(*dialog_info->command_links));
+ if (!dialog_info->command_links) return;
+
+ dialog_info->command_link_count = taskconfig->cButtons;
+ for (i = 0; i < dialog_info->command_link_count; i++)
+ {
+ is_default = taskconfig->pButtons[i].nButtonID == taskconfig->nDefaultButton;
+ style = is_default ? default_style | BS_DEFCOMMANDLINK : default_style | BS_COMMANDLINK;
+ textW = taskdialog_gettext(dialog_info, TRUE, taskconfig->pButtons[i].pszButtonText);
+ dialog_info->command_links[i] = CreateWindowW(WC_BUTTONW, textW, style, 0, 0, 0, 0, dialog_info->hwnd,
+ (HMENU)taskconfig->pButtons[i].nButtonID, 0, NULL);
+ SendMessageW(dialog_info->command_links[i], WM_SETFONT, (WPARAM)dialog_info->font, 0);
+ Free(textW);
+
+ if (is_default && !dialog_info->default_button) dialog_info->default_button = dialog_info->command_links[i];
+ }
+}
+
static void taskdialog_add_button(struct taskdialog_info *dialog_info, HWND *button, INT_PTR id, const WCHAR *text,
BOOL custom_button)
{
@@ -504,17 +540,18 @@ static void taskdialog_add_button(struct taskdialog_info *dialog_info, HWND *but
static void taskdialog_add_buttons(struct taskdialog_info *dialog_info)
{
const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig;
+ BOOL use_command_links = taskdialog_use_command_link(dialog_info);
DWORD flags = taskconfig->dwCommonButtons;
INT count, max_count;
/* Allocate enough memory for the custom and the default buttons. Maximum 6 default buttons possible. */
max_count = 6;
- if (taskconfig->cButtons && taskconfig->pButtons) max_count += taskconfig->cButtons;
+ if (!use_command_links && taskconfig->cButtons && taskconfig->pButtons) max_count += taskconfig->cButtons;
dialog_info->buttons = Alloc(max_count * sizeof(*dialog_info->buttons));
if (!dialog_info->buttons) return;
- for (count = 0; count < taskconfig->cButtons; count++)
+ for (count = 0; !use_command_links && count < taskconfig->cButtons; count++)
taskdialog_add_button(dialog_info, &dialog_info->buttons[count], taskconfig->pButtons[count].nButtonID,
taskconfig->pButtons[count].pszButtonText, TRUE);
@@ -532,7 +569,7 @@ static void taskdialog_add_buttons(struct taskdialog_info *dialog_info)
if (flags & TDCBF_CANCEL_BUTTON) TASKDIALOG_INIT_COMMON_BUTTON(CANCEL);
if (flags & TDCBF_CLOSE_BUTTON) TASKDIALOG_INIT_COMMON_BUTTON(CLOSE);
- if (!count) TASKDIALOG_INIT_COMMON_BUTTON(OK);
+ if (!count && !dialog_info->command_link_count) TASKDIALOG_INIT_COMMON_BUTTON(OK);
#undef TASKDIALOG_INIT_COMMON_BUTTON
dialog_info->button_count = count;
@@ -621,6 +658,19 @@ static void taskdialog_layout(struct taskdialog_info *dialog_info)
dialog_height = y + size.cy;
}
+ /* Command links */
+ for (i = 0; i < dialog_info->command_link_count; i++)
+ {
+ x = main_icon_right + h_spacing;
+ y = dialog_height + v_spacing;
+ taskdialog_get_label_size(dialog_info, dialog_info->command_links[i], dialog_width - x - h_spacing, &size, FALSE);
+ size.cx = dialog_width - x - h_spacing;
+ /* Add spacing */
+ size.cy += 4;
+ SetWindowPos(dialog_info->command_links[i], 0, x, y, size.cx, size.cy, SWP_NOZORDER);
+ dialog_height = y + size.cy;
+ }
+
dialog_height = max(dialog_height, main_icon_bottom);
/* Common and custom buttons */
@@ -756,9 +806,12 @@ static void taskdialog_init(struct taskdialog_info *dialog_info, HWND hwnd)
taskdialog_add_content(dialog_info);
taskdialog_add_progress_bar(dialog_info);
taskdialog_add_radio_buttons(dialog_info);
+ taskdialog_add_command_links(dialog_info);
taskdialog_add_buttons(dialog_info);
/* Set default button */
+ if (!dialog_info->default_button && dialog_info->command_links)
+ dialog_info->default_button = dialog_info->command_links[0];
if (!dialog_info->default_button) dialog_info->default_button = dialog_info->buttons[0];
SendMessageW(dialog_info->hwnd, WM_NEXTDLGCTL, (WPARAM)dialog_info->default_button, TRUE);
id = GetWindowLongW(dialog_info->default_button, GWLP_ID);
@@ -774,6 +827,7 @@ static void taskdialog_destroy(struct taskdialog_info *dialog_info)
if (dialog_info->main_instruction_font) DeleteObject(dialog_info->main_instruction_font);
if (dialog_info->buttons) Free(dialog_info->buttons);
if (dialog_info->radio_buttons) Free(dialog_info->radio_buttons);
+ if (dialog_info->command_links) Free(dialog_info->command_links);
}
static INT_PTR CALLBACK taskdialog_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
diff --git a/dlls/comctl32/tests/taskdialog.c b/dlls/comctl32/tests/taskdialog.c
index 2cda04081f..33d3757308 100644
--- a/dlls/comctl32/tests/taskdialog.c
+++ b/dlls/comctl32/tests/taskdialog.c
@@ -323,7 +323,7 @@ static void test_callback(void)
static void test_buttons(void)
{
TASKDIALOGCONFIG info = {0};
-
+ static const DWORD command_link_flags[] = {0, TDF_USE_COMMAND_LINKS, TDF_USE_COMMAND_LINKS_NO_ICON};
TASKDIALOG_BUTTON custom_buttons[TEST_NUM_BUTTONS], radio_buttons[TEST_NUM_RADIO_BUTTONS];
const WCHAR button_format[] = {'%','0','2','d',0};
/* Each button has two digits as title, plus null-terminator */
@@ -373,31 +373,40 @@ static void test_buttons(void)
info.dwCommonButtons = TDCBF_CANCEL_BUTTON | TDCBF_CLOSE_BUTTON;
run_test(&info, IDCANCEL, 0, msg_return_press_cancel, "default button: unset default");
- /* Test with all common and custom buttons and invalid default ID */
- info.nDefaultButton = 0xff; /* Random ID, should also default to first created button */
- info.cButtons = TEST_NUM_BUTTONS;
- info.pButtons = custom_buttons;
- run_test(&info, ID_START_BUTTON, 0, msg_return_press_custom1, "default button: invalid default, with common buttons - 1");
-
- info.nDefaultButton = -1; /* Should work despite button ID -1 */
- run_test(&info, -1, 0, msg_return_press_custom10, "default button: invalid default, with common buttons - 2");
-
- info.nDefaultButton = -2; /* Should also default to first created button */
- run_test(&info, ID_START_BUTTON, 0, msg_return_press_custom1, "default button: invalid default, with common buttons - 3");
-
- /* Test with only custom buttons and invalid default ID */
- info.dwCommonButtons = 0;
- run_test(&info, ID_START_BUTTON, 0, msg_return_press_custom1, "default button: invalid default, no common buttons");
-
- /* Test with common and custom buttons and valid default ID */
- info.dwCommonButtons = TDCBF_OK_BUTTON | TDCBF_YES_BUTTON | TDCBF_NO_BUTTON
- | TDCBF_CANCEL_BUTTON | TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON;
- info.nDefaultButton = IDRETRY;
- run_test(&info, IDRETRY, 0, msg_return_press_retry, "default button: valid default - 1");
-
- /* Test with common and custom buttons and valid default ID */
- info.nDefaultButton = ID_START_BUTTON + 3;
- run_test(&info, ID_START_BUTTON + 3, 0, msg_return_press_custom4, "default button: valid default - 2");
+ /* Custom buttons could be command links */
+ for (i = 0; i < ARRAY_SIZE(command_link_flags); i++)
+ {
+ info.dwFlags = command_link_flags[i];
+
+ /* Test with all common and custom buttons and invalid default ID */
+ info.nDefaultButton = 0xff; /* Random ID, should also default to first created button */
+ info.cButtons = TEST_NUM_BUTTONS;
+ info.pButtons = custom_buttons;
+ run_test(&info, ID_START_BUTTON, 0, msg_return_press_custom1,
+ "default button: invalid default, with common buttons - 1");
+
+ info.nDefaultButton = -1; /* Should work despite button ID -1 */
+ run_test(&info, -1, 0, msg_return_press_custom10, "default button: invalid default, with common buttons - 2");
+
+ info.nDefaultButton = -2; /* Should also default to first created button */
+ run_test(&info, ID_START_BUTTON, 0, msg_return_press_custom1,
+ "default button: invalid default, with common buttons - 3");
+
+ /* Test with only custom buttons and invalid default ID */
+ info.dwCommonButtons = 0;
+ run_test(&info, ID_START_BUTTON, 0, msg_return_press_custom1,
+ "default button: invalid default, no common buttons");
+
+ /* Test with common and custom buttons and valid default ID */
+ info.dwCommonButtons = TDCBF_OK_BUTTON | TDCBF_YES_BUTTON | TDCBF_NO_BUTTON | TDCBF_CANCEL_BUTTON
+ | TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON;
+ info.nDefaultButton = IDRETRY;
+ run_test(&info, IDRETRY, 0, msg_return_press_retry, "default button: valid default - 1");
+
+ /* Test with common and custom buttons and valid default ID */
+ info.nDefaultButton = ID_START_BUTTON + 3;
+ run_test(&info, ID_START_BUTTON + 3, 0, msg_return_press_custom4, "default button: valid default - 2");
+ }
/* Test radio buttons */
info.nDefaultButton = 0;
--
2.17.1
June 26, 2018
[PATCH v2 2/3] comctl32/taskdialog: Add support for radio buttons.
by Zhiyi Zhang
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/comctl32/taskdialog.c | 139 ++++++++++++++++++++++++-
dlls/comctl32/tests/taskdialog.c | 172 +++++++++++++++++++++++++++----
2 files changed, 290 insertions(+), 21 deletions(-)
diff --git a/dlls/comctl32/taskdialog.c b/dlls/comctl32/taskdialog.c
index 5625f2bc24..207f77b012 100644
--- a/dlls/comctl32/taskdialog.c
+++ b/dlls/comctl32/taskdialog.c
@@ -58,6 +58,8 @@ struct taskdialog_info
HWND main_instruction;
HWND content;
HWND progress_bar;
+ HWND *radio_buttons;
+ INT radio_button_count;
HWND *buttons;
INT button_count;
HWND default_button;
@@ -69,6 +71,7 @@ struct taskdialog_info
LONG h_spacing;
LONG v_spacing;
} m;
+ INT selected_radio_id;
};
struct button_layout_info
@@ -185,6 +188,18 @@ static void taskdialog_enable_button(const struct taskdialog_info *dialog_info,
if (hwnd) EnableWindow(hwnd, enable);
}
+static void taskdialog_enable_radio_button(const struct taskdialog_info *dialog_info, INT id, BOOL enable)
+{
+ HWND hwnd = taskdialog_find_button(dialog_info->radio_buttons, dialog_info->radio_button_count, id);
+ if (hwnd) EnableWindow(hwnd, enable);
+}
+
+static void taskdialog_click_radio_button(const struct taskdialog_info *dialog_info, INT id)
+{
+ HWND hwnd = taskdialog_find_button(dialog_info->radio_buttons, dialog_info->radio_button_count, id);
+ if (hwnd) SendMessageW(hwnd, BM_CLICK, 0, 0);
+}
+
static HRESULT taskdialog_notify(struct taskdialog_info *dialog_info, UINT notification, WPARAM wparam, LPARAM lparam)
{
const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig;
@@ -193,8 +208,18 @@ static HRESULT taskdialog_notify(struct taskdialog_info *dialog_info, UINT notif
: S_OK;
}
-static void taskdialog_on_button_click(struct taskdialog_info *dialog_info, WORD command_id)
+static void taskdialog_on_button_click(struct taskdialog_info *dialog_info, INT command_id)
{
+ HWND radio_button;
+
+ radio_button = taskdialog_find_button(dialog_info->radio_buttons, dialog_info->radio_button_count, command_id);
+ if (radio_button)
+ {
+ dialog_info->selected_radio_id = command_id;
+ taskdialog_notify(dialog_info, TDN_RADIO_BUTTON_CLICKED, command_id, 0);
+ return;
+ }
+
if (taskdialog_notify(dialog_info, TDN_BUTTON_CLICKED, command_id, 0) == S_OK)
EndDialog(dialog_info->hwnd, command_id);
}
@@ -269,6 +294,49 @@ static void taskdialog_get_label_size(struct taskdialog_info *dialog_info, HWND
Free(text);
}
+static void taskdialog_get_radio_button_size(struct taskdialog_info *dialog_info, HWND hwnd, LONG max_width, SIZE *size)
+{
+ DWORD style = DT_EXPANDTABS | DT_CALCRECT | DT_WORDBREAK;
+ HFONT hfont, old_hfont;
+ HDC hdc;
+ RECT rect = {0};
+ INT text_length;
+ WCHAR *text;
+ INT text_offset, radio_box_width, radio_box_height;
+
+ hdc = GetDC(hwnd);
+ hfont = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0);
+ old_hfont = SelectObject(hdc, hfont);
+
+ radio_box_width = 12 * GetDeviceCaps(hdc, LOGPIXELSX) / 96 + 1;
+ radio_box_height = 12 * GetDeviceCaps(hdc, LOGPIXELSY) / 96 + 1;
+ GetCharWidthW(hdc, '0', '0', &text_offset);
+ text_offset /= 2;
+
+ if (dialog_info->taskconfig->dwFlags & TDF_RTL_LAYOUT)
+ style |= DT_RIGHT | DT_RTLREADING;
+ else
+ style |= DT_LEFT;
+
+ rect.right = max_width - radio_box_width - text_offset;
+ text_length = GetWindowTextLengthW(hwnd);
+ text = Alloc((text_length + 1) * sizeof(WCHAR));
+ if (!text)
+ {
+ size->cx = 0;
+ size->cy = 0;
+ return;
+ }
+ GetWindowTextW(hwnd, text, text_length + 1);
+ size->cy = DrawTextW(hdc, text, text_length, &rect, style);
+ size->cx = min(max_width - radio_box_width - text_offset, rect.right - rect.left);
+ size->cx += radio_box_width + text_offset;
+ size->cy = max(size->cy, radio_box_height);
+ if (old_hfont) SelectObject(hdc, old_hfont);
+ Free(text);
+ ReleaseDC(hwnd, hdc);
+}
+
static ULONG_PTR taskdialog_get_standard_icon(LPCWSTR icon)
{
if (icon == TD_WARNING_ICON)
@@ -309,6 +377,28 @@ static void taskdialog_set_icon(struct taskdialog_info *dialog_info, INT element
}
}
+static void taskdialog_check_default_radio_buttons(struct taskdialog_info *dialog_info)
+{
+ const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig;
+ HWND default_button;
+ INT id;
+
+ if (!dialog_info->radio_button_count) return;
+
+ default_button = taskdialog_find_button(dialog_info->radio_buttons, dialog_info->radio_button_count,
+ taskconfig->nDefaultRadioButton);
+
+ if (!default_button && !(taskconfig->dwFlags & TDF_NO_DEFAULT_RADIO_BUTTON))
+ default_button = dialog_info->radio_buttons[0];
+
+ if (default_button)
+ {
+ SendMessageW(default_button, BM_SETCHECK, BST_CHECKED, 0);
+ id = GetWindowLongW(default_button, GWLP_ID);
+ taskdialog_on_button_click(dialog_info, id);
+ }
+}
+
static void taskdialog_add_main_icon(struct taskdialog_info *dialog_info)
{
if (!dialog_info->taskconfig->u.hMainIcon) return;
@@ -372,6 +462,30 @@ static void taskdialog_add_progress_bar(struct taskdialog_info *dialog_info)
CreateWindowW(PROGRESS_CLASSW, NULL, style, 0, 0, 0, 0, dialog_info->hwnd, NULL, 0, NULL);
}
+static void taskdialog_add_radio_buttons(struct taskdialog_info *dialog_info)
+{
+ const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig;
+ static const DWORD style = BS_AUTORADIOBUTTON | BS_MULTILINE | BS_TOP | WS_CHILD | WS_VISIBLE | WS_TABSTOP;
+ WCHAR *textW;
+ INT i;
+
+ if (!taskconfig->cRadioButtons || !taskconfig->pRadioButtons) return;
+
+ dialog_info->radio_buttons = Alloc(taskconfig->cRadioButtons * sizeof(*dialog_info->radio_buttons));
+ if (!dialog_info->radio_buttons) return;
+
+ dialog_info->radio_button_count = taskconfig->cRadioButtons;
+ for (i = 0; i < dialog_info->radio_button_count; i++)
+ {
+ textW = taskdialog_gettext(dialog_info, TRUE, taskconfig->pRadioButtons[i].pszButtonText);
+ dialog_info->radio_buttons[i] =
+ CreateWindowW(WC_BUTTONW, textW, i == 0 ? style | WS_GROUP : style, 0, 0, 0, 0, dialog_info->hwnd,
+ (HMENU)taskconfig->pRadioButtons[i].nButtonID, 0, NULL);
+ SendMessageW(dialog_info->radio_buttons[i], WM_SETFONT, (WPARAM)dialog_info->font, 0);
+ Free(textW);
+ }
+}
+
static void taskdialog_add_button(struct taskdialog_info *dialog_info, HWND *button, INT_PTR id, const WCHAR *text,
BOOL custom_button)
{
@@ -496,6 +610,17 @@ static void taskdialog_layout(struct taskdialog_info *dialog_info)
dialog_height = y + size.cy;
}
+ /* Radio buttons */
+ for (i = 0; i < dialog_info->radio_button_count; i++)
+ {
+ x = main_icon_right + h_spacing;
+ y = dialog_height;
+ taskdialog_get_radio_button_size(dialog_info, dialog_info->radio_buttons[i], dialog_width - x - h_spacing, &size);
+ size.cx = dialog_width - x - h_spacing;
+ SetWindowPos(dialog_info->radio_buttons[i], 0, x, y, size.cx, size.cy, SWP_NOZORDER);
+ dialog_height = y + size.cy;
+ }
+
dialog_height = max(dialog_height, main_icon_bottom);
/* Common and custom buttons */
@@ -630,6 +755,7 @@ static void taskdialog_init(struct taskdialog_info *dialog_info, HWND hwnd)
taskdialog_add_main_instruction(dialog_info);
taskdialog_add_content(dialog_info);
taskdialog_add_progress_bar(dialog_info);
+ taskdialog_add_radio_buttons(dialog_info);
taskdialog_add_buttons(dialog_info);
/* Set default button */
@@ -647,6 +773,7 @@ static void taskdialog_destroy(struct taskdialog_info *dialog_info)
if (dialog_info->font) DeleteObject(dialog_info->font);
if (dialog_info->main_instruction_font) DeleteObject(dialog_info->main_instruction_font);
if (dialog_info->buttons) Free(dialog_info->buttons);
+ if (dialog_info->radio_buttons) Free(dialog_info->radio_buttons);
}
static INT_PTR CALLBACK taskdialog_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
@@ -698,6 +825,12 @@ static INT_PTR CALLBACK taskdialog_proc(HWND hwnd, UINT msg, WPARAM wParam, LPAR
case TDM_SET_PROGRESS_BAR_MARQUEE:
SendMessageW(dialog_info->progress_bar, PBM_SETMARQUEE, wParam, lParam);
break;
+ case TDM_CLICK_RADIO_BUTTON:
+ taskdialog_click_radio_button(dialog_info, wParam);
+ break;
+ case TDM_ENABLE_RADIO_BUTTON:
+ taskdialog_enable_radio_button(dialog_info, wParam, lParam);
+ break;
case WM_INITDIALOG:
dialog_info = (struct taskdialog_info *)lParam;
@@ -706,6 +839,8 @@ static INT_PTR CALLBACK taskdialog_proc(HWND hwnd, UINT msg, WPARAM wParam, LPAR
SetPropW(hwnd, taskdialog_info_propnameW, dialog_info);
taskdialog_notify(dialog_info, TDN_DIALOG_CONSTRUCTED, 0, 0);
taskdialog_notify(dialog_info, TDN_CREATED, 0, 0);
+ /* Default radio button click notification sent after TDN_CREATED */
+ taskdialog_check_default_radio_buttons(dialog_info);
return FALSE;
case WM_COMMAND:
if (HIWORD(wParam) == BN_CLICKED)
@@ -771,7 +906,7 @@ HRESULT WINAPI TaskDialogIndirect(const TASKDIALOGCONFIG *taskconfig, int *butto
Free(template);
if (button) *button = ret;
- if (radio_button) *radio_button = taskconfig->nDefaultButton;
+ if (radio_button) *radio_button = dialog_info.selected_radio_id;
if (verification_flag_checked) *verification_flag_checked = TRUE;
return S_OK;
diff --git a/dlls/comctl32/tests/taskdialog.c b/dlls/comctl32/tests/taskdialog.c
index e91a878876..2cda04081f 100644
--- a/dlls/comctl32/tests/taskdialog.c
+++ b/dlls/comctl32/tests/taskdialog.c
@@ -35,9 +35,11 @@
#define TASKDIALOG_SEQ_INDEX 0
#define TEST_NUM_BUTTONS 10 /* Number of custom buttons to test with */
+#define TEST_NUM_RADIO_BUTTONS 3
#define ID_START 20 /* Lower IDs might be used by the system */
#define ID_START_BUTTON (ID_START + 0)
+#define ID_START_RADIO_BUTTON (ID_START + 20)
static HRESULT (WINAPI *pTaskDialogIndirect)(const TASKDIALOGCONFIG *, int *, int *, BOOL *);
static HRESULT (WINAPI *pTaskDialog)(HWND, HINSTANCE, const WCHAR *, const WCHAR *, const WCHAR *,
@@ -141,6 +143,78 @@ static const struct message_info msg_got_tdn_help[] =
{ 0 }
};
+/* Three radio buttons */
+static const struct message_info msg_return_default_radio_button_1[] =
+{
+ { TDN_CREATED, 0, 0, S_OK, NULL },
+ { TDN_RADIO_BUTTON_CLICKED, ID_START_RADIO_BUTTON, 0, S_OK, msg_send_click_ok },
+ { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
+ { 0 }
+};
+
+static const struct message_info msg_return_default_radio_button_2[] =
+{
+ { TDN_CREATED, 0, 0, S_OK, NULL },
+ { TDN_RADIO_BUTTON_CLICKED, ID_START_RADIO_BUTTON + 1, 0, S_OK, msg_send_click_ok },
+ { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
+ { 0 }
+};
+
+static const struct message_info msg_return_default_radio_button_3[] =
+{
+ { TDN_CREATED, 0, 0, S_OK, NULL },
+ { TDN_RADIO_BUTTON_CLICKED, -2, 0, S_OK, msg_send_click_ok },
+ { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
+ { 0 }
+};
+
+static const struct message_info msg_select_first_radio_button[] =
+{
+ { TDM_CLICK_RADIO_BUTTON, ID_START_RADIO_BUTTON, 0 },
+ { 0 }
+};
+
+static const struct message_info msg_return_first_radio_button[] =
+{
+ { TDN_CREATED, 0, 0, S_OK, NULL },
+ { TDN_RADIO_BUTTON_CLICKED, ID_START_RADIO_BUTTON + 1, 0, S_OK, msg_select_first_radio_button },
+ { TDN_RADIO_BUTTON_CLICKED, ID_START_RADIO_BUTTON, 0, S_OK, msg_send_click_ok },
+ { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
+ { 0 }
+};
+
+static const struct message_info msg_select_first_disabled_radio_button_and_press_ok[] =
+{
+ { TDM_ENABLE_RADIO_BUTTON, ID_START_RADIO_BUTTON, 0 },
+ { TDM_CLICK_RADIO_BUTTON, ID_START_RADIO_BUTTON, 0 },
+ { TDM_CLICK_BUTTON, IDOK, 0 },
+ { 0 }
+};
+
+static const struct message_info msg_return_default_radio_button_clicking_disabled[] =
+{
+ { TDN_CREATED, 0, 0, S_OK, NULL },
+ { TDN_RADIO_BUTTON_CLICKED, ID_START_RADIO_BUTTON + 1, 0, S_OK, msg_select_first_disabled_radio_button_and_press_ok },
+ { TDN_RADIO_BUTTON_CLICKED, ID_START_RADIO_BUTTON, 0, S_OK, NULL },
+ { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
+ { 0 }
+};
+
+static const struct message_info msg_return_no_default_radio_button_flag[] =
+{
+ { TDN_CREATED, 0, 0, S_OK, msg_send_click_ok },
+ { TDN_RADIO_BUTTON_CLICKED, ID_START_RADIO_BUTTON, 0, S_OK, NULL },
+ { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
+ { 0 }
+};
+
+static const struct message_info msg_return_no_default_radio_button_id_and_flag[] =
+{
+ { TDN_CREATED, 0, 0, S_OK, msg_send_click_ok },
+ { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
+ { 0 }
+};
+
static void init_test_message(UINT message, WPARAM wParam, LPARAM lParam, struct message *msg)
{
msg->message = WM_TD_CALLBACK;
@@ -151,11 +225,13 @@ static void init_test_message(UINT message, WPARAM wParam, LPARAM lParam, struct
msg->stage = 0;
}
-#define run_test(info, expect_button, seq, context) \
- run_test_(info, expect_button, seq, context, ARRAY_SIZE(seq) - 1, __FILE__, __LINE__)
+#define run_test(info, expect_button, expect_radio_button, seq, context) \
+ run_test_(info, expect_button, expect_radio_button, seq, context, \
+ ARRAY_SIZE(seq) - 1, __FILE__, __LINE__)
-static void run_test_(TASKDIALOGCONFIG *info, int expect_button, const struct message_info *test_messages,
- const char *context, int test_messages_len, const char *file, int line)
+static void run_test_(TASKDIALOGCONFIG *info, int expect_button, int expect_radio_button,
+ const struct message_info *test_messages, const char *context, int test_messages_len,
+ const char *file, int line)
{
struct message *msg, *msg_start;
int ret_button = 0;
@@ -182,6 +258,8 @@ static void run_test_(TASKDIALOGCONFIG *info, int expect_button, const struct me
ok_sequence_(sequences, TASKDIALOG_SEQ_INDEX, msg_start, context, FALSE, file, line);
ok_(file, line)(ret_button == expect_button,
"Wrong button. Expected %d, got %d\n", expect_button, ret_button);
+ ok_(file, line)(ret_radio == expect_radio_button,
+ "Wrong radio button. Expected %d, got %d\n", expect_radio_button, ret_radio);
heap_free(msg_start);
}
@@ -239,16 +317,17 @@ static void test_callback(void)
info.pfCallback = taskdialog_callback_proc;
info.lpCallbackData = test_ref_data;
- run_test(&info, IDOK, msg_return_press_ok, "Press VK_RETURN.");
+ run_test(&info, IDOK, 0, msg_return_press_ok, "Press VK_RETURN.");
}
static void test_buttons(void)
{
TASKDIALOGCONFIG info = {0};
- TASKDIALOG_BUTTON custom_buttons[TEST_NUM_BUTTONS];
+ TASKDIALOG_BUTTON custom_buttons[TEST_NUM_BUTTONS], radio_buttons[TEST_NUM_RADIO_BUTTONS];
const WCHAR button_format[] = {'%','0','2','d',0};
- WCHAR button_titles[TEST_NUM_BUTTONS * 3]; /* Each button has two digits as title, plus null-terminator */
+ /* Each button has two digits as title, plus null-terminator */
+ WCHAR button_titles[TEST_NUM_BUTTONS * 3], radio_button_titles[TEST_NUM_BUTTONS * 3];
int i;
info.cbSize = sizeof(TASKDIALOGCONFIG);
@@ -266,48 +345,103 @@ static void test_buttons(void)
}
custom_buttons[TEST_NUM_BUTTONS - 1].nButtonID = -1;
+ /* Init radio buttons */
+ for (i = 0; i < TEST_NUM_RADIO_BUTTONS; i++)
+ {
+ WCHAR *text = &radio_button_titles[i * 3];
+ wsprintfW(text, button_format, i);
+
+ radio_buttons[i].pszButtonText = text;
+ radio_buttons[i].nButtonID = ID_START_RADIO_BUTTON + i;
+ }
+ radio_buttons[TEST_NUM_RADIO_BUTTONS - 1].nButtonID = -2;
+
/* Test nDefaultButton */
/* Test common buttons with invalid default ID */
info.nDefaultButton = 0; /* Should default to first created button */
info.dwCommonButtons = TDCBF_OK_BUTTON | TDCBF_YES_BUTTON | TDCBF_NO_BUTTON
| TDCBF_CANCEL_BUTTON | TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON;
- run_test(&info, IDOK, msg_return_press_ok, "default button: unset default");
+ run_test(&info, IDOK, 0, msg_return_press_ok, "default button: unset default");
info.dwCommonButtons = TDCBF_YES_BUTTON | TDCBF_NO_BUTTON
| TDCBF_CANCEL_BUTTON | TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON;
- run_test(&info, IDYES, msg_return_press_yes, "default button: unset default");
+ run_test(&info, IDYES, 0, msg_return_press_yes, "default button: unset default");
info.dwCommonButtons = TDCBF_NO_BUTTON | TDCBF_CANCEL_BUTTON | TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON;
- run_test(&info, IDNO, msg_return_press_no, "default button: unset default");
+ run_test(&info, IDNO, 0, msg_return_press_no, "default button: unset default");
info.dwCommonButtons = TDCBF_CANCEL_BUTTON | TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON;
- run_test(&info, IDRETRY, msg_return_press_retry, "default button: unset default");
+ run_test(&info, IDRETRY, 0, msg_return_press_retry, "default button: unset default");
info.dwCommonButtons = TDCBF_CANCEL_BUTTON | TDCBF_CLOSE_BUTTON;
- run_test(&info, IDCANCEL, msg_return_press_cancel, "default button: unset default");
+ run_test(&info, IDCANCEL, 0, msg_return_press_cancel, "default button: unset default");
/* Test with all common and custom buttons and invalid default ID */
info.nDefaultButton = 0xff; /* Random ID, should also default to first created button */
info.cButtons = TEST_NUM_BUTTONS;
info.pButtons = custom_buttons;
- run_test(&info, ID_START_BUTTON, msg_return_press_custom1, "default button: invalid default, with common buttons - 1");
+ run_test(&info, ID_START_BUTTON, 0, msg_return_press_custom1, "default button: invalid default, with common buttons - 1");
info.nDefaultButton = -1; /* Should work despite button ID -1 */
- run_test(&info, -1, msg_return_press_custom10, "default button: invalid default, with common buttons - 2");
+ run_test(&info, -1, 0, msg_return_press_custom10, "default button: invalid default, with common buttons - 2");
info.nDefaultButton = -2; /* Should also default to first created button */
- run_test(&info, ID_START_BUTTON, msg_return_press_custom1, "default button: invalid default, with common buttons - 3");
+ run_test(&info, ID_START_BUTTON, 0, msg_return_press_custom1, "default button: invalid default, with common buttons - 3");
/* Test with only custom buttons and invalid default ID */
info.dwCommonButtons = 0;
- run_test(&info, ID_START_BUTTON, msg_return_press_custom1, "default button: invalid default, no common buttons");
+ run_test(&info, ID_START_BUTTON, 0, msg_return_press_custom1, "default button: invalid default, no common buttons");
/* Test with common and custom buttons and valid default ID */
info.dwCommonButtons = TDCBF_OK_BUTTON | TDCBF_YES_BUTTON | TDCBF_NO_BUTTON
| TDCBF_CANCEL_BUTTON | TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON;
info.nDefaultButton = IDRETRY;
- run_test(&info, IDRETRY, msg_return_press_retry, "default button: valid default - 1");
+ run_test(&info, IDRETRY, 0, msg_return_press_retry, "default button: valid default - 1");
/* Test with common and custom buttons and valid default ID */
info.nDefaultButton = ID_START_BUTTON + 3;
- run_test(&info, ID_START_BUTTON + 3, msg_return_press_custom4, "default button: valid default - 2");
+ run_test(&info, ID_START_BUTTON + 3, 0, msg_return_press_custom4, "default button: valid default - 2");
+
+ /* Test radio buttons */
+ info.nDefaultButton = 0;
+ info.cButtons = 0;
+ info.pButtons = 0;
+ info.dwCommonButtons = TDCBF_OK_BUTTON;
+ info.cRadioButtons = TEST_NUM_RADIO_BUTTONS;
+ info.pRadioButtons = radio_buttons;
+
+ /* Test default first radio button */
+ run_test(&info, IDOK, ID_START_RADIO_BUTTON, msg_return_default_radio_button_1, "default radio button: default first radio button");
+
+ /* Test default radio button */
+ info.nDefaultRadioButton = ID_START_RADIO_BUTTON + 1;
+ run_test(&info, IDOK, info.nDefaultRadioButton, msg_return_default_radio_button_2, "default radio button: default radio button");
+
+ /* Test default radio button with -2 */
+ info.nDefaultRadioButton = -2;
+ run_test(&info, IDOK, info.nDefaultRadioButton, msg_return_default_radio_button_3, "default radio button: default radio button with id -2");
+
+ /* Test default radio button after clicking the first, messages still work even radio button is disabled */
+ info.nDefaultRadioButton = ID_START_RADIO_BUTTON + 1;
+ run_test(&info, IDOK, ID_START_RADIO_BUTTON, msg_return_first_radio_button, "default radio button: radio button after clicking");
+
+ /* Test radio button after disabling and clicking the first */
+ info.nDefaultRadioButton = ID_START_RADIO_BUTTON + 1;
+ run_test(&info, IDOK, ID_START_RADIO_BUTTON, msg_return_default_radio_button_clicking_disabled, "default radio button: disable radio button before clicking");
+
+ /* Test no default radio button, TDF_NO_DEFAULT_RADIO_BUTTON is set, TDN_RADIO_BUTTON_CLICKED will still be received, just radio button not selected */
+ info.nDefaultRadioButton = ID_START_RADIO_BUTTON;
+ info.dwFlags = TDF_NO_DEFAULT_RADIO_BUTTON;
+ run_test(&info, IDOK, info.nDefaultRadioButton, msg_return_no_default_radio_button_flag, "default radio button: no default radio flag");
+
+ /* Test no default radio button, TDF_NO_DEFAULT_RADIO_BUTTON is set and nDefaultRadioButton is 0.
+ * TDN_RADIO_BUTTON_CLICKED will not be sent, and just radio button not selected */
+ info.nDefaultRadioButton = 0;
+ info.dwFlags = TDF_NO_DEFAULT_RADIO_BUTTON;
+ run_test(&info, IDOK, 0, msg_return_no_default_radio_button_id_and_flag, "default radio button: no default radio id and flag");
+
+ /* Test no default radio button, TDF_NO_DEFAULT_RADIO_BUTTON is set and nDefaultRadioButton is invalid.
+ * TDN_RADIO_BUTTON_CLICKED will not be sent, and just radio button not selected */
+ info.nDefaultRadioButton = 0xff;
+ info.dwFlags = TDF_NO_DEFAULT_RADIO_BUTTON;
+ run_test(&info, IDOK, 0, msg_return_no_default_radio_button_id_and_flag, "default radio button: no default flag, invalid id");
}
static void test_help(void)
@@ -319,7 +453,7 @@ static void test_help(void)
info.lpCallbackData = test_ref_data;
info.dwCommonButtons = TDCBF_OK_BUTTON;
- run_test(&info, IDOK, msg_got_tdn_help, "send f1");
+ run_test(&info, IDOK, 0, msg_got_tdn_help, "send f1");
}
struct timer_notification_data
--
2.17.1
June 26, 2018
[PATCH v2 1/3] comctl32/taskdialog: Use dynamic buffer for taskdialog_get_label_size().
by Zhiyi Zhang
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/comctl32/taskdialog.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/dlls/comctl32/taskdialog.c b/dlls/comctl32/taskdialog.c
index 33fb578910..5625f2bc24 100644
--- a/dlls/comctl32/taskdialog.c
+++ b/dlls/comctl32/taskdialog.c
@@ -235,7 +235,7 @@ static void taskdialog_get_label_size(struct taskdialog_info *dialog_info, HWND
HFONT hfont, old_hfont;
HDC hdc;
RECT rect = {0};
- WCHAR text[1024];
+ WCHAR *text;
INT text_length;
if (syslink)
@@ -250,7 +250,15 @@ static void taskdialog_get_label_size(struct taskdialog_info *dialog_info, HWND
style |= DT_LEFT;
hfont = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0);
- text_length = GetWindowTextW(hwnd, text, ARRAY_SIZE(text));
+ text_length = GetWindowTextLengthW(hwnd);
+ text = Alloc((text_length + 1) * sizeof(WCHAR));
+ if (!text)
+ {
+ size->cx = 0;
+ size->cy = 0;
+ return;
+ }
+ GetWindowTextW(hwnd, text, text_length + 1);
hdc = GetDC(hwnd);
old_hfont = SelectObject(hdc, hfont);
rect.right = max_width;
@@ -258,6 +266,7 @@ static void taskdialog_get_label_size(struct taskdialog_info *dialog_info, HWND
size->cx = min(max_width, rect.right - rect.left);
if (old_hfont) SelectObject(hdc, old_hfont);
ReleaseDC(hwnd, hdc);
+ Free(text);
}
static ULONG_PTR taskdialog_get_standard_icon(LPCWSTR icon)
--
2.17.1
June 26, 2018
Re: [PATCH v2 4/4] winemac.drv: Implement waking up the display when activity occurs.
by Ken Thomases
This prevents display sleep and/or wakes a sleeping display, but doesn't prevent the screensaver from kicking in. We don't know why and don't see any other suitable API, so:
Signed-off-by: Ken Thomases <ken(a)codeweavers.com>
June 25, 2018
[PATCH 3/3] wsdapi: Send Probe Matches message via UDP unicast.
by Owen Rudge
Signed-off-by: Owen Rudge <orudge(a)codeweavers.com>
---
dlls/wsdapi/network.c | 32 ++++++++++++++++++++++++++++++++
dlls/wsdapi/soap.c | 4 ++--
dlls/wsdapi/tests/discovery.c | 22 +++++++++++-----------
dlls/wsdapi/wsdapi_internal.h | 1 +
4 files changed, 46 insertions(+), 13 deletions(-)
June 25, 2018