629 lines
16 KiB
C++
629 lines
16 KiB
C++
// Copyright (c) 1997-1999 Microsoft Corporation
|
|
#include "precomp.h"
|
|
#include "logDrive.h"
|
|
#include "ResultNode.h"
|
|
#include <winioctl.h>
|
|
#include "..\common\util.h"
|
|
#include "..\common\ServiceThread.h"
|
|
#include "..\MMFUtil\MsgDlg.h"
|
|
#include <wbemcli.h>
|
|
#include "SI.h"
|
|
|
|
static const GUID CResultGUID_NODETYPE =
|
|
{ 0x692a8957, 0x1089, 0x11d2, { 0x88, 0x37, 0x0, 0x10, 0x4b, 0x2a, 0xfb, 0x47 } };
|
|
const GUID* CResultDrive::m_NODETYPE = &CResultGUID_NODETYPE;
|
|
const OLECHAR* CResultDrive::m_SZNODETYPE = OLESTR("692A8957-1089-11D2-8837-00104B2AFB47");
|
|
const OLECHAR* CResultDrive::m_SZDISPLAY_NAME = OLESTR("Result");
|
|
const CLSID* CResultDrive::m_SNAPIN_CLASSID = &CLSID_NSDrive;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CResultDrive::CResultDrive(WbemServiceThread *thread) :
|
|
g_serviceThread(thread),
|
|
m_AcluiDLL(0),
|
|
m_propSheet(0)
|
|
{
|
|
// Image indexes may need to be modified depending on the images specific to
|
|
// the snapin.
|
|
memset(&m_scopeDataItem, 0, sizeof(SCOPEDATAITEM));
|
|
m_scopeDataItem.mask = SDI_STR | SDI_IMAGE | SDI_OPENIMAGE | SDI_PARAM;
|
|
m_scopeDataItem.displayname = MMC_CALLBACK;
|
|
m_scopeDataItem.nOpenImage = 0; // May need modification
|
|
m_scopeDataItem.lParam = (LPARAM) this;
|
|
|
|
memset(&m_resultDataItem, 0, sizeof(RESULTDATAITEM));
|
|
m_resultDataItem.mask = RDI_STR | RDI_IMAGE | RDI_PARAM;
|
|
m_resultDataItem.str = L"RN";//MMC_CALLBACK;
|
|
m_resultDataItem.nImage = 0;
|
|
m_resultDataItem.lParam = (LPARAM) this;
|
|
|
|
memset(m_descBar, 0, 100 * sizeof(wchar_t));
|
|
if(::LoadString(HINST_THISDLL, IDS_DRIVE_DESCRIPTION, m_descBar, 100) == 0)
|
|
{
|
|
wcscpy(m_descBar, L"Detailed information about the selected drive");
|
|
}
|
|
|
|
m_WbemServices = g_serviceThread->GetPtr();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CResultDrive::~CResultDrive()
|
|
{
|
|
if(m_propSheet)
|
|
{
|
|
::SendMessage(m_propSheet, WM_COMMAND, MAKEWPARAM(IDCANCEL,0),0);
|
|
}
|
|
m_propSheet = 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool CResultDrive::Initialize(IWbemClassObject *inst)
|
|
{
|
|
m_inst = inst;
|
|
|
|
m_bstrDisplayName = (BSTR)m_inst.GetString("Name");
|
|
m_bstrMapping = L"Local";
|
|
|
|
TCHAR temp[50] = {0};
|
|
if(::LoadString(HINST_THISDLL, IDS_LOCAL, temp, 50) > 0)
|
|
{
|
|
m_bstrMapping = temp;
|
|
}
|
|
|
|
ATLTRACE(L"Result %s using %x\n", m_bstrDisplayName, this);
|
|
SelectIcon();
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------
|
|
HRESULT CResultDrive::GetScopePaneInfo(SCOPEDATAITEM *pScopeDataItem)
|
|
{
|
|
if(pScopeDataItem->mask & SDI_STR)
|
|
pScopeDataItem->displayname = m_bstrDisplayName;
|
|
if(pScopeDataItem->mask & SDI_IMAGE)
|
|
pScopeDataItem->nImage = m_scopeDataItem.nImage;
|
|
if(pScopeDataItem->mask & SDI_OPENIMAGE)
|
|
pScopeDataItem->nOpenImage = m_scopeDataItem.nOpenImage;
|
|
if(pScopeDataItem->mask & SDI_PARAM)
|
|
pScopeDataItem->lParam = m_scopeDataItem.lParam;
|
|
if(pScopeDataItem->mask & SDI_STATE )
|
|
pScopeDataItem->nState = m_scopeDataItem.nState;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//------------------------------------------------------------------
|
|
HRESULT CResultDrive::GetResultPaneInfo(RESULTDATAITEM *pResultDataItem)
|
|
{
|
|
if(pResultDataItem->bScopeItem)
|
|
{
|
|
if(pResultDataItem->mask & RDI_STR)
|
|
{
|
|
pResultDataItem->str = GetResultPaneColInfo(pResultDataItem->nCol);
|
|
}
|
|
if(pResultDataItem->mask & RDI_IMAGE)
|
|
{
|
|
pResultDataItem->nImage = m_scopeDataItem.nImage;
|
|
}
|
|
if(pResultDataItem->mask & RDI_PARAM)
|
|
{
|
|
pResultDataItem->lParam = m_scopeDataItem.lParam;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
if(pResultDataItem->mask & RDI_STR)
|
|
{
|
|
pResultDataItem->str = GetResultPaneColInfo(pResultDataItem->nCol);
|
|
}
|
|
if(pResultDataItem->mask & RDI_IMAGE)
|
|
{
|
|
pResultDataItem->nImage = m_resultDataItem.nImage;
|
|
}
|
|
if(pResultDataItem->mask & RDI_PARAM)
|
|
{
|
|
pResultDataItem->lParam = m_resultDataItem.lParam;
|
|
}
|
|
if(pResultDataItem->mask & RDI_INDEX)
|
|
{
|
|
pResultDataItem->nIndex = m_resultDataItem.nIndex;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool CResultDrive::SelectIcon()
|
|
{
|
|
// NOTE: The CLogDriveScopeNode loads the icons using the resID as the idx.
|
|
|
|
// NOTE: Called by the enumerator template.
|
|
if(m_inst)
|
|
{
|
|
BYTE driveType = (BYTE)m_inst.GetLong(_T("DriveType"));
|
|
|
|
CWbemClassObject cls = m_WbemServices.GetObject(m_inst.GetString(_T("__CLASS")),
|
|
0x20000); //WBEM_FLAG_USE_AMENDED_QUALIFIERS);
|
|
|
|
switch(driveType)
|
|
{
|
|
case DRIVE_REMOVABLE: // The disk can be removed from the drive.
|
|
{//BEGIN
|
|
|
|
// NOTE: Only removeables resort to MediaType.
|
|
long mediaType = Unknown;
|
|
variant_t temp;
|
|
HRESULT hr = m_inst.Get(_T("mediatype"), temp);
|
|
|
|
// zip drives will do this.
|
|
if(temp.vt == VT_NULL)
|
|
{
|
|
hr = E_FAIL; // just to force the following code path.
|
|
}
|
|
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
mediaType = V_I4(&temp);
|
|
|
|
// what size of removeable media?
|
|
switch(mediaType)
|
|
{
|
|
case F3_1Pt44_512: // 3.5", 1.44MB, 512 bytes/sector
|
|
case F3_2Pt88_512: // 3.5", 2.88MB, 512 bytes/sector
|
|
case F3_20Pt8_512: // 3.5", 20.8MB, 512 bytes/sector
|
|
case F3_720_512: // 3.5", 720KB, 512 bytes/sector
|
|
case F3_120M_512: // 3.5", 120M Floppy
|
|
m_resultDataItem.nImage = IDI_DRIVE35;
|
|
break;
|
|
|
|
case F5_1Pt2_512: // 5.25", 1.2MB, 512 bytes/sector
|
|
case F5_360_512: // 5.25", 360KB, 512 bytes/sector
|
|
case F5_320_512: // 5.25", 320KB, 512 bytes/sector
|
|
case F5_320_1024: // 5.25", 320KB, 1024 bytes/sector
|
|
case F5_180_512: // 5.25", 180KB, 512 bytes/sector
|
|
case F5_160_512: // 5.25", 160KB, 512 bytes/sector
|
|
m_resultDataItem.nImage = IDI_DRIVE525;
|
|
break;
|
|
|
|
case Unknown: // Format is unknown
|
|
case RemovableMedia: // Removable media other than floppy
|
|
case FixedMedia: // Fixed hard disk media
|
|
default:
|
|
m_resultDataItem.nImage = IDI_DRIVEREMOVE;
|
|
break;
|
|
} //endswitch mediaType
|
|
|
|
if(cls)
|
|
{
|
|
cls.GetValueMap(_T("MediaType"), mediaType, m_bstrDesc);
|
|
}
|
|
else
|
|
{
|
|
m_bstrDesc = m_inst.GetString("Description");
|
|
}
|
|
}
|
|
else // fall back to a generic removeable drive. NT hates ZIPs. :)
|
|
{
|
|
m_resultDataItem.nImage = IDI_DRIVEREMOVE;
|
|
if(cls)
|
|
{
|
|
cls.GetValueMap(_T("DriveType"), driveType, m_bstrDesc);
|
|
}
|
|
else
|
|
{
|
|
m_bstrDesc = m_inst.GetString("Description");
|
|
}
|
|
|
|
}
|
|
|
|
} //END
|
|
|
|
break; // driveType
|
|
|
|
case DRIVE_FIXED: // The disk cannot be removed from the drive.
|
|
m_resultDataItem.nImage = IDI_DRIVEFIXED;
|
|
if(cls)
|
|
{
|
|
cls.GetValueMap(_T("DriveType"), driveType, m_bstrDesc);
|
|
}
|
|
else
|
|
{
|
|
m_bstrDesc = m_inst.GetString("Description");
|
|
}
|
|
break;
|
|
|
|
case DRIVE_REMOTE: // The drive is a remote (network) drive.
|
|
m_resultDataItem.nImage = IDI_DRIVENET;
|
|
if(cls)
|
|
{
|
|
cls.GetValueMap(_T("DriveType"), driveType, m_bstrDesc);
|
|
}
|
|
else
|
|
{
|
|
m_bstrDesc = m_inst.GetString("Description");
|
|
}
|
|
|
|
break;
|
|
|
|
case DRIVE_CDROM: // The drive is a CD-ROM drive.
|
|
m_resultDataItem.nImage = IDI_DRIVECD;
|
|
if(cls)
|
|
{
|
|
cls.GetValueMap(_T("DriveType"), driveType, m_bstrDesc);
|
|
}
|
|
else
|
|
{
|
|
m_bstrDesc = m_inst.GetString("Description");
|
|
}
|
|
break;
|
|
|
|
case DRIVE_RAMDISK:
|
|
m_resultDataItem.nImage = IDI_DRIVERAM;
|
|
if(cls)
|
|
{
|
|
cls.GetValueMap(_T("DriveType"), driveType, m_bstrDesc);
|
|
}
|
|
else
|
|
{
|
|
m_bstrDesc = m_inst.GetString("Description");
|
|
}
|
|
break;
|
|
|
|
default: break;
|
|
} // endswitch driveType;
|
|
}
|
|
MangleProviderName();
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void CResultDrive::MangleProviderName()
|
|
{
|
|
HRESULT hr = 0;
|
|
_variant_t v1;
|
|
TCHAR fmt[20] = {0};
|
|
wchar_t clean[100] = {0}, share[100] = {0};
|
|
|
|
memset(m_provider, 0, 100 * sizeof(wchar_t));
|
|
memset(m_mangled, 0, 255 * sizeof(wchar_t));
|
|
|
|
if(m_inst)
|
|
{
|
|
hr = m_inst->Get(L"ProviderName", 0, &v1, NULL, NULL);
|
|
|
|
// "" means local. Otherwise mangle the name.
|
|
if(v1.vt == VT_BSTR)
|
|
{
|
|
// mangle "\\machine\share" into "share on 'machine'"
|
|
m_rawShare = V_BSTR(&v1);
|
|
|
|
// get the formatting string.
|
|
if(::LoadString(HINST_THISDLL, IDS_PROVIDER_FMT, fmt, 20) == 0)
|
|
{
|
|
// oops, load a reasonable default fmt.
|
|
_tcscpy(fmt, _T("%1 on '%2'"));
|
|
}
|
|
// NOTE: some kinda format loaded now.
|
|
|
|
_wsplitpath(m_rawShare, NULL, m_provider, share, NULL);
|
|
|
|
wcsncpy(clean, &m_provider[2], wcslen(&m_provider[2]) - 1);
|
|
|
|
long *args[] = {(long*)&share[0], (long *)&clean[0]};
|
|
|
|
FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
|
fmt, 0, 0, m_mangled, ARRAYSIZE(m_mangled),
|
|
(va_list *)&args);
|
|
|
|
m_bstrMapping = m_mangled;
|
|
}
|
|
else if(m_resultDataItem.nImage == IDI_DRIVENET)
|
|
{
|
|
int x = LoadString(HINST_THISDLL, IDS_UNAVAILABLE, m_mangled, 255);
|
|
m_bstrMapping = m_mangled;
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CResultDrive::Notify( MMC_NOTIFY_TYPE event,
|
|
LONG_PTR arg,
|
|
LONG_PTR param,
|
|
IComponentData* pComponentData,
|
|
IComponent* pComponent,
|
|
DATA_OBJECT_TYPES type)
|
|
{
|
|
// Add code to handle the different notifications.
|
|
// Handle MMCN_SHOW and MMCN_EXPAND to enumerate children items.
|
|
// In response to MMCN_SHOW you have to enumerate both the scope
|
|
// and result pane items.
|
|
|
|
// For MMCN_EXPAND you only need to enumerate the scope items
|
|
// Use IConsoleNameSpace::InsertItem to insert scope pane items
|
|
// Use IResultData::InsertItem to insert result pane item.
|
|
|
|
HRESULT hr = E_NOTIMPL;
|
|
|
|
_ASSERTE(pComponentData != NULL || pComponent != NULL);
|
|
|
|
CComPtr<IConsole> spConsole;
|
|
CComQIPtr<IHeaderCtrl, &IID_IHeaderCtrl> spHeader;
|
|
|
|
if(pComponentData != NULL)
|
|
spConsole = ((CNSDrive*)pComponentData)->m_spConsole;
|
|
else
|
|
{
|
|
spConsole = ((CNSDriveComponent*)pComponent)->m_spConsole;
|
|
spHeader = spConsole;
|
|
}
|
|
|
|
switch(event)
|
|
{
|
|
case MMCN_CONTEXTHELP:
|
|
{
|
|
WCHAR topic[] = L"drivprop.chm::/drivprop_overview.htm";
|
|
CComQIPtr<IDisplayHelp, &IID_IDisplayHelp> displayHelp(spConsole);
|
|
|
|
LPOLESTR lpCompiledHelpFile = reinterpret_cast<LPOLESTR>(
|
|
CoTaskMemAlloc((wcslen(topic) + 1) *
|
|
sizeof(wchar_t)));
|
|
|
|
if(lpCompiledHelpFile == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
USES_CONVERSION;
|
|
wcscpy(lpCompiledHelpFile, T2OLE((LPTSTR)(LPCTSTR)topic));
|
|
hr = displayHelp->ShowTopic(lpCompiledHelpFile);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MMCN_SELECT:
|
|
{
|
|
CComQIPtr<IResultData, &IID_IResultData> spResultData(spConsole);
|
|
spResultData->SetDescBarText(m_descBar);
|
|
|
|
IConsoleVerb *menu = NULL;
|
|
if(SUCCEEDED(spConsole->QueryConsoleVerb(&menu)))
|
|
{
|
|
menu->SetVerbState(MMC_VERB_PROPERTIES, ENABLED, TRUE);
|
|
menu->SetDefaultVerb(MMC_VERB_PROPERTIES);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// NOTE: The CLogDriveScopeNode loads the icons using the resID as the idx.
|
|
|
|
case MMCN_DBLCLICK:
|
|
hr = S_FALSE; // do the default verb. (Properties)
|
|
break;
|
|
|
|
} //endswitch
|
|
|
|
return hr;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
LPOLESTR CResultDrive::GetResultPaneColInfo(int nCol)
|
|
{
|
|
switch(nCol)
|
|
{
|
|
case 0:
|
|
return m_bstrDisplayName;
|
|
break;
|
|
case 1:
|
|
return m_bstrDesc;
|
|
break;
|
|
case 2:
|
|
return m_bstrMapping;
|
|
break;
|
|
} //endswitch nCol
|
|
|
|
return OLESTR("missed one in CResultDrive::GetResultPaneColInfo");
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CResultDrive::QueryPagesFor(DATA_OBJECT_TYPES type)
|
|
{
|
|
if(type == CCT_RESULT)
|
|
return S_OK;
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CResultDrive::CreatePropertyPages(LPPROPERTYSHEETCALLBACK lpProvider,
|
|
LONG_PTR handle,
|
|
IUnknown* pUnk,
|
|
DATA_OBJECT_TYPES type)
|
|
{
|
|
if(type == CCT_RESULT)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CWbemClassObject inst2;
|
|
bstr_t temp;
|
|
ATLTRACE(L"drive factory Enum\n");
|
|
|
|
if((bool)m_WbemServices)
|
|
{
|
|
IWbemServices *service;
|
|
m_WbemServices.GetServices(&service);
|
|
m_WbemServices.SetBlanket(service);
|
|
|
|
// get the expensive version.
|
|
m_objPath = m_inst.GetString("__PATH");
|
|
inst2 = m_WbemServices.GetObject(m_objPath);
|
|
|
|
service->Release();
|
|
|
|
// if it's still there...
|
|
if(inst2 != NULL)
|
|
{
|
|
m_deviceID = inst2.GetString("DeviceID");
|
|
// instance the class for the pages.
|
|
DrivesPage *dvPg = new DrivesPage(g_serviceThread,
|
|
inst2,
|
|
m_resultDataItem.nImage,
|
|
&m_propSheet,
|
|
m_bstrDesc,
|
|
m_mangled,
|
|
handle,
|
|
true);
|
|
|
|
|
|
lpProvider->AddPage(dvPg->Create());
|
|
|
|
bool hasAcls = false;
|
|
bstr_t fs;
|
|
variant_t temp;
|
|
|
|
inst2.Get("FileSystem", temp);
|
|
|
|
|
|
// if its a null FS from a non-removeable drive...
|
|
if((temp.vt == VT_NULL) &&
|
|
((m_resultDataItem.nImage == IDI_DRIVEFIXED) ||
|
|
(m_resultDataItem.nImage == IDI_DRIVENET)
|
|
)
|
|
)
|
|
{
|
|
// check Win32_directory...
|
|
CWbemClassObject dirInst;
|
|
TCHAR objPath[100] = {0};
|
|
_tcscpy(objPath, L"Win32_Directory=\"");
|
|
_tcscat(objPath, (LPCTSTR)m_deviceID);
|
|
_tcscat(objPath, L"\\\\\"");
|
|
dirInst = m_WbemServices.GetObject(objPath);
|
|
|
|
// not found implies the null FS was caused by accessDenied on the "FileSystem" property.
|
|
// acessDenied with only happen if the volume security protection to deny you. A FAT drive
|
|
// would have let you in cuz it cant keep you out. Hows that for deductive reasoning. :)
|
|
if(!(bool)dirInst)
|
|
{
|
|
hasAcls = true;
|
|
}
|
|
}
|
|
else if(temp.vt != VT_NULL)
|
|
{
|
|
// cast to bstr_t
|
|
fs = temp;
|
|
|
|
if(fs == (bstr_t)_T("NTFS")) // actually says its NTFS.
|
|
{
|
|
hasAcls = true;
|
|
}
|
|
}
|
|
// NOTE: This doesn't account for future FSs (non-NTFS) having security.
|
|
// A null FS from a REMOVEABLE drive (meaning its removed right now)
|
|
// will leave fs as blank & hasAcls == false (no security tab).
|
|
|
|
|
|
// security tab if the volume has security.
|
|
if(hasAcls)
|
|
{
|
|
CreateSecPage(lpProvider);
|
|
// NOTE: Ignore any error. Atleast you'll get the "general" page.
|
|
}
|
|
|
|
LONG_PTR x = m_resultDataItem.lParam;
|
|
}
|
|
else // it went away.
|
|
{
|
|
TCHAR caption[50] = {0}, text[500] = {0};
|
|
|
|
::LoadString(HINST_THISDLL,
|
|
IDS_DISPLAY_NAME,
|
|
caption, 50);
|
|
|
|
::LoadString(HINST_THISDLL,
|
|
IDS_NO_DRIVE,
|
|
text, 500);
|
|
|
|
MessageBox(NULL, text, caption,
|
|
MB_OK | MB_ICONHAND);
|
|
|
|
hr = E_UNEXPECTED;
|
|
|
|
} //endif inst2 != NULL;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
typedef HPROPSHEETPAGE (WINAPI *CREATEPAGE_PROC) (LPSECURITYINFO);
|
|
|
|
HRESULT CResultDrive::CreateSecPage(LPPROPERTYSHEETCALLBACK lpProvider)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if(m_AcluiDLL == NULL)
|
|
{
|
|
m_AcluiDLL = LoadLibrary(L"aclui.dll");
|
|
if(m_AcluiDLL == NULL)
|
|
{
|
|
DWORD e = GetLastError();
|
|
}
|
|
}
|
|
|
|
if(m_AcluiDLL == NULL)
|
|
{
|
|
// dont have both so give up.
|
|
if(m_AcluiDLL != NULL)
|
|
{
|
|
FreeLibrary(m_AcluiDLL);
|
|
}
|
|
// TODO: error msg.
|
|
TCHAR caption[50] = {0}, text[500] = {0};
|
|
|
|
::LoadString(HINST_THISDLL,
|
|
IDS_DISPLAY_NAME,
|
|
caption, 50);
|
|
|
|
::LoadString(HINST_THISDLL,
|
|
IDS_CANT_LOAD_SEC_DLLS,
|
|
text, 500);
|
|
|
|
::MessageBox(NULL, text, caption,
|
|
MB_OK | MB_ICONHAND);
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
CREATEPAGE_PROC createPage = (CREATEPAGE_PROC)GetProcAddress(m_AcluiDLL, "CreateSecurityPage");
|
|
if(createPage)
|
|
{
|
|
CSecurity *pSecInfo = new CSecurity;
|
|
|
|
if(pSecInfo)
|
|
{
|
|
pSecInfo->AddRef();
|
|
// give the SI the "context" from this result node.
|
|
pSecInfo->Initialize(g_serviceThread,
|
|
m_inst, m_deviceID,
|
|
m_idiotName, m_provider,
|
|
m_mangled);
|
|
;
|
|
HPROPSHEETPAGE hPage = createPage(pSecInfo);
|
|
if(hPage)
|
|
lpProvider->AddPage(hPage);
|
|
else
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// TODO: couldnt get the exported routines.
|
|
}
|
|
|
|
}// m_AcluiDLL != NULL
|
|
return hr;
|
|
}
|
|
|
|
|