使用CreateActCtx Win32 API创建激活上下文

时间:2015-08-10 16:31:21

标签: c# winapi pinvoke marshalling activation-context-api

我正在尝试使用CreateActCtx Win32 API创建激活上下文。在使用此功能的互联网上没有很多代码,但我能够找到两个博客,经过大量的谷歌搜索后谈论这个,并得到这么远。但是,我还没有找到关于此API的更多信息及其在Google或SO上的其他地方的调用表单.Net这很奇怪。我认为这很奇怪的原因是因为我试图做一些虽然很少见的事情,但在我看来这是合理的。我试图使用免注册COM互操作,其中COM Dll驻留在将在运行时决定的文件夹中。当Dll位于同一文件夹中时,可以使用清单文件完成此操作。但是,当COM Dll位于执行程序集的工作目录之外的另一个文件夹中时,必须明确地向操作系统提供清单文件。为什么必须在运行时决定文件夹是此时无法更改的业务要求。我们需要快速解决这个问题。

我不是Pinvoke的专家,我也不知道如何调试从API收到的错误消息。在这个特定的例子中,我收到一个错误87,它是"无效的参数"正如here所述。我试图阅读有关Pinvoke的更多信息,并确保我使用正确的托管类型进行编组,并按照MSDN文档中的说明正确使用这些参数。在这一点上,我真的不知道如何进一步调试这个!我完全失去了为什么这个方法返回错误信息。这是我的代码(为了简洁,我删除了激活,发布和其他相关方法):

// Activation context structure
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Auto)]
internal struct ACTCTX
{
    public Int32 cbSize;
    public UInt32 dwFlags;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string lpSource;
    public UInt16 wProcessorArchitecture;
    public UInt16 wLangId;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string lpAssemblyDirectory;
    public UInt16 lpResourceName;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string lpApplicationName;
    public IntPtr hModule;
}

// Activation Context API Functions
[DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "CreateActCtx")]
internal extern static IntPtr CreateActCtx(ref ACTCTX actctx);

private IntPtr m_hActCtx = (IntPtr)0;

public ActivationContextWin32API()
{
    m_hActCtx = (IntPtr)0;
}

//private const int ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID = 0x004;
private const int ACTCTX_FLAG_RESOURCE_NAME_VALID = 0x008;
public bool CreateContext(string manifestPath, string rootFolder, out UInt32 dwError)
{
    dwError = 0;
    ACTCTX info = new ACTCTX();
    info.cbSize = Marshal.SizeOf(typeof(ACTCTX));
    info.lpSource = manifestPath;
    info.hModule = IntPtr.Zero;
    info.lpAssemblyDirectory = rootFolder;
    info.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID;
    info.lpResourceName = 2;

    lock (this)
    {
        m_hActCtx = CreateActCtx(ref info);
        if (m_hActCtx == (IntPtr)(-1))
        {
            dwError = (uint)Marshal.GetLastWin32Error();
            return false;
        }
    }

    return true;
}

我可以使用此API的两种模式。一种是使用嵌入在EXE中的清单或使用已经单独存在的清单文件。目前,两种方法都返回错误消息。我已经测试了清单文件的格式,当我没有通过API时(因此清单文件是健全的),它可以正常工作。

任何有关如何进一步调试的帮助将不胜感激。

1 个答案:

答案 0 :(得分:2)

我认为你已经对结构翻译做了一些准备。我会这样:

"AxMstr_ExMstr_bodyPlaceHolder_bodyPlaceHolder_selReport"

我认为不再支持ANSI了。这意味着该功能应该是:

DropDownList

现在,当您尝试将[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] struct ACTCTX { public int cbSize; public uint dwFlags; public string lpSource; public UInt16 wProcessorArchitecture; public UInt16 wLangId; public string lpAssemblyDirectory; public string lpResourceName; public string lpApplicationName; public IntPtr hModule; } 设置为资源索引时,这会咬你。所以你实际上将它用作结构声明:

[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
extern static IntPtr CreateActCtx(ref ACTCTX actctx);

并将lpResourceName设为[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] struct ACTCTX { public int cbSize; public uint dwFlags; public string lpSource; public UInt16 wProcessorArchitecture; public UInt16 wLangId; public string lpAssemblyDirectory; public IntPtr lpResourceName; public string lpApplicationName; public IntPtr hModule; }

lpResourceName(IntPtr)2,这就是问题所在。根据流程架构,它可以是32位或64位,但绝不是16位。