65.9K
CodeProject 正在变化。 阅读更多。
Home

如何构建暴露 Win32 API 和本机 COM 对象的程序集

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.69/5 (8投票s)

2007年5月16日

CPOL

2分钟阅读

viewsIcon

36603

downloadIcon

522

在 DLL 库中进行托管和非托管调用。

Screenshot - adsauthentication.png

引言

现在,C++ 在 Visual Studio 2005 中似乎是二等公民。虽然 C# 比 C++/MC++ 更优雅且更容易,但在某些情况下,Visual C++ 可能是必不可少的工具。如果您正在尝试构建一个程序集,该程序集为托管代码和非托管代码公开功能,那么 Visual C++ 可能是您的唯一选择。此示例背后的唯一功能是 ADS 身份验证,以便使本文具有一定的意义。

创建多用途 DLL

以下是创建此类项目所需的步骤。 从创建 DLL 的 ATL 项目开始。 添加一个带有双接口的简单 ATL 对象。 在我的例子中,我有一个带有 IADSAuthenticate 接口的 ADSAuthenticate COM 类。 此接口中只有一个函数

STDMETHOD(IsAuthorized)(BSTR bstrDomain, BSTR bstrName, 
		BSTR bstrPassword, VARIANT_BOOL* pvbResult);

为了使事情更加有趣,我添加了一个类似的函数作为 C 导出 API,供旧版客户端使用。 我在项目中添加了一个新文件 dllexportapi.h(如下),并在项目级别(或 stdafx.h 文件)定义了 AUTHORIZATION_EXPORTS

#ifdef AUTHORIZATION_EXPORTS 
#define AUTHORIZATION_API __declspec(dllexport) 
#else 
#define AUTHORIZATION_API __declspec(dllimport) 
#endif 

extern "C" AUTHORIZATION_API BOOL _stdcall IsUserAuthorized
	(wchar_t* szDomain, //wchar_t* szUser, wchar_t* szPassword); 

.def 文件中,添加您导出的函数 (IsUserAuthorized)。 它应该看起来像这样

; ADSAuthentication.def : Declares the module parameters. 
LIBRARY "ADSAuthentication.DLL" 
EXPORTS 
DllCanUnloadNow PRIVATE 
DllGetClassObject PRIVATE 
DllRegisterServer PRIVATE 
DllUnregisterServer PRIVATE
IsUserAuthorized 

对于这个特定的项目,整个想法是将非托管调用引导到托管调用,后者将针对当前的 ADS 目录进行授权。
最复杂的任务是使这个原生 DLL 成为程序集,因为 Visual Studio 没有提供添加托管类的工具。

为此,首先添加一个常规 C++ 类。 将其命名为 ManagedAuthentication。 在解决方案资源管理器中选择 ManagedAuthentication.cpp,并按照如下所述更改所有配置的文件属性

在“配置属性”->“C/C++”->“常规”页面上
选择“调试信息格式”:“C7 兼容(/Z7)”
使用公共语言运行时编译: 公共语言运行时支持 (/clr)

在“配置属性”->“C/C++”->“代码生成”页面上
启用最小重新生成: 否
启用 C++ 异常: 是,带 SHE 异常 (/EHa)
运行时库 : 多线程 DLL (/MD)

在“配置属性”->“C/C++”->“预编译头”页面上
创建/使用预编译头: 不使用预编译头

在“项目属性”->“通用属性”->“引用”下
添加所需的程序集,在本例中为 System.DirectoryServices
现在我们将要处理这个项目的主力,将正确的标头添加到 ManagedAuthentication.cpp 文件

#include "StdAfx.h"
#include "dllexportapi.h"
#include <atlstr.h> 
using namespace System;
using namespace System::DirectoryServices;
using namespace System::Runtime::InteropServices;
#include <atlstr.h> 
#include "ManagedAuthentication.h"

添加处理身份验证的方法

bool ManagedAuthentication::IsAuthorized
	(String^ domain, String^ user, String^ password)
{
            String^ domainAndUsername = domain + "\\" + user;
            DirectoryEntry^ entry = gcnew DirectoryEntry(String::Empty,
                                                       domainAndUsername,
                                                         password);

            try
            {
                // Bind to the native AdsObject to force authentication.
                return entry->NativeObject != nullptr;

            }
            catch (...)
            {
            }
            finally
            {
                if (entry != nullptr)
                    entry->Close();
            }
            return false;
}

最后,提供 C 导出函数的实现

BOOL _stdcall IsUserAuthorized(wchar_t* szDomain, 
		wchar_t* szUser, wchar_t* szPassword)
{
    bool bres = false;
    try
    {
        String^ user = Marshal::PtrToStringUni((IntPtr)szUser);
        String^ domain = Marshal::PtrToStringUni((IntPtr)szDomain);
        String^ password = Marshal::PtrToStringUni((IntPtr)szPassword);

        bres = ManagedAuthentication::IsAuthorized(domain, user, password);
    }
    catch (...)
    {
    }
    return (BOOL)bres;
}

关注点

不要忘记像 COM 服务器一样使用 regsvr32 注册 DLL ADSAuthentication.dll,以充分利用其公开的接口。 解决方案中包含 2 个测试项目,用于以不同的方式调用 DLL。

© . All rights reserved.