VC/MFC 基础

VC/MFC 基础



Q:删除NTFS格式下目录继承的权限

BOOL bRetval = FALSE;

HANDLE hToken = NULL;
PSID pSIDAdmin = NULL;
PSID pSIDEveryone = NULL;
PACL pACL = NULL;
SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
const int NUM_ACES = 1;
EXPLICIT_ACCESS ea[NUM_ACES];
DWORD dwRes;

// Specify the DACL to use.
// Create a SID for the Everyone group.
/* if (!AllocateAndInitializeSid(&SIDAuthWorld, 1,
SECURITY_WORLD_RID,
0,
0, 0, 0, 0, 0, 0,
&pSIDEveryone))
{
printf("AllocateAndInitializeSid (Everyone) error %u/n", GetLastError());
goto Cleanup;
}*/

pSIDEveryone = GetSid(L"EveryOne", 0);

// Create a SID for the BUILTIN/Administrators group.
/* if (!AllocateAndInitializeSid(&SIDAuthNT, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&pSIDAdmin))
{
printf("AllocateAndInitializeSid (Admin) error %u/n", GetLastError());
goto Cleanup;
}*/

ZeroMemory(&ea, NUM_ACES * sizeof(EXPLICIT_ACCESS));

// Set read access for Everyone.
ea[0].grfAccessPermissions = GENERIC_ALL;
ea[0].grfAccessMode = REVOKE_ACCESS;
ea[0].grfInheritance = INHERITED_ACE;
ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[0].Trustee.TrusteeType = TRUSTEE_IS_INVALID;
ea[0].Trustee.ptstrName = (LPTSTR) pSIDEveryone;


if (ERROR_SUCCESS != SetEntriesInAcl(NUM_ACES,
ea,
NULL,
&pACL))
{
printf("Failed SetEntriesInAcl/n");
goto Cleanup;
}

// Try to modify the object's DACL.
dwRes = SetNamedSecurityInfo(
lpszOwnFile, // name of the object
SE_FILE_OBJECT, // type of object
DACL_SECURITY_INFORMATION, // change only the object's DACL
NULL, NULL, // do not change owner or group
pACL, // DACL specified
NULL); // do not change SACL

if (ERROR_SUCCESS == dwRes)
{
printf("Successfully changed DACL/n");
bRetval = TRUE;
// No more processing needed.
goto Cleanup;
}
if (dwRes != ERROR_ACCESS_DENIED)
{
printf("First SetNamedSecurityInfo call failed: %u/n", dwRes);
goto Cleanup;
}

// If the preceding call failed because access was denied,
// enable the SE_TAKE_OWNERSHIP_NAME privilege, create a SID for
// the Administrators group, take ownership of the object, and
// disable the privilege. Then try again to set the object's DACL.

// Open a handle to the access token for the calling process.
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES,
&hToken))
{
printf("OpenProcessToken failed: %u/n", GetLastError());
goto Cleanup;
}

// Enable the SE_TAKE_OWNERSHIP_NAME privilege.
if (!SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, TRUE))
{
printf("You must be logged on as Administrator./n");
goto Cleanup;
}

// Set the owner in the object's security descriptor.
dwRes = SetNamedSecurityInfo(
lpszOwnFile, // name of the object
SE_FILE_OBJECT, // type of object
OWNER_SECURITY_INFORMATION, // change only the object's owner
pSIDAdmin, // SID of Administrator group
NULL,
NULL,
NULL);

if (dwRes != ERROR_SUCCESS)
{
printf("Could not set owner. Error: %u/n", dwRes);
goto Cleanup;
}

// Disable the SE_TAKE_OWNERSHIP_NAME privilege.
if (!SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, FALSE))
{
printf("Failed SetPrivilege call unexpectedly./n");
goto Cleanup;
}

// Try again to modify the object's DACL, now that we are the owner.
dwRes = SetNamedSecurityInfo(
lpszOwnFile, // name of the object
SE_FILE_OBJECT, // type of object
DACL_SECURITY_INFORMATION, // change only the object's DACL
NULL, NULL, // do not change owner or group
pACL, // DACL specified
NULL); // do not change SACL

if (dwRes == ERROR_SUCCESS)
{
printf("Successfully changed DACL/n");
bRetval = TRUE;
}
else
{
printf("Second SetNamedSecurityInfo call failed: %u/n", dwRes);
}

Cleanup:

if (pSIDAdmin)
FreeSid(pSIDAdmin);

/* if (pSIDEveryone)
FreeSid(pSIDEveryone);*/

if (pACL)
LocalFree(pACL);

if (hToken)
CloseHandle(hToken);

上述方法只能删除自己添加的权限,不能删除从父目录继承过来的权限
该如何实现不从父目录继承权限呢????

A:
if you do not want to inherit permissions from the parent
directory, you need to use the SE_DACL_PROTECTED flag.

if you want to save a lot of code, you can use SDDL (security
descriptor description language). The security descriptor creation
code can be replaced by a single call:

ConvertStringSecurityDescriptorToSecurityDescriptor(
L"O:COD:(A;;FA;;;WD)",
SDDL_REVISION_1,
&pSD,
&dwSize
);
SDDL is documented in MSDN.

Q: 控制面板扩展(.cpl)文件 怎么开发? 有这方面的资料么?

A:
http://www.vckbase.com/document/viewdoc/?id=557
http://msdn.microsoft.com/msdnmag/issues/0500/c/

VC/MFC 控件


Q:为什么cricheditview不响应wm_contextmenu消息?

A:
send WM_CONTEXTMENU yourself
void MyRichEditCtrl::OnRButtonUp(UINT nFlags, CPoint point)
{
ClientToScreen(&point);
SendMessage(WM_CONTEXTMENU,WPARAM(m_hWnd),MAKELPARAM(point.x,point.y));
}


A:
自己基于richeditctrl做个类
改写OnRButtonDown



void CRichEditCtrlT::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
::SendMessage(GetParent()->GetSafeHwnd(),WM_RBUTTONUP,nFlags,point.y*65536+point.x);
CRect rect;
GetParent()->GetWindowRect(&rect);
point.x += rect.left;
point.y += rect.top;
CRichEditCtrl::OnRButtonDown(nFlags, point);
}

然后在你自己的view 类中加入onContextMenu就可以了


VC/MFC 硬件/系统


Q: Windows2000服务程序的两个问题(如何调试,设置界面)。

A:
服务程序调试方法二:
在要下断点的地方用_ASSERT(FALSE);或者DebugBreak();启动Debug版Service。
出现错误提示框时选择Cancle进入调试(DebugBreak),或则选择Retry(_ASSERT),然后打开Stack,定位到向调试的函数里。

服务程序调试方法三:
请使用Soft-Ice


A:
〉1.服务程序如何调试?

你可以试一下这个方法:
1、ServiceMain函数起始处添加ASSERT(0);语句

inline void CXXX::ServiceMain(DWORD /* dwArgc */, LPTSTR* /* lpszArgv */)
{
ASSERT(0);
//...

}
2、编译DEBUG版本的服务程序,注册服务并启动。此时将显示Debug Assertion Failed调试信息对话框
3、启动任务管理器,从中选择你的服务进程,右击选择调试。在弹出的警告对话框中点击“YES”按钮。此时系统将启动MSDEV.exe
4、在Debug Assertion Failed调试信息对话框中点击“重试”按钮,执行断点将显示在 ASSERT(0);语句处。
至此,F10、F11随便按吧。

如果服务程序提供对外的接口,调试它就更容易了。(像调DLL一样,从接口函数进入即可)

〉2.我希望服务程序有自己的设置界面,怎么做?
可以使用进程间通信,也可以按照边城浪子的方法实现
下述链接可以参照
http://www.codeproject.com/system/iconservice.asp

Q: 怎么从网络上获取当前的北京时间?

A:
http://blog.vckbase.com/hatemath/archive/2005/10/12/13154.aspx


Q: 如何在程序中获取驱动程序信息?
如:就是在设备管理器里面点击板卡属性中的位置信息,
如位置: PCI slot5(PCI 总线0、设备19、功能0)

具体操作:
我的电脑-》属性-》硬件-》设备管理器-》声音,视频和游戏控制器-》某某驱动-》属性-》常规

可以看见如下信息:
设备类型:声音,视频和游戏控制器
制造商: DVB-T
位置: PCI slot5(PCI 总线0、设备19、功能0)

我现在就是想要获取该驱动的这个“位置: PCI slot5(PCI 总线0、设备19、功能0)”信息,好在我的应用程序里面显示出来,这应该有API函数可以获取吧,但怎么样具体操作,我不知道。可以给点例子,或者指点我一下吗,谢谢了!


A:
用 SetupDiGetDeviceRegistryProperty 可以得到:

#include <stdio.h>
#include <windows.h>
#include <setupapi.h>
#include <devguid.h>


VOID PrintWin32Error(DWORD dwError)
{
LPVOID lpMsgBuf;

FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dwError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&lpMsgBuf,
0,
NULL
);

if (lpMsgBuf)
{
::MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK);
LocalFree(lpMsgBuf);
}
}


int main(int argc, char *argv[], char *envp[])
{
HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
SP_DEVINFO_DATA DeviceInfoData;
DWORD dwErrCode = 0;

//
// Create a HDEVINFO with all present devices.
//
hDevInfo = SetupDiGetClassDevs(
(LPGUID)&GUID_DEVCLASS_DISPLAY,
0,
0,
DIGCF_PRESENT
);
if (hDevInfo == INVALID_HANDLE_VALUE)
{
dwErrCode = GetLastError();
PrintWin32Error(dwErrCode);
return 1;
}

//
// Enumerate through all devices.
//
printf("All Port Device List:/n");

LPTSTR pBuffer = NULL;
DWORD dwBufferSize = 0x40;

pBuffer = (char*)LocalAlloc(LPTR, dwBufferSize);
if (!pBuffer)
{
dwErrCode = GetLastError();
PrintWin32Error(dwErrCode);
return 2;
}

DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (DWORD i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); ++i)
{
DWORD PropertyRegDataType;

//
// Call function with NULL to begin with, then use the returned buffer
// size to allocate the buffer. Keep calling until success or an unknown
// failure.
//
while (!SetupDiGetDeviceRegistryProperty(
hDevInfo,
&DeviceInfoData,
SPDRP_LOCATION_INFORMATION,
&PropertyRegDataType,
(PBYTE)pBuffer,
dwBufferSize,
NULL))
{
dwErrCode = GetLastError();
if (dwErrCode == ERROR_INSUFFICIENT_BUFFER)
{
//
// Increase the buffer size.
//
dwBufferSize += 0x20;
pBuffer = (char*)LocalReAlloc(pBuffer, dwBufferSize, LMEM_MOVEABLE);
}
else if (dwErrCode == ERROR_NO_MORE_ITEMS)
{ // No more device
break;
}
else
{ // Some error occur!
PrintWin32Error(dwErrCode);

if (pBuffer)
{
LocalFree(pBuffer);
}

// Cleanup
SetupDiDestroyDeviceInfoList(hDevInfo);
return 3;
}
}

printf("%s/n", pBuffer);
}

if (pBuffer)
{
LocalFree(pBuffer);
}

// Cleanup
SetupDiDestroyDeviceInfoList(hDevInfo);
return 0;
}


A:

给你一个完整的模拟设备管理器的控件:
/
// CDeviceTreeCtrl message handlers
int CDeviceTreeCtrl::EnumDeviceClasses(int index, TCHAR* DeviceClassName, TCHAR* DeviceClassDesc, BOOL* DevicePresent, int* ClassImage)
{
int nResult = -1;
GUID ClassGuid = {0};
BOOL resNam = FALSE;
ULONG RequiredSize = MAX_DEV_LEN;
TCHAR* name = new TCHAR[MAX_DEV_LEN];
HDEVINFO NewDeviceInfoSet = NULL;

nResult = CM_Enumerate_Classes(index, &ClassGuid, 0);
*DevicePresent = FALSE;

//incorrect device class:
if(nResult == CR_INVALID_DATA)
{
return -2;
}

//device class is absent
if(nResult == CR_NO_SUCH_VALUE)
{
return -1;
}

//bad param. - fatal error
if(nResult != CR_SUCCESS)
{
return -3;
}

resNam = SetupDiClassNameFromGuid(&ClassGuid, name, RequiredSize, &RequiredSize);
if(RequiredSize > 0)
{
delete[] name;
name = new TCHAR[RequiredSize];
resNam = SetupDiClassNameFromGuid(&ClassGuid, name, RequiredSize, &RequiredSize);
}

SetupDiGetClassImageIndex(&m_ImageListData, &ClassGuid, ClassImage);
NewDeviceInfoSet = SetupDiGetClassDevs(&ClassGuid, 0, NULL, DIGCF_PRESENT);

if(NewDeviceInfoSet == INVALID_HANDLE_VALUE)
{
*DevicePresent = FALSE;
_tcscpy(DeviceClassName, name);

delete[] name;
name = NULL;
return 0;
}

HKEY KeyClass = SetupDiOpenClassRegKeyEx(&ClassGuid,
MAXIMUM_ALLOWED,
DIOCR_INSTALLER,
NULL,
0);

if(KeyClass == INVALID_HANDLE_VALUE)
{
*DevicePresent = FALSE;
_tcscpy(DeviceClassName, name);

delete[] name;
name = NULL;

return 0;
}
else
{
long dwSize = MAX_DEV_LEN;
int res = RegQueryValue(KeyClass, NULL, DeviceClassDesc, &dwSize);

if (res != ERROR_SUCCESS)
_tcscpy(DeviceClassDesc, _T(""));
}

SetupDiDestroyDeviceInfoList(NewDeviceInfoSet);

_tcscpy(DeviceClassName, name);
*DevicePresent = TRUE;

RegCloseKey(KeyClass);

delete [] name;
name = NULL;
return 0;
}


int CDeviceTreeCtrl::EnumDevices(int index, TCHAR* DeviceClassName, TCHAR* DeviceName)
{
GUID* guids = new GUID[1];
ULONG RequiredSize = 0;
HDEVINFO NewDeviceInfoSet = NULL;
SP_DEVINFO_DATA DeviceInfoData = {0};

BOOL res = SetupDiClassGuidsFromName(DeviceClassName, &guids[0], RequiredSize, &RequiredSize);

if (RequiredSize==0)
{
//incorrect class name:
_tcscpy(DeviceName, _T(""));
return -2;
}

if(!res)
{
delete [] guids;
guids = new GUID[RequiredSize];
res = SetupDiClassGuidsFromName(DeviceClassName, &guids[0],
RequiredSize, &RequiredSize);

if (!res || RequiredSize==0)
{
//incorrect class name:
_tcscpy(DeviceName, _T(""));
return -2;
}
}

//get device info set for our device class
NewDeviceInfoSet = SetupDiGetClassDevs(&guids[0], 0, NULL, DIGCF_PRESENT);

if(NewDeviceInfoSet == INVALID_HANDLE_VALUE)
if(!res)
{
//device information is unavailable:
_tcscpy(DeviceName, _T(""));
return -3;
}

DeviceInfoData.cbSize = 28;
//is devices exist for class
DeviceInfoData.DevInst = 0;
ZeroMemory(&DeviceInfoData.ClassGuid, sizeof(GUID));
DeviceInfoData.Reserved = 0;

res = SetupDiEnumDeviceInfo(NewDeviceInfoSet, index, &DeviceInfoData);

if (!res)
{
//no such device:
SetupDiDestroyDeviceInfoList(NewDeviceInfoSet);
_tcscpy(DeviceName, _T(""));
return -1;
}


if (!SetupDiGetDeviceRegistryProperty(NewDeviceInfoSet, &DeviceInfoData,
SPDRP_FRIENDLYNAME, 0, (BYTE*) DeviceName,
MAX_DEV_LEN, NULL))
{
res = SetupDiGetDeviceRegistryProperty(NewDeviceInfoSet, &DeviceInfoData,
SPDRP_DEVICEDESC, 0, (BYTE*) DeviceName,
MAX_DEV_LEN, NULL);
if (!res)
{
//incorrect device name:
SetupDiDestroyDeviceInfoList(NewDeviceInfoSet);
_tcscpy(DeviceName, _T(""));
return -4;
}
}

return 0;
}


void CDeviceTreeCtrl::EnumDevices()
{
DeleteAllItems();

//Set Image List
m_ImageListData.cbSize = sizeof(m_ImageListData);
SetupDiGetClassImageList(&m_ImageListData);

m_ImageList.Attach(m_ImageListData.ImageList);
CBitmap myComputer;
myComputer.LoadBitmap(IDB_BITMAP_COMPUTER);
COLORREF colormask = RGB(255, 0, 255);
m_ImageList.Add(&myComputer, colormask);

SetImageList(&m_ImageList, TVSIL_NORMAL);
HTREEITEM hRoot, hDeviceClasses;

TCHAR ComputerName[MAX_PATH];
DWORD dwSize = MAX_PATH;

GetComputerName(ComputerName, &dwSize);

int ComputerImage = m_ImageList.GetImageCount() - 1;
hRoot = InsertItem(ComputerName, ComputerImage, ComputerImage);

TCHAR classes[MAX_DEV_LEN] = {0};
TCHAR classesDesc[MAX_DEV_LEN] = {0};

BOOL DevExist = FALSE;
int index = 0;
int DeviceImage;
int res = EnumDeviceClasses(index , classes, classesDesc, &DevExist, &DeviceImage);

while (res != -1)
{
if (res >= -1 && DevExist)
{
//Add New Device Entry to Tree
if (_tcsicmp(classesDesc, _T(""))==0)
hDeviceClasses = InsertItem((LPCTSTR) classes,
DeviceImage, DeviceImage, hRoot);
else
hDeviceClasses = InsertItem((LPCTSTR) classesDesc,
DeviceImage, DeviceImage, hRoot);

//loop for enumerating devices of specefic class!
int result, DevIndex = 0;
TCHAR DeviceName[MAX_DEV_LEN] = _T("");

result = EnumDevices(DevIndex, classes, DeviceName);

while (result != -1)
{
if (result == 0)
InsertItem(DeviceName, DeviceImage, DeviceImage, hDeviceClasses);

DevIndex++;
result = EnumDevices(DevIndex, classes, DeviceName);
}

if (GetChildItem(hDeviceClasses)==NULL)
DeleteItem(hDeviceClasses);
else
SortChildren(hDeviceClasses);

}

index++;
res = EnumDeviceClasses(index, classes, classesDesc, &DevExist, &DeviceImage);
}

Expand(hRoot, TVE_EXPAND);
SortChildren(hRoot);
}

Q:高分求教:编写能适应XP下快速用户切换特性的服务程序的问题
Windows XP下写了一个服务程序,创建时指定了SERVICE_WIN32_OWN_PROCESS和SERVICE_INTERACTIVE_PROCESS标志,还指定了SERVICE_AUTO_START使服务自动启动。服务启动时创建一个线程,该线程只是简单的一个循环:每秒Beep一声。系统启动后,在欢迎界面时该服务就自动启动了,可以听见每秒一次的Beep声,然后点击一个用户登录后,Beep声也正常,然后点击“开始”-〉“注销”-〉“切换用户”回到用户选择界面时,Beep声仍然正常,但是选择另外一个用户登录后,Beep声消失,再切换回原来的用户,Beep声恢复,这是为什么?切换到新用户后Beep线程是否已经被自动挂起?如何才能使切换到新用户后仍然能使Beep正常继续?请高手不吝赐教,万分感谢!

A:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/interactive_services.asp

WTSRegisterSessionNotification


A:
1.切换到新用户后删除线程,然后重新生成与用户交互的线程(注用代码交互,不是设置SERVICE_INTERACTIVE_PROCESS标志)
A:
我原先是这么做的:
在开始菜单-》启动里有个程序,负责启动服务程序。这样,服务程序就在用户登陆以后才能运行。
服务程序在用户注销/切换的时候就自己结束。

Shell 编程


Q: [Shell]如何获得某个打开的文件夹的路径
比如打开我的电脑(目的是启动一个Shell窗口),然后进入某个分区,打开某个文件夹。这时候启动我的程序找到这个Shell窗口,然后获得这个Shell窗口当前打开的文件夹的路径。
当然我可以通过GetWindowText获得,但是“文件夹选项”里面可以把“在标题栏显示完整路径”或“在地址栏显示完整路径”去掉。。。
现在就是找不到一个确定的方法来获得Shell窗口当前打开文件夹的完整路径。

A:
http://www.codeproject.com/shell/AutomateShellWindow.asp

Q: 如何能够实现一个IEXPLORE.EXE进程打开多个窗口?

A:
http://www.codeproject.com/shell/AutomateShellWindow.asp


VC/MFC HTML


Q:IHTMLWindow2::execScript时而正常时而不正常是怎么回事???????[高分求教!急用!]
我使用IHTMLWindow2::execScript方法执行若干多句Javascript脚本,
经常出非常诡异的错误,还请各路高人指点:

假设有ABCDEFG七条固定的Javascript语句,每条语句都要使用IHTMLWindow2::execScript来在一个IE控件里执行,结果总会出现一到两条语句执行失败,错误码为“非法参数”-E_INVALIDARG。

此错误的特点:七条语句都有一定几率出错。也就是说,这次运行是C、E出错,下次就有可能是A、F出错,但C、E正常执行。第三次则可能ACE都正确,只有F出错。当然,有时候也会全部七条语句都执行成功。

由此我的判断是Javascript语句没错,IHTMLWindow2::execScript的用法也“应该”没错,但就不知道为什么功能不正常。

请各位热心人及功力深厚者指点一二 :)
感激不尽!

PS:由IHTMLDOMDocument2::get_parentWindow(&pWindow);获得的IHTMLWindow2指针,用完后,到底需不需要Release() ?

我用的代码:
IHTMLWindow2 *pWindow=NULL;
hr=m_pDoc->get_parentWindow(&pWindow);

WCHAR *CONSTTYPES=L"javascript";
BSTR bscode,bstype;
bstype=CONSTTYPES;
WCHAR bsstr[1024];//避免动态申请内存的开销
bscode=bsstr;
long j=lstrlen(strScript);
MultiByteToWideChar(CP_ACP,0,strScript,j+1,bsstr,j+1);
VARIANT v;
VariantInit(&v);
v.vt=VT_EMPTY;
hr=pWindow->execScript(bscode,bstype,&v);//就是这里有时会出错,且hr会返回E_INVALIDARG
VariantClear(&v);
pWindow->Release();

真是太诡异了!!即使是同一条Javascript语句,也会有时正确执行,有时出错,我快被它搞疯了!!!!

A:
是COM指针无法在多线程模式中正常传值和使用,使用CoMarshalInterThreadInterfaceInStream即可解决问题 :)

 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值