I'm creating a project with C++Builder XE7, in which a user can click on a button to open a web link, e.g. to open a support page, or to share his experience on a social media. For that, I use the ShellExecute() function, and it works well, except for one button.
When I click on this button, simply nothing happens. The ShellExecute() function returns without error (the returned value is 42), but my default browser does not open, and the web page isn't shown at all.
Here is my ShellExecute() implementation
const HINSTANCE result = ::ShellExecute(handle, "open", url.c_str(), NULL, NULL, SW_SHOWDEFAULT);
I also tried the ShellExecuteEx() function:
::SHELLEXECUTEINFO info;
std::memset(&info, 0, sizeof(info));
info.cbSize = sizeof(info);
info.hwnd = handle;
info.lpVerb = "open";
info.lpFile = url.c_str();
info.nShow = SW_SHOWDEFAULT;
if (!::ShellExecuteEx(&info))
The url parameter contains the website link I am trying to open. For security reasons, I cannot post it here as a sample, however I tested it in my browser (FireFox) and it works well. On the other hand, if I execute my code by just replacing the url content with Google's website, all works as expected.
The handle is just the Handle parameter of the parent frame.
I also tried to tweak the ShellExecute/Ex() parameters, like the hwnd and nShow fields, but no change.
Can anybody point me to what is wrong?
The url is formatted like this: http:// www.
mysite.xxx/selectPage.php?arg1=xxx&arg2=yyy&...&argX=a text containing
"quotes" and some %26amp%3b special chars!
In this example you have to URL-encode the double quotes and the spaces because these are not valid characters for the query part of an URL.
Fix it by replacing double quotes with %22 and spaces with %20. I suggest to use a function like UrlEscape() to properly encode the URL.
Although most browsers have an error tolerance for user input and will also accept an URL which does not have valid encoding, it's better to strictly follow the spec because you are not guaranteed that tolerance.
In addition, the double quotes will make problems when the URL is passed as a command-line argument to the command associated with the URL protocol. This is because double quotes are reserved characters for defining command-line parameters that contain spaces.
For instance, on my machine the http protocol is associated with the following command (see HKEY_CLASSES_ROOT\http\shell\open\command):
"C:\Program Files (x86)\Mozilla Firefox\firefox.exe" -osint -url "%1"
You can see that the double quotes are already used to enclose the last parameter, which obviously gets messed up if you have unencoded double quotes within the URL.
Example for correctly encoding an URL for use with ShellExecuteEx():
#include <windows.h>
#include <Shellapi.h>
int main()
{
::CoInitialize(nullptr);
SHELLEXECUTEINFOW info{ sizeof(info) };
info.fMask = SEE_MASK_NOASYNC; // because we exit process after ShellExecuteEx()
info.lpVerb = L"open";
info.lpFile = L"http://www.google.de/search?q=ShellExecuteEx%20URL%20%22double%20quotes%22";
info.nShow = SW_SHOWDEFAULT;
if( !::ShellExecuteExW( &info ) )
{
DWORD err = ::GetLastError();
printf("ShellExecuteEx failed with error %d\n", err );
}
::CoUninitialize();
}
Related
When doing
const std::string LaunchStr = "C:\\\"Program Files (x86)\"\\Microsoft\\Edge\\Application\\msedge.exe --profile-directory=\"Profile 1\" C:\\Users\\redacted1\\redacted4.html";
System(LaunchStr.c_str());
Microsoft Edge launches as expected, the loaded profile is the correct one and there is a new tab on redacted4.html. However, the first tab (and the focused one too) is the following url program%20--fast-start%20files%20%28x86%29/Microsoft/Edge/Application/msedge.exe. Which I find weird because nowhere in my code do I write program%20--fast-start%20files%20%28x86%29/.
Why is that? How can I prevent it?
I suggest you try to refer to the sample code below that may help you to launch the MS Edge browser correctly with the correct profile and with the specified URL.
#include <windows.h>
int main()
{
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
SHELLEXECUTEINFOW sei = { sizeof sei };
sei.lpVerb = L"open";
sei.lpFile = L"C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe";
sei.lpParameters = L"--user-data-dir=\"C:\\Users\\<user>\\AppData\\Local\\Microsoft\\Edge\\User Data\\Profile 1\" C:\\Users\\redacted1\\redacted4.html"; // Modify the path for user-profile here...
ShellExecuteExW(&sei);
}
Note: You can type edge://version/ in the address bar of the Edge browser and see the profile path to modify it in the above code sample.
Output:
I use MSHTML (IHTMLDocument) to display offline HTML which may contain various links. These are loaded from email HTML.
Some of them have URLs starting with // or / for example:
<img src="//www.example.com/image.jpg">
<img src="/www.example.com/image.jpg">
This takes a lot of time to resolve and show the document because it cannot find the URL obviously as it doesn't start with http:// or https://
I tried injecting <base> tag into <head> and adding a local known folder (which is empty) and that stopped this problem. For example:
<base href="C:\myemptypath\">
However, if links begin with \\ (UNC path) the same problem and long loading time begin again. Like:
<img src="\\www.something.com\image.jpg">
I also tried placing WebBrowser control into "offline" mode and all other tricks I could think of and couldn't come up with anything short of RegEx and replacing all the links in the HTML which would be terribly slow solution (or parsing HTML myself which defeats the purpose of MSHTML).
Is there a way to:
Detect these invalid URLs before the document is loaded? - Note: I already did navigate through DOM e.g. WebBrowser1.Document.body.all collection, to get all possible links from all tags and modify them and that works, but it only happens after the document is already loaded so the long waiting time before loading gives up is still happening
Maybe trigger some event to avoid loading these invalid links and simply replace them with about:blank or empty "" text like some sort of "OnURLPreview" event which I could inspect and reject loading of URLs that are invalid? There is only OnDownloadBegin event which is not it.
Any examples in any language are welcome although I use Delphi and C++ (C++ Builder) as I only need the principle here in what direction to look at.
After a long time this is the solution I used:
Created an instance of CLSID_HTMLDocument to parse HTML:
DelphiInterface<IHTMLDocument2> diDoc;
OleCheck(CoCreateInstance(CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&diDoc)));
Write IHTMLDocument2 to diDoc using Document->write
// Creates a new one-dimensional array
WideString HTML = "Example HTML here...";
SAFEARRAY *psaStrings = SafeArrayCreateVector(VT_VARIANT,0,1);
if (psaStrings)
{
VARIANT *param;
BSTR bstr = SysAllocString(HTML.c_bstr());
SafeArrayAccessData(psaStrings, (LPVOID*)¶m);
param->vt = VT_BSTR;
param->bstrVal = bstr;
SafeArrayUnaccessData(psaStrings);
diDoc->write(psaStrings);
diDoc->close();
// SafeArrayDestroy calls SysFreeString for each BSTR
//SysFreeString(bstr); // SafeArrayDestroy should be enough
SafeArrayDestroy(psaStrings);
return S_OK;
}
Parse unwanted links in diDoc
DelphiInterface<IHTMLElementCollection> diCol;
if (SUCCEEDED(diDoc->get_all(&diCol)) && diCol)
{
// Parse IHTMLElementCollection here...
}
Extract parsed HTML into WideString and write into TWebBrowser
DelphiInterface<IHTMLElement> diBODY;
OleCheck(diDoc->get_body(&diBODY));
if (diBODY)
{
DelphiInterface<IHTMLElement> diHTML;
OleCheck(diBODY->get_parentElement(&diHTML));
if (diHTML)
{
WideString wsHTML;
OleCheck(diHTML->get_outerHTML(&wsHTML));
// And finally use the `Document->write` like above to write into your final TWebBrowser document here...
}
}
I'm trying to install a kernel driver from an MFC application using CreateService function and I'm not sure that I fully understand how lpBinaryPathName parameter is supposed to be set up.
Quoting MSDN:
The fully qualified path to the service binary file. If the path
contains a space, it must be quoted so that it is correctly
interpreted. For example, "d:\my share\myservice.exe" should be
specified as "\"d:\my share\myservice.exe\"".
The path can also include arguments for an auto-start service. For
example, "d:\myshare\myservice.exe arg1 arg2". These arguments are
passed to the service entry point (typically the main function).
So I do this:
LPCTSTR pStrDriverFilePath; //Driver full path
LPCTSTR pStrDriverFileParams; //Parameters
hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
CString strDrvPath;
strDrvPath.Format(L"\"%s\"", pStrDriverFilePath);
if(pStrDriverFileParams &&
pStrDriverFileParams[0])
{
strDrvPath.AppendFormat(L" %s", pStrDriverFileParams);
}
CreateService(hSCManager, pStrDriverName, pStrDriverDispName,
SERVICE_START | DELETE | SERVICE_STOP | SERVICE_QUERY_STATUS,
dwDriverType, dwStartType, dwErrorCtrl,
strDrvPath,
NULL, NULL, NULL,
NULL, NULL);
But then when I try to start it:
StartService(hScDrvHandle, 0, NULL);
it fails with the error code 123, or ERROR_INVALID_NAME:
The filename, directory name, or volume label syntax is incorrect.
Edit: This is how it ends up looking in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\ key:
It only works if I remove double quotes (but only w/o a parameter.)
First, here is a picture of what I see
http://img713.imageshack.us/img713/4797/iedrop.png
I need an solution to clear addressbar dropdawn, but not using ClearMyTracksByProcess or IE dialogs. I need to delete only a specific URL and all his traces.
I deleted manually all traces of that URL in:
Users\\AppData\Local\Microsoft\Windows\Temporary Internet Files*
Users\\AppData\Local\Microsoft\Windows\History*
Users\\Recent*
also that URL can be found in:
4) Users\\AppData\Local\Microsoft\Internet Explorer\Recovery\High
Now I made an BootTime program that searches for 8 and 16 bit charsets string in all my system disc files. URL wasn't found anywhere, but after logging and starting IE, the URL is still there. I suspect this is related to 4), but can't understand how.
Finally I found solution.
HRESULT CreateCatalogManager(ISearchCatalogManager **ppSearchCatalogManager)
{
*ppSearchCatalogManager = NULL;
ISearchManager *pSearchManager;
HRESULT hr = CoCreateInstance(CLSID_CSearchManager, NULL, CLSCTX_SERVER, IID_PPV_ARGS(&pSearchManager));
if (SUCCEEDED(hr))
{
hr = pSearchManager->GetCatalog(L"SystemIndex", ppSearchCatalogManager);
pSearchManager->Release();
}
return hr;
}
{
ISearchCatalogManager *pCatalogManager;
HRESULT hr = CreateCatalogManager(&pCatalogManager);
if (SUCCEEDED(hr))
{
pCatalogManager->Reset();
pCatalogManager->Release();
}
}
Address bar urls are stored in the TypedUrls registry key. See this project which claims to enum and delete them (I haven't tested it).
The History items in the dropdown are stored in the Url History database. Use IUrlHistoryStg::DeleteUrl().
I'm trying to open the MessageStore of a user using MAPI. The weird thing is, when I run this a console application, while I'm logged with the user, everything works fine.
But when I run this as a Windows Service I get MAPI_E_NOT_FOUND when trying to open the MessageStore.
I already configured the service to run as the user.
MapiLogonEx seems to work fine and GetMsgStoreTables also gives me the correct results (I verfied that the EntryID of the MessageStore is correct).
Here's my code:
LPMAPITABLE pStoresTbl = NULL;
m_lpMAPISession->GetMsgStoresTable(0, &pStoresTbl);
// Query Collumns
LPSPropTagArray pTags = NULL;
LPSRowSet pRows = NULL;
pStoresTbl->SeekRow(BOOKMARK_BEGINNING,0,NULL);
pStoresTbl->QueryRows(
LONG_MAX,
NULL,
&pRows);
LPSBinary lpEntryID = NULL;
ULONG iprops;
for (iprops = 0; iprops < pRows->aRow[0].cValues; iprops++)
{
SPropValue sProp = pRows->aRow[0].lpProps[iprops];
if (PROP_ID(sProp.ulPropTag) == PROP_ID(PR_ENTRYID))
{
lpEntryID = &sProp.Value.bin;
break;
}
}
lpMDB = NULL;
HRESULT hres = m_lpMAPISession->OpenMsgStore(NULL,
lpEntryID->cb,
(LPENTRYID) lpEntryID->lpb,
NULL,
MDB_NO_DIALOG |
MDB_NO_MAIL | // spooler not notified of our presence
MDB_TEMPORARY | // message store not added to MAPI profile
MAPI_BEST_ACCESS,
&lpMDB);
Is that an Exchange profile? Are you sure you are opening the primary mailbox rather than the PF store?
Dmitry Streblechenko (MVP)
http://www.dimastr.com/
OutlookSpy - Outlook, CDO
and MAPI Developer Tool
Do you pass in the MAPI_NT_SERVICE flag in the MAPIINIT_0 structure when calling MAPIInitialize? I've never not passed it in when running in a service, so I'm not exactly sure what happens if you don't. The MSDN docs say it is required.
MAPI_NT_SERVICE
The caller is
running as a Windows service. Callers
that are not running as a Windows
service should not set this flag;
callers that are running as a service
must set this flag.