python/pyqt - Pass a CancelEvent to a C++ function - windows

I have a WinApi function with a CancelEvent parameter but I don't know what I have to pass there?
HRESULT WINAPI DismUnmountImage(
_In_ PCWSTR MountPath,
_In_ DWORD Flags,
_In_opt_ HANDLE CancelEvent,
_In_opt_ DISM_PROGRESS_CALLBACK Progress,
_In_opt_ PVOID UserData
);
https://msdn.microsoft.com/en-us/library/windows/desktop/hh824802(v=vs.85).aspx
I'm working with python 3.6 on Windows 10. The function is working properly, the progress dialog too. I used QProgressDialog widget to display progress state, I only have to implement the CancelEvent.
The reDefinition:
from ctypes import *
import win32con, win32api
def UnmountImage(self, MountPath, Flags=DISM_DISCARD_IMAGE, CancelEvent=None, Progress=None, UserData=None):
self.hDism.DismUnmountImage.restype = HRESULT
try:
return self.hDism.DismUnmountImage(MountPath, Flags, CancelEvent, Progress, UserData)
except OSError as e:
print("DismUnmountImage failed: %s\nErrorCode: %s" % (e.strerror, e))
return self.GetLastErrorMessage()
And the pyqt part:
def canceled(self):
print("canceled")
#pyqtSlot(QVariant)
def unmount_image(self, json_data):
dism_progress_callback = dism_manager.DISM_PROGRESS_CALLBACK(self.dism_progress_callback)
data = json.loads(json_data)
self.progdialog = QProgressDialog("", "Cancel", 0, 100, None)
self.progdialog.setWindowTitle("Unmounting Image...")
self.progdialog.setModal(True)
self.progdialog.canceled.connect(self.canceled)
self.progdialog.show()
for image in data:
dism_manager.UnmountImage(MountPath=image['MountPath'], Progress=dism_progress_callback, CancelEvent=self.progdialog.winId())
I tried to pass the handle of the qtWindow but I get an error message ..can't convert parameter 3... What does the function expect? A windows handle? I really have no idea and I'm not familar with C++.
Btw: The QProgressdialog is a window with a QProgress and a QButton. When I click on the Cancel button, my def canceled(self): method is emitted and the window will be closed for a second and then the progress continues.
EDIT:
After zett42 suggestions I came up with this:
DISM_CANCEl_EVENT = CreateEvent(None, False, False, None)
And:
def canceled(self):
print("canceled")
SetEvent(dism_manager.DISM_CANCEl_EVENT)
...
for image in data:
dism_manager.UnmountImage(MountPath=image['MountPath'], Progress=dism_progress_callback, CancelEvent=dism_manager.DISM_CANCEl_EVENT)
I get this error message:
ctypes.ArgumentError: argument 3: <class 'TypeError'>: Don't know how to convert parameter 3
Do you have any idea, what I am missing?
EDIT2:
I got it:
def canceled(self):
self.progdialog.cancel()
SetEvent(self.cancel_event)
self.cancel_event = dism_manager.DISM_CANCEl_EVENT.Detach()
for image in data:
dism_manager.UnmountImage(MountPath=image['MountPath'], Progress=dism_progress_callback, CancelEvent=self.cancel_event)
The only problem I have: The cancelevent needs round about 2 seconds to be performed so that meanwhile the dism_progress_callback forces the window to popup again, although i called self.progdialog.cancel() which closes the window...hope you can follow me. Do you have any suggestions how i can control this?
Solved:
I got a final solution: I called self.progdialog.canceled.disconnect() before self.progdialog.canceled.connect(self.dism_cancel_event) to overwrite the canceled() signal and prevent the call of cancel().

The function expects the handle of an event object which can be created using the CreateEvent() C API. In Python you may call win32event.CreateEvent().
In your function def canceled(self) you should call win32event.SetEvent(hEvent) passing the handle of the event object you created for the hEvent parameter. This will request a cancellation of UnmountImage().

Related

Enabling Closed-Display Mode w/o Meeting Apple's Requirements

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.

Using promises with Transcrypt

I'm having great fun with Transcrypt, a fantastic Python 3 to Javascript compiler available as a python module. Most of my code is synchronous, but i've had no problem doing things with setTimeout and XHR requests. Now i've started using PouchDB for local persistence and am trying to find a pretty way to handle promises. At the moment, I am doing this to write to a pouchdb instance:
def db_put():
def put_success(doc):
print("Put a record in the db. Id: ", doc.id, "rev: ", doc.rev)
def put_failure(error):
print('Failed to put a record in the db. Error: ', error)
strHello = {'_id': "1", 'title': 'hello db'}
db.put(strHello) \
.then(put_success) \
.catch(put_failure)
db = PouchDB('test_db')
document.getElementById("db_put").addEventListener("click", db_put)
This works fine, but I am curious to know a few things about promises being transcrypted from python to Javascript (this may save me from madness):
Are there more preferable 'pythonic' ways to handle this?
Can one make use of ES7's async / await through Transcrypt? Since Transcrypt allows Javascript functions to be accessed directly from within the python code, i thought there might be some trick here that i'm not getting..
Thanks!
About the promises
The way you dealt with promises looks pythonic enough to me.
In case you get tired of the line continuations where 'fluent' notation (call chaining) is involved, there's an alternative to using \. This alternative is used e.g. in the d3js_demo that comes with Transcrypt, in the following fragment:
self.svg = d3.select('body'
).append('svg'
).attr('width', self.width
).attr('height', self.height
).on('mousemove', self.mousemove
).on('mousedown', self.mousedown)
Since many .then's can be chained as well, one could write:
db.put(strHello
).then(put_success
).then(put_success_2
).then(put_success_3
... etc.
).catch(put_failure)
After some getting used to, this will immediately make clear that call chaining is involved. But it is only a matter of formatting.
about async/await
They aren't yet supported, but the plan is they will be soon after JS officially has them (JS7, I hope). For now you can use __pragma__ ('js', '{}', '''<any javascript code>''') as a workaround.
Async/await is supported some time now. You can use it to deal with Promises. For example:
Enable JQuery usage:
__pragma__ ('alias', 'S', '$')
Define a function which returns a Promise, in this case an Ajax call:
def read(url: str) -> 'Promise':
deferred = S.Deferred()
S.ajax({'type': "POST", 'url': url, 'data': { },
'success': lambda d: deferred.resolve(d),
'error': lambda e: deferred.reject(e)
})
return deferred.promise()
Use the asynchronous code as if it were synchronous:
async def readALot():
try:
result1 = await read("url_1")
result2 = await read("url_2")
except Exception:
console.warn("Reading a lot failed")
Happy usage of python in the browser

Ignoring exclusively locked files in SHFileOperation

I am using Windows 7 Professional and I am using SHFileOperation() to recursive copy one folder contents to another. But there is a locked file (opened exclusively by an application); I need to skip it, but SHFileOperation() returns 0x20 when tries to copy this file.
How can I skip this file during the file copy operation?
UPDATE: this is the code:
//
// CopyDirectory()
// рекурсивное копирование содержимого одной директории в другую средствами Windows
// lpszSource - исходная папка
// lpszDestination - папка назначения
//
BOOL CopyDirectory( LPSTR lpszSource, LPSTR lpszDestination )
{
LPSTR lpszNewSource = NULL;
// структура операции с файлами
SHFILEOPSTRUCT fileOP = { 0 };
// выделим память под новый путь
lpszNewSource = (LPSTR)calloc(strlen(lpszSource) + 50, 1);
// запишем новый путь с маской
wsprintf(lpszNewSource, "%s\\*", lpszSource);
// запишем параметры операции копирования
fileOP.wFunc = FO_COPY;
fileOP.pTo = lpszDestination;
fileOP.pFrom = lpszSource;
fileOP.fFlags = FOF_SILENT | FOF_NOCONFIRMMKDIR | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_NO_UI;
// выполняем операцию
INT retVal = SHFileOperation( &fileOP );
// освободим память
FREE_NULL(lpszNewSource);
DebugPrint(DEBUG_INFO, "retVal = %d\n", retVal);
// возвращаем результат копирования
return retVal == 0;
}
The SHFileOperation() documentation says:
Return value
Type: int
Returns zero if successful; otherwise nonzero. Applications normally should simply check for zero or nonzero.
It is good practice to examine the value of the fAnyOperationsAborted member of the SHFILEOPSTRUCT. SHFileOperation can return 0 for success if the user cancels the operation. If you do not check fAnyOperationsAborted as well as the return value, you cannot know that the function accomplished the full task you asked of it and you might proceed under incorrect assumptions.
Do not use GetLastError with the return values of this function.
To examine the nonzero values for troubleshooting purposes, they largely map to those defined in Winerror.h. However, several of its possible return values are based on pre-Win32 error codes, which in some cases overlap the later Winerror.h values without matching their meaning. Those particular values are detailed here, and for these specific values only these meanings should be accepted over the Winerror.h codes.
In your case, 0x20 is not one of the pre-Win32 error codes, so it maps to a standard Win32 error code, specifically ERROR_SHARING_VIOLATION, which is appropriate for your situation as one of the files could not be accessed.
To skip the offending file, enable the FOF_NOERRORUI flag in the SHFILEOPSTRUCT::fFlags field. The SHFILEOPSTRUCT documentation says only the following about that flag:
FOF_NOERRORUI
Do not display a dialog to the user if an error occurs.
However, the documentation does also say this:
fAnyOperationsAborted
Type: BOOL
When the function returns, this member contains TRUE if any file operations were aborted before they were completed; otherwise, FALSE. An operation can be manually aborted by the user through UI or it can be silently aborted by the system if the FOF_NOERRORUI or FOF_NOCONFIRMATION flags were set.
The documentation for IFileOperation (which replaces SHFileOperation() on Vista and later) has more to say about the FOF_NOERRORUI flag:
FOF_NOERRORUI (0x0400)
Do not display a message to the user if an error occurs. If this flag is set without FOFX_EARLYFAILURE, any error is treated as if the user had chosen Ignore or Continue in a dialog box. It halts the current action, sets a flag to indicate that an action was aborted, and proceeds with the rest of the operation.
...
FOFX_EARLYFAILURE (0x00100000)
If FOFX_EARLYFAILURE is set together with FOF_NOERRORUI, the entire set of operations is stopped upon encountering any error in any operation. This flag is valid only when FOF_NOERRORUI is set.
So, with FOF_NOERRORUI enabled, the return value of ERROR_SHARING_VIOLATION, and also the SHFILEOPSTRUCT::fAnyOperationsAborted field being set to TRUE, will tell you that a file could not be accessed during the copy, but not which file specifically. It does not mean that the entire SHFileOperation() task failed completely.

IPropertyStore_Commit method - is it needed and why isn't it implemented?

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);
}
}

Determine the registered application for an extension

I've got a file extension and I'd like to get the name of the application (if there is one) that will be invoked when I ShellExecute a file of that type. This is a WTL/C++ app. Is there any sample code out there that does this?
Thanks!
twk,
You're probably looking for the Win32 AssocQueryStringByKey Function.
http://msdn.microsoft.com/en-us/library/bb773473(VS.85).aspx
The ASSOCSTR value that specifies the type of string that is to be returned:
typedef enum {
ASSOCSTR_COMMAND = 1,
ASSOCSTR_EXECUTABLE,
ASSOCSTR_FRIENDLYDOCNAME,
ASSOCSTR_FRIENDLYAPPNAME,
ASSOCSTR_NOOPEN,
ASSOCSTR_SHELLNEWVALUE,
ASSOCSTR_DDECOMMAND,
ASSOCSTR_DDEIFEXEC,
ASSOCSTR_DDEAPPLICATION,
ASSOCSTR_DDETOPIC,
ASSOCSTR_INFOTIP,
ASSOCSTR_QUICKTIP,
ASSOCSTR_TILEINFO,
ASSOCSTR_CONTENTTYPE,
ASSOCSTR_DEFAULTICON,
ASSOCSTR_SHELLEXTENSION,
ASSOCSTR_DROPTARGET,
ASSOCSTR_DELEGATEEXECUTE,
ASSOCSTR_MAX
} ASSOCSTR;
My guess is that you want ASSOCSTR_FRIENDLYAPPNAME.
DWORD dwSize = 255;
TCHAR sBuffer[MAX_PATH] = {0};
HRESULT hr = AssocQueryString(0, ASSOCSTR_EXECUTABLE, _T(".htm"), _T("Open"), sBuffer, &dwSize);
CString csExt;
csExt.Format(_T("%s"), sBuffer);
AfxMessageBox(csExt);
Sorry, no code, but some useful information. See this related question: how-does-vista-generate-the-icon-for-documents-associated-to-my-application
It asked about icons, but it turns out the program associated to an extension is stored in the same place in the registry as the icon for that extension.
It's a Win32 FAQ since 1995 (Shell, see Google Groups, Win32)

Resources