I've got a service project in Visual Studio 2005 that was converted to a Visual Studio 2010 project. And I've noticed a problem with the PreMessageLoop function, which looks like this:
HRESULT CMyModule::PreMessageLoop (int nShowCmd)
{
HRESULT result = CAtlServiceModuleT<CMyModule,100>::PreMessageLoop(nShowCmd);
if (ERROR_SUCCESS == result)
{
ComplicatedInitialization();
_AtlModule.SetServiceStatus (SERVICE_START_PENDING);
MoreComplicatedInitialization();
_AtlModule.SetServiceStatus (SERVICE_START_PENDING);
StillMoreComplicatedInitialization();
_AtlModule.SetServiceStatus (SERVICE_START_PENDING);
EvenMoreComplicatedInitialization();
}
return result;
}
This works great in Visual C++ 2005: The Run function calls my PreMessageLoop, which calls the base-class PreMessageLoop. The complicated initialization happens when the service is in SERVICE_START_PENDING. When my PreMessageLoop returns, Run calls SetServiceStatus(SERVICE_RUNNING).
Visual C++ 2010 is different: the base-class PreMessageLoop calls SetServiceStatus(SERVICE_RUNNING). The complicated initialization happens when the service is in SERVICE_RUNNING state, which is not good (because the service looks like it is running when it is in fact still initializing).
Can I simply move the base-class PreMessageLoop call to the bottom of my PreMessageLoop call? Or is it more complicated than a simple move?
Followup
It appears that a service can go from the SERVICE_RUNNING state back to the SERVICE_START_PENDING state. Is that wise?
First of all, "if (ERROR_SUCCESS == result)" is something not quite correct, as you should be checking result against HRESULT values, that is against S_OK, S_FALSE, or using SUCCEEDED sort of macros.
Base PreMessageLoop is registering COM class objects, if your complicated initialization is not using COM instanatiation you are free to move your stuff above __super::PreMessageLoop call.
The COM Initialization codes in PreMessageLoop are causing the Error 1053.
Solution 1: Disable the COM Support.
#define _ATL_NO_COM_SUPPORT
in "stdafx.h" before all ATL related includes.
Solution 2: Override the "PreMessageLoop" and strip it from the COM Initialization codes.
HRESULT PreMessageLoop(_In_ int nShowCmd) throw()
{
if (m_bService)
{
// Make sure that service was not stoped during initialization
if (::InterlockedCompareExchange(&m_status.dwCurrentState, SERVICE_RUNNING, SERVICE_START_PENDING) == SERVICE_START_PENDING)
{
LogEvent(_T("Service started/resumed"));
::SetServiceStatus(m_hServiceStatus, &m_status);
}
}
// Start the tread(s)
_worker = new CWorkerThread();
return S_OK;
}
Related
EDIT:
I have heavily edited this question after making some significant new discoveries and the question not having any answers yet.
Historically/AFAIK, keeping your Mac awake while in closed-display mode and not meeting Apple's requirements, has only been possible with a kernel extension (kext), or a command run as root. Recently however, I have discovered that there must be another way. I could really use some help figuring out how to get this working for use in a (100% free, no IAP) sandboxed Mac App Store (MAS) compatible app.
I have confirmed that some other MAS apps are able to do this, and it looks like they might be writing YES to a key named clamshellSleepDisabled. Or perhaps there's some other trickery involved that causes the key value to be set to YES? I found the function in IOPMrootDomain.cpp:
void IOPMrootDomain::setDisableClamShellSleep( bool val )
{
if (gIOPMWorkLoop->inGate() == false) {
gIOPMWorkLoop->runAction(
OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::setDisableClamShellSleep),
(OSObject *)this,
(void *)val);
return;
}
else {
DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val);
if ( clamshellSleepDisabled != val )
{
clamshellSleepDisabled = val;
// If clamshellSleepDisabled is reset to 0, reevaluate if
// system need to go to sleep due to clamshell state
if ( !clamshellSleepDisabled && clamshellClosed)
handlePowerNotification(kLocalEvalClamshellCommand);
}
}
}
I'd like to give this a try and see if that's all it takes, but I don't really have any idea about how to go about calling this function. It's certainly not a part of the IOPMrootDomain documentation, and I can't seem to find any helpful example code for functions that are in the IOPMrootDomain documentation, such as setAggressiveness or setPMAssertionLevel. Here's some evidence of what's going on behind the scenes according to Console:
I've had a tiny bit of experience working with IOMProotDomain via adapting some of ControlPlane's source for another project, but I'm at a loss for how to get started on this. Any help would be greatly appreciated. Thank you!
EDIT:
With #pmdj's contribution/answer, this has been solved!
Full example project:
https://github.com/x74353/CDMManager
This ended up being surprisingly simple/straightforward:
1. Import header:
#import <IOKit/pwr_mgt/IOPMLib.h>
2. Add this function in your implementation file:
IOReturn RootDomain_SetDisableClamShellSleep (io_connect_t root_domain_connection, bool disable)
{
uint32_t num_outputs = 0;
uint32_t input_count = 1;
uint64_t input[input_count];
input[0] = (uint64_t) { disable ? 1 : 0 };
return IOConnectCallScalarMethod(root_domain_connection, kPMSetClamshellSleepState, input, input_count, NULL, &num_outputs);
}
3. Use the following to call the above function from somewhere else in your implementation:
io_connect_t connection = IO_OBJECT_NULL;
io_service_t pmRootDomain = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPMrootDomain"));
IOServiceOpen (pmRootDomain, current_task(), 0, &connection);
// 'enable' is a bool you should assign a YES or NO value to prior to making this call
RootDomain_SetDisableClamShellSleep(connection, enable);
IOServiceClose(connection);
I have no personal experience with the PM root domain, but I do have extensive experience with IOKit, so here goes:
You want IOPMrootDomain::setDisableClamShellSleep() to be called.
A code search for sites calling setDisableClamShellSleep() quickly reveals a location in RootDomainUserClient::externalMethod(), in the file iokit/Kernel/RootDomainUserClient.cpp. This is certainly promising, as externalMethod() is what gets called in response to user space programs calling the IOConnectCall*() family of functions.
Let's dig in:
IOReturn RootDomainUserClient::externalMethod(
uint32_t selector,
IOExternalMethodArguments * arguments,
IOExternalMethodDispatch * dispatch __unused,
OSObject * target __unused,
void * reference __unused )
{
IOReturn ret = kIOReturnBadArgument;
switch (selector)
{
…
…
…
case kPMSetClamshellSleepState:
fOwner->setDisableClamShellSleep(arguments->scalarInput[0] ? true : false);
ret = kIOReturnSuccess;
break;
…
So, to invoke setDisableClamShellSleep() you'll need to:
Open a user client connection to IOPMrootDomain. This looks straightforward, because:
Upon inspection, IOPMrootDomain has an IOUserClientClass property of RootDomainUserClient, so IOServiceOpen() from user space will by default create an RootDomainUserClient instance.
IOPMrootDomain does not override the newUserClient member function, so there are no access controls there.
RootDomainUserClient::initWithTask() does not appear to place any restrictions (e.g. root user, code signing) on the connecting user space process.
So it should simply be a case of running this code in your program:
io_connect_t connection = IO_OBJECT_NULL;
IOReturn ret = IOServiceOpen(
root_domain_service,
current_task(),
0, // user client type, ignored
&connection);
Call the appropriate external method.
From the code excerpt earlier on, we know that the selector must be kPMSetClamshellSleepState.
arguments->scalarInput[0] being zero will call setDisableClamShellSleep(false), while a nonzero value will call setDisableClamShellSleep(true).
This amounts to:
IOReturn RootDomain_SetDisableClamShellSleep(io_connect_t root_domain_connection, bool disable)
{
uint32_t num_outputs = 0;
uint64_t inputs[] = { disable ? 1 : 0 };
return IOConnectCallScalarMethod(
root_domain_connection, kPMSetClamshellSleepState,
&inputs, 1, // 1 = length of array 'inputs'
NULL, &num_outputs);
}
When you're done with your io_connect_t handle, don't forget to IOServiceClose() it.
This should let you toggle clamshell sleep on or off. Note that there does not appear to be any provision for automatically resetting the value to its original state, so if your program crashes or exits without cleaning up after itself, whatever state was last set will remain. This might not be great from a user experience perspective, so perhaps try to defend against it somehow, for example in a crash handler.
Background
It is possible to perform a software-controlled disconnection of the power adapter of a Mac laptop by creating an DisableInflow power management assertion.
Code from this answer to an SO question can be used to create said assertion. The following is a working example that creates this assertion until the process is killed:
#include <IOKit/pwr_mgt/IOPMLib.h>
#include <unistd.h>
int main()
{
IOPMAssertionID neverSleep = 0;
IOPMAssertionCreateWithName(kIOPMAssertionTypeDisableInflow,
kIOPMAssertionLevelOn,
CFSTR("disable inflow"),
&neverSleep);
while (1)
{
sleep(1);
}
}
This runs successfully and the power adapter is disconnected by software while the process is running.
What's interesting, though, is that I was able to run this code as a regular user, without root privileges, which wasn't supposed to happen. For instance, note the comment in this file from Apple's open source repositories:
// Disables AC Power Inflow (requires root to initiate)
#define kIOPMAssertionTypeDisableInflow CFSTR("DisableInflow")
#define kIOPMInflowDisableAssertion kIOPMAssertionTypeDisableInflow
I found some code which apparently performs the actual communication with the charger; it can be found here. The following functions, from this file, appears to be of particular interest:
IOReturn
AppleSmartBatteryManagerUserClient::externalMethod(
uint32_t selector,
IOExternalMethodArguments * arguments,
IOExternalMethodDispatch * dispatch __unused,
OSObject * target __unused,
void * reference __unused )
{
if (selector >= kNumBattMethods) {
// Invalid selector
return kIOReturnBadArgument;
}
switch (selector)
{
case kSBInflowDisable:
// 1 scalar in, 1 scalar out
return this->secureInflowDisable((int)arguments->scalarInput[0],
(int *)&arguments->scalarOutput[0]);
break;
// ...
}
// ...
}
IOReturn AppleSmartBatteryManagerUserClient::secureInflowDisable(
int level,
int *return_code)
{
int admin_priv = 0;
IOReturn ret = kIOReturnNotPrivileged;
if( !(level == 0 || level == 1))
{
*return_code = kIOReturnBadArgument;
return kIOReturnSuccess;
}
ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeAdministrator);
admin_priv = (kIOReturnSuccess == ret);
if(admin_priv && fOwner) {
*return_code = fOwner->disableInflow( level );
return kIOReturnSuccess;
} else {
*return_code = kIOReturnNotPrivileged;
return kIOReturnSuccess;
}
}
Note how, in secureInflowDisable(), root privileges are checked for prior to running the code. Note also this initialization code in the same file, again requiring root privileges, as explicitly pointed out in the comments:
bool AppleSmartBatteryManagerUserClient::initWithTask(task_t owningTask,
void *security_id, UInt32 type, OSDictionary * properties)
{
uint32_t _pid;
/* 1. Only root processes may open a SmartBatteryManagerUserClient.
* 2. Attempts to create exclusive UserClients will fail if an
* exclusive user client is attached.
* 3. Non-exclusive clients will not be able to perform transactions
* while an exclusive client is attached.
* 3a. Only battery firmware updaters should bother being exclusive.
*/
if ( kIOReturnSuccess !=
clientHasPrivilege(owningTask, kIOClientPrivilegeAdministrator))
{
return false;
}
// ...
}
Starting from the code from the same SO question above (the question itself, not the answer), for the sendSmartBatteryCommand() function, I wrote some code that calls the function passing kSBInflowDisable as the selector (the variable which in the code).
Unlike the code using assertions, this one only works as root. If running as a regular user, IOServiceOpen() returns, weirdly enough, kIOReturnBadArgument (not kIOReturnNotPrivileged, as I would have expected). Perhaps this has to do with the initWithTask() method above.
The question
I need to perform a call with a different selector to this same Smart Battery Manager kext. Even so, I can't even get to the IOConnectCallMethod() since IOServiceOpen() fails, presumably because the initWithTask() method prevents any non-root users from opening the service.
The question, therefore, is this: how is IOPMAssertionCreateWithName() capable of creating a DisableInflow assertion without root privileges?
The only possibility I can think of is if there's a root-owned process to which requests are forwarded, and which performs the actual work of calling IOServiceOpen() and later IOConnectCallMethod() as root.
However, I'm hoping there's a different way of calling the Smart Battery Manager kext which doesn't require root (one that doesn't involve the IOServiceOpen() call.) Using IOPMAssertionCreateWithName() itself is not possible in my application, since I need to call a different selector within that kext, not the one that disables inflow.
It's also possible this is in fact a security vulnerability, which Apple will now fix in a future release as soon as it is alerted to this question. That would be too bad, but understandable.
Although running as root is a possibility in macOS, it's obviously desirable to avoid privilege elevation unless absolutely necessary. Also, in the future I'd like to run the same code under iOS, where it's impossible to run anything as root, in my understanding (note this is an app I'm developing for my own personal use; I understand linking to IOKit wipes out any chance of getting the app published in the App Store).
According to the documentation for IFileOperation::SetOperationFlags, the FOFX_RECYCLEONDELETE flag was introduced in Windows 8.
I would like to delete files and send them to the recycle bin. How is it possible to do that using IFileOperation in Vista and Windows 7?
I know that SHFileOperation supports that functionality, but I don't want to use SHFileOperation as Microsoft are telling us to use IFileOperation in its place. Is this possible using IFileOperation, and if so, how is it to be done?
The documentation for SetOperationFlags says:
This member can be a combination of the following flags. FOF flags are defined in Shellapi.h and FOFX flags are defined in Shobjidl.h.
So you can use the exact same flag, FOF_ALLOWUNDO, that you use with SHFileOperation to direct a delete action to move to the recycle bin.
FOFX_RECYCLEONDELETE flag was introduced in Win 8 - will it work in Vista/7?
Since FOFX_RECYCLEONDELETE was introduced in Windows 8, then it did not exist in Vista/7, so no, it will not work in those versions.
There's always SHFileOperation but I'd rather use a more up-to-date Win32 API method. Anything else to know? Any alternate ways of recycling files/folders?
SHFileOperation() is the only documented way to recycle files/folders:
When used to delete a file, SHFileOperation permanently deletes the file unless you set the FOF_ALLOWUNDO flag in the fFlags member of the SHFILEOPSTRUCT structure pointed to by lpFileOp. Setting that flag sends the file to the Recycle Bin. If you want to simply delete a file and guarantee that it is not placed in the Recycle Bin, use DeleteFile.
That same flag is available in IFileOperation, but its documented behavior is different:
Preserve undo information, if possible.
Prior to Windows Vista, operations could be undone only from the same process that performed the original operation.
In Windows Vista and later systems, the scope of the undo is a user session. Any process running in the user session can undo another operation. The undo state is held in the Explorer.exe process, and as long as that process is running, it can coordinate the undo functions.
That is why FOFX_RECYCLEONDELETE had to be introduced - to re-add the old Recycle Bin behavior that had been lost when IFileOperation was first introduced.
I have verified David Heffernan's assessment of the FOF_ALLOWUNDO flag's use with IFileOperation to send items to the recycle bin. Here's the code. Apparently SHCreateItemFromParsingName is MS's way of saying create an item from a string. This code is catered to C++ with Qt. You'll have to initialize COM first of course.
void Worker::deleteItem(QString item)
{
HRESULT hr;
IFileOperation *pfo;
wchar_t *itemWChar = new wchar_t[item.length()+1];
item.toWCharArray(itemWChar);
itemWChar[item.length()] = 0;
PCWSTR itemPCWSTR = itemWChar;
hr = CoCreateInstance(CLSID_FileOperation,
NULL,
CLSCTX_ALL,
//IID_IFileOperation,
IID_PPV_ARGS(&pfo));
if (!SUCCEEDED(hr))
{
//error handling here
return;
}
hr = pfo->SetOperationFlags(FOF_ALLOWUNDO | FOF_NOCONFIRMATION);
if (!SUCCEEDED(hr))
{
//error handling here
return;
}
IShellItem *deleteItem = NULL;
hr = SHCreateItemFromParsingName(itemPCWSTR,
NULL,
IID_PPV_ARGS(&deleteItem));
if (!SUCCEEDED(hr))
{
//error handling here
return;
}
hr = pfo->DeleteItem(deleteItem,NULL);
if (deleteItem != NULL)
{
deleteItem->Release();
}
if (!SUCCEEDED(hr))
{
//error handling here
return;
}
hr = pfo->PerformOperations();
if (!SUCCEEDED(hr))
{
//error handling here
return;
}
pfo->Release();
delete[] itemWChar;
}
I'm trying to change the value of a flag in an IPropertyStore. However, my code seems to behave the same way, regardless of the value of the flag.
Is this because my code doesn't call IPropertyStore_Commit after changing the flag?
I did try to call the method, however I got an error code 0x80004001 which means "not implemented". Hence, the second part of my question: why isn't it implemented?
In more detail, I'm working on a Java softphone which makes use of WASAPI (via the JNI) for some of the audio processing. The native code is written in C.
Having recently enabled AES (Acoustic Echo Suppression), I've found that AGC (Automatic Gain Control) is also enabled. I'm trying to disable AGC by setting the MFPKEY_WMAAECMA_FEATR_AGC key on an IPropertyStore object. However, whatever I set the value to be makes no difference.
The relevant code snippets are as follows:
// Obtain the property store
void *pvObject;
HRESULT hr = IMediaObject_QueryInterface((IMediaObject *) thiz, &iid_, &pvObject);
// Do some checking that the store is valid...
// Set the value of the AGC key:
PROPVARIANT propvar = ...
IPropertyStore_SetValue((IPropertyStore *)pvObject, (REFPROPERTYKEY) key, &propvar);
// Call commit - fails, with 0x80004001:
HRESULT hr = IPropertyStore_Commit((IPropertyStore *)pvObject);
A couple of issues:
I'm not sure what thiz actually is; I'm pretty sure it's not an IMediaObject interface.
You can't just cast from IMediaObject to IPropertyStore; you have to QueryInterface the IMediaObject pointer for IPropertyStore.
You shouldn't need to call IPropertyStore_Commit; at least, not for setting the AGC key.
When you're calling IPropertyStore_SetValue, make sure the PROPVARIANT is initialized correctly. MFPKEY_WMAAECMA_FEATR_AGC is a BOOLEAN property, so your code needs to look something like this:
IMediaObject *pvObject;
HRESULT hr = IUnknown_QueryInterface((IUnknown*) thiz, IID_PPV_ARGS(&pvObject));
if (SUCCEEDED(hr))
{
IPropertyStore* pvPropStore;
hr = IMediaObject_QueryInterface(pvObject, IID_PPV_ARGS(&pvPropStore));
if (SUCCEEDED(hr))
{
PROPVARIANT pvFeature;
PropVariantInit(&pvFeature);
pvFeature.vt = VT_BOOL;
pvFeature.boolVal = fValue ? VBTRUE : VBFALSE;
hr = IPropertyStore_SetValue(pvPropStore, MFPKEY_WMAAECMA_FEATR_AGC, pvFeature);
}
}
I would like to know how to use the Invoke method of the TRttiMethod class in C++Builder 2010.
This is my code
Tpp *instance=new Tpp(this);
TValue *args;
TRttiContext * ctx=new TRttiContext();
TRttiType * t = ctx->GetType(FindClass(instance->ClassName()));
TRttiMethod *m=t->GetMethod("Show");
m->Invoke(instance,args,0);
Show has no arguments and it is __published. When I execute I get a EInvocationError with message 'Parameter count mismatch'.
Can someone demonstrate the use of Invoke? Both no arguments and with arguments in the called method.
Thanks
Josep
You get the error because you are telling Invoke() that you are passing in 1 method parameter (even though you really are not, but that is a separate bug in your code). Invoke() takes an OPENARRAY of TValue values as input. Despite its name, the Args_Size parameter is not the NUMBER of parameters being passed in, but rather is the INDEX of the last parameter in the array. So, to pass 0 method parameters to Show() via Invoke(), set the Args parameter to NULL and the Args_Size parameter to -1 instead of 0, ie:
Tpp *instance = new Tpp(this);
TRttiContext *ctx = new TRttiContext;
TRttiType *t = ctx->GetType(instance->ClassType());
TRttiMethod *m = t->GetMethod("Show");
m->Invoke(instance, NULL, -1);
delete ctx;
Now, once you fix that, you will notice Invoke() start to raise an EInsufficientRtti exception instead. That happens when Runtime Packages are enabled. Unfortunately, disabling Runtime Packages will cause TRttiContext::GetType() to raise an EAccessViolation in TRttiPool::GetPackageFor() because of a known linker bug under C++:
QC #76875, RAID #272782: InitContext.PackageTypeInfo shouldn't be 0 in a C++ module:
Which causes these bugs:
QC #76672, RAID #272419: Rtti.pas is unusable in a C++ application
QC #76877, RAID #272767: AV in TRttiContext::GetType() when Runtime Packages are disabled
So you are in a catch-22 situation. The new RTTI system is not ready for production work in C++ yet. You will have to use Delphi instead for the time being.