TaskDialogにWindowsAPICodePackを使用しています。ダイアログを表示しようとすると、バージョン 6 の comctl32.dll をロードする必要があると表示されます。ということで、app.manifestにバージョン6を追加して実行してみました。まだ運がありません。Debug フォルダーに移動し、Visual Studio を使用せずにプログラムを実行したところ、正常に動作しました。私は、Visual Studio がマニフェスト ファイルを使用していないと推測しています...これを行う方法があるかどうか疑問に思っていました。
4 に答える
最近、CodePack の TaskDialogDemo を使用してコードをデバッグしているときに、この問題に遭遇しました。これが私がそれを修正した方法です。これを使用する際の問題は、2 つまたは 3 つのダイアログを開くと SEHException がスローされることです。これを修正する方法がわかりません。バイヤーは注意してください。
Core\Interop\TaskDialogs\EnableThemingInScope.csを追加します。
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Windows.Forms;
namespace Microsoft.WindowsAPICodePack.Dialogs {
/// http://support.microsoft.com/kb/830033
/// <devdoc>
/// This class is intended to use with the C# 'using' statement in
/// to activate an activation context for turning on visual theming at
/// the beginning of a scope, and have it automatically deactivated
/// when the scope is exited.
/// </devdoc>
[SuppressUnmanagedCodeSecurity]
internal class EnableThemingInScope : IDisposable {
// Private data
private uint cookie;
private static ACTCTX enableThemingActivationContext;
[System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources" )]
private static IntPtr hActCtx;
private static bool contextCreationSucceeded = false;
public EnableThemingInScope( bool enable ) {
cookie = 0;
if ( enable && OSFeature.Feature.IsPresent( OSFeature.Themes ) ) {
if ( EnsureActivateContextCreated() ) {
if ( !ActivateActCtx( hActCtx, out cookie ) ) {
// Be sure cookie always zero if activation failed
cookie = 0;
}
}
}
}
~EnableThemingInScope() {
Dispose();
}
void IDisposable.Dispose() {
Dispose();
GC.SuppressFinalize( this );
}
private void Dispose() {
if ( cookie != 0 ) {
try {
if ( DeactivateActCtx( 0, cookie ) ) {
// deactivation succeeded...
cookie = 0;
}
} catch ( SEHException ) {
// Robpol86: I don't know how to fix this!
}
}
}
[System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity" )]
private static bool EnsureActivateContextCreated() {
lock ( typeof( EnableThemingInScope ) ) {
if ( !contextCreationSucceeded ) {
// Pull manifest from the .NET Framework install
// directory
string assemblyLoc = null;
FileIOPermission fiop = new FileIOPermission( PermissionState.None );
fiop.AllFiles = FileIOPermissionAccess.PathDiscovery;
fiop.Assert();
try {
assemblyLoc = typeof( Object ).Assembly.Location;
} finally {
CodeAccessPermission.RevertAssert();
}
string manifestLoc = null;
string installDir = null;
if ( assemblyLoc != null ) {
installDir = Path.GetDirectoryName( assemblyLoc );
const string manifestName = "XPThemes.manifest";
manifestLoc = Path.Combine( installDir, manifestName );
}
if ( manifestLoc != null && installDir != null ) {
enableThemingActivationContext = new ACTCTX();
enableThemingActivationContext.cbSize = Marshal.SizeOf( typeof( ACTCTX ) );
enableThemingActivationContext.lpSource = manifestLoc;
// Set the lpAssemblyDirectory to the install
// directory to prevent Win32 Side by Side from
// looking for comctl32 in the application
// directory, which could cause a bogus dll to be
// placed there and open a security hole.
enableThemingActivationContext.lpAssemblyDirectory = installDir;
enableThemingActivationContext.dwFlags = ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID;
// Note this will fail gracefully if file specified
// by manifestLoc doesn't exist.
hActCtx = CreateActCtx( ref enableThemingActivationContext );
contextCreationSucceeded = (hActCtx != new IntPtr( -1 ));
}
}
// If we return false, we'll try again on the next call into
// EnsureActivateContextCreated(), which is fine.
return contextCreationSucceeded;
}
}
// All the pinvoke goo...
[DllImport( "Kernel32.dll" )]
private extern static IntPtr CreateActCtx( ref ACTCTX actctx );
[DllImport( "Kernel32.dll" )]
private extern static bool ActivateActCtx( IntPtr hActCtx, out uint lpCookie );
[DllImport( "Kernel32.dll" )]
private extern static bool DeactivateActCtx( uint dwFlags, uint lpCookie );
private const int ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID = 0x004;
private struct ACTCTX {
public int cbSize;
public uint dwFlags;
public string lpSource;
public ushort wProcessorArchitecture;
public ushort wLangId;
public string lpAssemblyDirectory;
public string lpResourceName;
public string lpApplicationName;
}
}
}
次に、Core\Interop\TaskDialogs\NativeTaskDialog.csの 93 行目 ( HResult hresult = TaskDialogNativeMethods.TaskDialogIndirectの上) で、セクションを次のようにします (最終的に 3 つの新しい行があります)。
// Here is the way we use "vanilla" P/Invoke to call TaskDialogIndirect().
HResult hresult;
using ( new EnableThemingInScope( true ) ) {
hresult = TaskDialogNativeMethods.TaskDialogIndirect(
nativeDialogConfig,
out selectedButtonId,
out selectedRadioButtonId,
out checkBoxChecked );
}
このページでは、新しいcomctl32.dll(バージョン6.0)をロードするようにWindowsに指示するために、プロジェクトにカスタムマニフェストを追加する方法について説明します。
マニフェストはcomctl32.dllに適切に依存していますか?作成したマニフェストを埋め込みましたか?
デバッグ モードの Visual Studio でも同じ問題があります。これまでのところ、回避策は見つかりませんでした。リリース モードでは問題なく動作します。