Starting Microsoft Edge from MFC with web file paramater - visual-c++

If I open up a console prompt I can type this command:
start msedge "d:\HTML\Verticle Alignment.HTM"
It starts Microsoft Edge and opens the web page.
So I tried to do this programmatically in a test program using MFC:
void CMFCApplication8Dlg::OnBnClickedButton1()
{
ExecuteProgram(_T("start"), _T("msedge d:\\HTML\\Verticle Alignment.HTM"));
}
BOOL CMFCApplication8Dlg::ExecuteProgram(CString strProgram, CString strArguments)
{
SHELLEXECUTEINFO se = { 0 };
MSG sMessage;
DWORD dwResult;
se.cbSize = sizeof(se);
se.lpFile = strProgram;
se.lpParameters = strArguments;
se.nShow = SW_SHOWDEFAULT;
se.fMask = SEE_MASK_NOCLOSEPROCESS;
ShellExecuteEx(&se);
if (se.hProcess != nullptr)
{
do
{
dwResult = ::MsgWaitForMultipleObjects(1, &(se.hProcess), FALSE,
INFINITE, QS_ALLINPUT);
if (dwResult != WAIT_OBJECT_0)
{
while (PeekMessage(&sMessage, nullptr, NULL, NULL, PM_REMOVE))
{
TranslateMessage(&sMessage);
DispatchMessage(&sMessage);
}
}
} while ((dwResult != WAIT_OBJECT_0) && (dwResult != WAIT_FAILED));
CloseHandle(se.hProcess);
}
if ((DWORD_PTR)(se.hInstApp) < 33)
{
// Throw error
AfxThrowUserException();
return FALSE;
}
return TRUE;
}
But when I run it I get this error message:
So how can I launch my file in Microsoft Edge? I am using the latest Windows 10 so it is Microsoft Edge Chromium.
I have seen other questions which refer to making Edge the default browser and then just "opening" the data file and it working it all out but this is not OK in this case. In my editor I have a menu flyout which lists all the installed browsers (excluding Edge for now). But i want to add Edge so need to be able to programatically start it with my file to view.

Based on the comments provided to me, and to factor in for spaces in the file name, this works:
ExecuteProgram(_T("msedge"), _T("\"d:/HTML/Verticle Alignment.HTM\""));
The program to execute needs to be msedge and not start.
The parameter needs to be wrapped in " quotes.

Related

IDataObjectAsyncCapability not being handled by Outlook in OLE Drag and Drop

I work on an electron application, and we would like to support dragging and dropping .msg files from our app into Outlook (or the Windows shell, or wherever, but primarily Outlook). The files will not necessarily be available before the user starts the drag and drop operation, and will need to be downloaded once the user begins the drag and drop. This means we can't use electron's inbuilt startDrag as it requires that the files are already in the filesystem, so I have implemented a node c++ addon to handle it using the OLE Drag and Drop API.
The data extraction (from my app to Outlook) needs to occur asynchronously, otherwise node's event loop will be blocked, halting the download. This means that the data extraction has to occur on another thread so that the event loop can continue actually downloading the data (currently doing the download in c++ is not an option, it has to occur in node). So I have implemented IDataObjectAsyncCapability on my DataObject, to indicate that I support asynchronous data extraction (it would be even nicer to be able to indicate that I don't support synchronous), but Outlook won't even query for the Interface, let alone do the data extraction asynchronously. The Windows shell does however query for the interface, but after the call to GetData, it still performs the extraction synchronously inside DoDragDrop, without even invoking any of the IDataObjectAsyncCapability methods. Is there something lacking in my implementation, or a specific way to encourage the drop target to start up a new thread?
Here is the meat of my DataObject implementation, if there's anything else that could be of use, I can provide.
STDMETHODIMP DataObject::QueryInterface(REFIID iid, LPVOID* ppvObject) {
if (ppvObject == nullptr) {
return E_INVALIDARG;
} else if (iid == IID_IUnknown) {
AddRef();
*ppvObject = reinterpret_cast<LPUNKNOWN>(this);
return S_OK;
} else if (iid == IID_IDataObject) {
AddRef();
*ppvObject = reinterpret_cast<LPDATAOBJECT>(this);
return S_OK;
} else if (iid == IID_IDataObjectAsyncCapability) {
AddRef();
*ppvObject = reinterpret_cast<IDataObjectAsyncCapability*>(this);
return S_OK;
}
*ppvObject = nullptr;
return E_NOINTERFACE;
}
STDMETHODIMP DataObject::GetData(LPFORMATETC queryFormat,
LPSTGMEDIUM outputStorage) {
if (queryFormat->cfFormat == CF_FILEDESCRIPTOR &&
(queryFormat->tymed & TYMED_HGLOBAL) && queryFormat->lindex <= 0 &&
queryFormat->dwAspect == DVASPECT_CONTENT) {
outputStorage->tymed = TYMED_HGLOBAL;
outputStorage->pUnkForRelease = nullptr;
outputStorage->hGlobal =
lockAndDuplicateHGLOBAL(this->groupDescriptorStorage.hGlobal);
return S_OK;
} else if (queryFormat->cfFormat == CF_FILECONTENTS &&
(queryFormat->tymed & TYMED_ISTREAM) &&
queryFormat->dwAspect == DVASPECT_CONTENT &&
queryFormat->lindex >= 0 &&
queryFormat->lindex < this->files.size()) {
// files is vector<pair<FILEDESCRIPTOR, STGMEDIUM>>
// where the STGMEDIUM is set to IStream
// Am I doing something wrong here?
auto file = this->files[queryFormat->lindex].second;
*outputStorage = file;
return S_OK;
}
return DV_E_FORMATETC;
}
STDMETHODIMP DataObject::QueryGetData(LPFORMATETC queryFormat) {
if (queryFormat->cfFormat == CF_FILEDESCRIPTOR ||
(queryFormat->cfFormat == CF_FILECONTENTS &&
(queryFormat->tymed & TYMED_HGLOBAL))) {
return S_OK;
}
return DATA_E_FORMATETC;
}
STDMETHODIMP DataObject::EnumFormatEtc(DWORD dwDirection,
LPENUMFORMATETC* ppEnumFormatEtc) {
if (dwDirection == DATADIR_GET) {
// basic implementation of IEnumFormatEtc (not mine)
return EnumFormat::Create(this->supportedFormats, this->numFormats,
ppEnumFormatEtc);
}
return E_INVALIDARG;
}
// Do the actual drag drop
// files is a list of STGMEDIUMS with IStreams. I'm using data that's readily available while
// implementing this, could that be somehow interfering and causing this problem in the first place?
DWORD dwEffect;
auto dataObject = new DataObject(groupDescriptorStorage, files);
auto dropSource = new DropSource();
// Do these DROPEFFECTS have an effect?
auto result = DoDragDrop(dataObject, dropSource,
DROPEFFECT_COPY | DROPEFFECT_MOVE, &dwEffect);
// By the time we get here, the data extraction would already have occured
// because it's happening inside DoDragDrop. of course, isAsyncOperation will be false
BOOL isInAsyncOperation;
dataObject->InOperation(&isInAsyncOperation);
I've followed the instructions from here as well as various forum posts I've found, but I can't seem to find anything about what to do when the drop target doesn't play ball.
I'm really stuck for ideas as to how to make this work. If the drop target isn't even querying for IDataObjectAsyncCapability then is it hopeless? Should I be returning something other than the file contents when it's first requested?

Read file metadata via Windows Search from MFC program

I would like to read metadata of a DWG/AutoCAD file via Windows Search indexing service. I'm talking about properties that can be accessed with the right click in explorer without opening AutoCAD.
I have an MFC dialog based application written in Visual C++ 2005 and from inside this app I would like to access metadata (such as author, creation date etc.) of the given file. This was done by iFilter but it is deprecated since Windows XP and will be gone in Windows 8 (and LoadIFilter is not present in VS2005). Now from what I understand, it can be done with windows search - correct me if I'm wrong. Every example I found (msdn included) shows how to give data about your own files to windows search for indexing though. What I need is to know how to ask Windows Search about metadata for a given file.
Thanks
t.g.wilk
EDIT:
Here's what I've come up with so far:
BOOL WSQ_DoQuery( const wchar_t *constr, const wchar_t *querystr, VARIANT &result ) {
HRESULT hr = 0;
BOOL ret;
// Get the ADO connection
_Connection *con = NULL;
hr = CoCreateInstance( CLSID_Connection, NULL, CLSCTX_ALL, IID__Connection, (LPVOID *)&con );
if ( SUCCEEDED(hr) ) {
_Recordset *rs = NULL;
// Convert wide strings to BSTR as required by ADO APIs
BSTR bconstr = SysAllocString( constr );
BSTR bquerystr = SysAllocString( querystr );
if ( bconstr && bquerystr ) {
// Open the connection
hr = con->Open( bconstr, NULL, NULL, 0 );
if ( SUCCEEDED(hr) ) {
// Execute the query
hr = con->Execute( bquerystr, NULL, 0, &rs );
if ( SUCCEEDED(hr) ) {
// Display the results
ret = WSQ_GetCDate( rs ,result);
rs->Release();
} else {
TRACE( "Failed to execute query, %08x\r\n", hr );
} // if
} else {
TRACE( "Failed to open ADO connection, %08x\r\n", hr );
} // if
} else {
TRACE("Failed to convert wide to BSTR\r\n" );
} // if
con->Release();
if ( bconstr ) {
SysFreeString( bconstr );
}
if ( bquerystr ) {
SysFreeString( bquerystr );
}
} else {
TRACE("Failed to get connection, %08x\r\n", hr );
} // if
return ret;
} // DoQuery
The connection string (constr) is
provider=Search.CollatorDSO.1;EXTENDED PROPERTIES="Application=Windows"
as returned by ISearchQueryHelper.
And the query (querystr) is
SELECT System.Document.DateCreated FROM SystemIndex WHERE System.FileName LIKE 'filename%' AND DIRECTORY='file:C:\path\to\file'
The problem now is that I get an exception:
First-chance exception at 0x77c5fc56 in fraudTest.exe: Microsoft C++ exception: CNLBaseException at memory location 0x0012d6d0..
on this line
hr = con->Open( bconstr, NULL, NULL, 0 );
followed by the empty result from the query (this code is from WSQ_GetCDate):
rs->get_EOF( &eor );
while ( eor != VARIANT_TRUE ) { //this never executes }
Suprisingly SUCCEEDED(hr) returns true after the exception.
Where have I made en error and how to try and find it?
Thanks
t.g.wilk
I didn't solve this particular problem, but I learned that I don't need Windows Search to get the file metadata. The keyword to look for is "properties" instead of meta-data. I got my piece of code from Windows SDK v7.0 sample application named PropertyEdit.

Does AceFlags behavior changes with OS?

My utility extracts ACL from a directory & adds it to another. My issue is this -
While iterating through ACEs, I found that for ACEs with AceFlags value = 0, inherit flags (Applied To) is "Folder, subfolders & directories". When I apply the same ACL to another directory, in Windows 7 it works fine. However, in Windows XP, the inherit flags changes to "Folder only". Here is the code -
BOOL SetNonInheritedAceToTarget(LPWSTR pszSource, LPWSTR pszDestination)
{
BOOL bRetVal = FALSE;
DWORD dwRes = 0;
PSECURITY_DESCRIPTOR pSD = NULL;
PACL pacl = NULL;
if( ERROR_SUCCESS == GetNamedSecurityInfo(pszSource, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &pacl, NULL, &pSD) )
{
if(pacl)
{
for (USHORT i = 0; i < pacl->AceCount; i++)
{
ACCESS_DENIED_ACE * PACE = NULL;
if (!GetAce(pacl, i,(LPVOID*) &PACE))
continue;
if(PACE->Header.AceFlags & INHERIT_ONLY_ACE || PACE->Header.AceFlags & INHERITED_ACE)
{
// Delete the ACE
if(!DeleteAce(pacl, i))
{
TCHAR szErrorMsg[300] = {0};
wsprintf(szErrorMsg, L"Unable to delete ACE from DACL of = %ls", pszSource);
OutputDebugString(szErrorMsg);
}
}
}
}
}
if(ERROR_SUCCESS == SetNamedSecurityInfo(pszDestination, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION, NULL, NULL, pacl, NULL))
bRetVal = TRUE;
return bRetVal;
}
I don't know if I am messing up with the code or is it really OS related issue. Help!!!. Again, if it is OS related issue, what do recommend, should I assign AceFlag manually?
--
Varun
Yes, ACE have changed with the arrival of Vista, mainly because of the integration of Integrity Level - previously called Integrity Control (IL). You must manually take care of these when your code must run on Windows 7 AND XP.
Oh... Silly me. I was checking INHERIT_ONLY_ACE to see it the ACE is inhereted... Any ways, as Mox pointed out, with vista (and above), new ACEs have been added to enhance integrity check in windows based objects. However, this does not change the way ACEs are interpreted. My code is fine, I was just checking an extra flag.
Thanks Mox for educating me.
--
Varun

How to embed gstreamer videosink to a browser

I am working on a webkit-kernel-browser plugin.
Most plugin obey the rules of NPAPI.
After call the NP_new function,the browser should call the Npp_setwindows and etc.
But the chrome browser does not run this .
It call the Np_destory to finished the instance straightly.
So I can not get the browser 's xid to set the videosink on it .
How can work it out?
And when I use the firefox browser, I can get the xid.
Unfortunately ,When I use the gst_x_overlay_set_xwindow_id to embed to the browser .
The browser crashed.
Here is some code for test.
gst_init (NULL, NULL);
player->pipeline = gst_element_factory_make ("playbin2", "playstation");
LOGMSG("create playbin2");
player->audio_sink = gst_element_factory_make ("alsasink", "audio-sink");
if (NULL == player->audio_sink)
{
player->audio_sink = gst_element_factory_make ("autoaudiosink", "audio-sink");
g_warning ("Could not create a GST audio_sink. Audio unavailable.");
}
player->video_sink = gst_element_factory_make ("xvimagesink", "video-sink");
if (NULL == player->video_sink)
{
//pvrvideosink is used for some special solution ,but this case never used
player->video_sink = gst_element_factory_make ("pvrvideosink","video-sink");
g_warning ("Could not create a GST video_sink. Video unavailable.");
}
g_object_set (player->video_sink, "force-aspect-ratio", TRUE, NULL);
sprintf(buff," \n pipleline:%p\n video:%p\n audio:%p\n uri:%s\n xid:%d",
player->pipeline,player->video_sink,player->audio_sink,player->uri,player->xid);
LOGMSG(buff);enter code here
// log shows all the content is ok
g_object_set (player->pipeline, "video-sink", player->video_sink, NULL);
g_object_set (player->pipeline, "audio-sink", player->audio_sink, NULL);
g_object_set (player->pipeline, "uri",player->uri, NULL);
player->bus = gst_element_get_bus (GST_ELEMENT (player->pipeline));
gst_bus_add_watch(player->bus,(void *)process_events,player);
LOGMSG("start set winid");
/*
chrome can not get the browser xid ,so it display the image in fullscreen way with the player 's own window. The firefox can not display the image at all. It crashed here.
*/
if (player->xid != 0 )
{
gst_x_overlay_prepare_xwindow_id(GST_X_OVERLAY(GST_ELEMENT(player->video_sink)));
gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(GST_ELEMENT(player->video_sink)),player->xid);
gboolean spt = gst_x_overlay_set_render_rectangle
(GST_X_OVERLAY(GST_ELEMENT(player->video_sink)),10,10,480,270);
if (!spt)
{
LOGMSG("not support the rectangle");
}
gst_x_overlay_expose(GST_X_OVERLAY(GST_ELEMENT(player->video_sink)));
}
LOGMSG("set xwinid finished");
gst_element_set_state(player->pipeline,GST_STATE_PLAYING);
loop = g_main_loop_new (NULL, FALSE);
LOGMSG("start player loop");
g_main_loop_run (loop);
Can anyone give me some information about these?
Best regards,
forest
Try to use XEmbed

Chrome Bookmarks API -

I'm attempting to create a simple example that would just alert the first 5 bookmark titles.
I took Google's example code and stripped out the search query to see if I could create a basic way to cycle through all Nodes. The following test code fails my alert test and I do not know why.
function dumpBookmarks() {
var bookmarkTreeNodes = chrome.bookmarks.getTree(
function(bookmarkTreeNodes) {
(dumpTreeNodes(bookmarkTreeNodes));
});
}
function dumpTreeNodes(bookmarkNodes) {
var i;
for (i = 0; i < 5; i++) {
(dumpNode(bookmarkNodes[i]));
}
}
function dumpNode(bookmarkNode) {
alert(bookmarkNode.title);
};
Just dump your bookmarkTreeNodes into the console and you will see right away what is the problem:
var bookmarkTreeNodes = chrome.bookmarks.getTree(
function(bookmarkTreeNodes) {
console.log(bookmarkTreeNodes);
});
}
(to access the console go to chrome://extensions/ and click on background.html link)
As you would see a returned tree contains one root element with empty title. You would need to traverse its children to get to the actual bookmarks.
Simple bookmark traversal (just goes through all nodes):
function traverseBookmarks(bookmarkTreeNodes) {
for(var i=0;i<bookmarkTreeNodes.length;i++) {
console.log(bookmarkTreeNodes[i].title, bookmarkTreeNodes[i].url ? bookmarkTreeNodes[i].url : "[Folder]");
if(bookmarkTreeNodes[i].children) {
traverseBookmarks(bookmarkTreeNodes[i].children);
}
}
}

Resources