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:
Related
I am loading an local disk drive _test.htm file through IPersistMoniker Load method. From what I believe, it is supposed to add the path to the relative URLs as base path. Problem is - it does not do so. Instead, it takes a very long time trying to resolve the path from Internet until it gives up (about 20-30 seconds). What I want is to give up instantly, as soon as the unsolvable path is detected (since it is a local disk file anyway).
This is an example HTML I am loading:
<html>
<head>
<script src="//test/test.js"></script>
<head>
<body>
<img src="image.jpg">
<img src="/image.jpg">
<img src="//image.jpg">
</body>
</html>
Simplified code (C++ Builder) with no error checking:
WideString URL = "file:///" + StringReplace(ExtractFilePath(Application->ExeName), "\\", "/", TReplaceFlags() << rfReplaceAll) + "_test.htm";
TCppWebBrowser* WB = CppWebBrowser1;
DelphiInterface<IMoniker> pMoniker;
OleCheck(CreateURLMonikerEx(NULL, URL.c_bstr(), &pMoniker, URL_MK_UNIFORM));
DelphiInterface<IHTMLDocument2> diDoc2 = WB->Document;
DelphiInterface<IPersistMoniker> pPrstMnkr;
OleCheck(diDoc2->QueryInterface(IID_IPersistMoniker, (LPVOID*)&pPrstMnkr));
DelphiInterface<IBindCtx> pBCtx;
OleCheck(CreateBindCtx(0, &pBCtx));
pPrstMnkr->Load(0, pMoniker, pBCtx, STGM_READWRITE);
Problem - image.jpg loads fine, but the paths //test/test.js and /image.jpg and //image.jpg take a very long time to resolve/load. From what I understand CreateURLMonikerEx is supposed to use file:///path/to/executable/ and prepend that automatically to these paths in which case they would fail instantly - file:///path/to/executable//test/test.js for example. That does not happen.
I additionally tried to move image.jpg to a subfolder and then create custom IMoniker interface with the GetDisplayName and BindToStorage implementation which loaded the image from a custom path. However it doesn't do the same for paths which start with // or /. Even though I output file:///path/to/executable/ in the GetDisplayName through the *ppszDisplayName parameter.
How can I avoid extended time loading such unusable links (discard them), or redirect them to local path as above?
I found a partial solution to use about:blank in the *ppszDisplayName but then it doesn't load images with the valid path image.jpg as then it loads them as about:image.jpg which again is invalid path.
Additionally - I've tried adding IDocHostUIHandler interface with the implementation of Invoke method (DISPID_AMBIENT_DLCONTROL) with the pVarResult->lVal = DLCTL_NO_SCRIPTS | DLCTL_NO_JAVA | DLCTL_NO_RUNACTIVEXCTLS | DLCTL_NO_DLACTIVEXCTLS | DLCTL_NO_FRAMEDOWNLOAD | DLCTL_FORCEOFFLINE; - it it blocks the download of images entirely, but still does check 20-30 seconds for the links starting with // or /.
Update - this doesn't work well!
The code below doesn't work well! The problem is - it loses <BODY>
tag attributes. BODY tag turns out entirely empty after loading. I
ended up loading the message using IHTMLDocument2.write method.
See: Assigning IHTMLDocument2 instance to a TWebBrowser instance
After spending lots of time and no guidance of any kind here, I believe that it is not possible to avoid this wait 20-30 sec when the links are invalid. I found another solution and if someone wants to supplement this solution, feel free to do so.
Instead what I had to do is to create an instance of CLSID_HTMLDocument (IHTMLDocument3 or IHTMLDocument2 interface) and then load the document into that container and parse the links prior to doing anything with them. This is described on:
https://learn.microsoft.com/en-us/previous-versions/aa703592(v=vs.85)
This also helped:
How to load html contents from stream and then how to create style sheet to display the html file in preview pane (like HTML preview handler)
After parsing the document URLs and fixing the invalid ones, it can be saved/displayed in the actual TWebBrowser.
Rough solution (C++ Builder):
try
{
DelphiInterface<IHTMLDocument2> diDoc2;
OleCheck(CoCreateInstance(CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER, IID_IHTMLDocument2, (void**)&diDoc2));
DelphiInterface<IPersistStreamInit> diPersist;
OleCheck(diDoc2->QueryInterface(IID_IPersistStreamInit, (void**)&diPersist));
OleCheck(diPersist->InitNew());
DelphiInterface<IMarkupServices> diMS;
OleCheck(diDoc2->QueryInterface(IID_IMarkupServices, (void**)&diMS));
DelphiInterface<IMarkupPointer> diMkStart;
DelphiInterface<IMarkupPointer> diMkFinish;
OleCheck(diMS->CreateMarkupPointer(&diMkStart));
OleCheck(diMS->CreateMarkupPointer(&diMkFinish));
// ...Load from file or memory stream into your WideString here...
DelphiInterface<IMarkupContainer> diMC;
OleCheck(diMS->ParseString(WideString(MsgHTMLSrc).c_bstr(), 0, &diMC, diMkStart, diMkFinish));
DelphiInterface<IHTMLDocument2> diDoc;
OleCheck(diMC->QueryInterface(IID_PPV_ARGS(&diDoc)));
DelphiInterface<IHTMLElementCollection> diCol;
OleCheck(diDoc->get_all(&diCol));
long ColLen = 0;
OleCheck(diCol->get_length(&ColLen));
for (int i = 0; i < ColLen; ++i)
{
DelphiInterface<IDispatch> diItem;
diCol->item(OleVariant(i), OleVariant(i), &diItem);
DelphiInterface<IHTMLElement> diElem;
OleCheck(diItem->QueryInterface(IID_IHTMLElement, (void**)&diElem));
WideString wTagName;
OleCheck(diElem->get_tagName(&wTagName));
if (StartsText("img", wTagName))
{
OleVariant vSrc;
OleCheck(diElem->getAttribute(OleVariant("src"), 4, vSrc));
// Make changes to vSrc here....
// And save it back to src
OleCheck(diElem->setAttribute(OleVariant("src"), vSrc, 0));
}
else if (StartsText("script", wTagName))
{
// More parsing here...
}
}
}
catch (EOleSysError& e)
{
// Process exception as needed
}
catch (Exception& e)
{
// Process exception as needed
}
After full parsing of all required elements (img/src, script/src, base/href etc.) save and load into TWebBrowser.
I only now have to see if the parsed HTML IHTMLDocument2 can be directly assigned to TWebBrowser without loading it again, but that is another question (See - Assigning IHTMLDocument2 instance to a TWebBrowser instance)
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();
}
I am trying to redirect file creation on a volume of hard disk (i.e \Device\HarddiskVolume2)
I found redirecting file name in minifilter open pre. But I got a system dialog as below
Here is my code:
// I tested with pFileName = &Data->Iopb->TargetFileObject->FileName;
// It has same result
pFileName = &FltObjects->FileObject->FileName;
if (pFileName->Buffer != NULL)
ExFreePool(pFileName->Buffer);
// gRedirectFullFilePath is \\Device\\HarddiskVolume2\\File.ext
pFileName->Length = gRedirectFullFilePath.Length;
pFileName->MaximumLength = pFileName->Length;
pFileName->Buffer = (PWCH) ExAllocatePool(NonPagedPool, pFileName->MaximumLength);
if (pFileName->Buffer == NULL)
goto PreOperationCleanup;
RtlCopyUnicodeString(pFileName, &gRedirectFullFilePath);
// Change I/O status
Data->IoStatus.Information = IO_REPARSE;
Data->IoStatus.Status = STATUS_REPARSE;
Data->Iopb->TargetFileObject->RelatedFileObject = NULL;
FltSetCallbackDataDirty(Data);
return FLT_PREOP_COMPLETE;
I want this dialog to be not show. How should I do?
Thanks very much!
You should check SimRep File System Minifilter Driver example from WDK8.1 samples.
For example it ignores volume opens (FO_VOLUME_OPEN) and directory opens (SL_OPEN_TARGET_DIRECTORY). Maybe that is causing troubles to you.
It also uses IoReplaceFileObjectName to replace name of a file object (should be safer than direct changing of FILE_OBJECT).
I'm trying to control Word through a c++ builder 5 application. I would like to
open a ".dot" model file created with Word and modify it. In the ".dot" model file
there are some fields. For example, Title, LastName, FirstName, Address
and so on, and I would like to modify these fields putting text into them and then
saving file with a new name, for example "Warning.doc" leaving the ".dot" file
unaltered.
I can open the file, count the number of fields it contains, but then
when it comes to replacing each field with a string I don't know how to do because
I don't have a complete documentation on OleFunction and OlePropertyGet methods. I attach my source code to this message, can anybody help me to solve this problem please?
try
{
my_word = Variant::CreateObject("word.application");
}
catch (...)
{
Application->MessageBox("Unable to obtain Word automation object",
"Error:",MB_OK | MB_ICONERROR);
}
my_word.OlePropertySet("Visible", (Variant)true);
void __fastcall TForm1::Button2Click(TObject *Sender)
{
Variant this_doc;
Variant my_fields;
Variant test;
int k,field_count;
AnsiString test1;
AnsiString filename = "d:\\ProgrammaWord\\1-Avviso.dot";
my_docs = my_word.OlePropertyGet("Documents");
this_doc = my_docs.OleFunction("Open", filename);
my_fields = this_doc.OlePropertyGet("Fields");
field_count = my_fields.OlePropertyGet("Count");
for(k = 1; k <= field_count; k++)
{
test = my_fields.OleFunction("Item",(Variant)k);
test1 = test.OleFunction("Value"); //This instruction throws an exception
// "Value" is not a recognized parameter
// in this case
Memo1->Lines->Add(test1);
}
}
I never used word Ole but I used it for Outlook and Excel, I can't try it with word since I'm currently on OSX but you should try something similar as what I did.
The generic way of using Ole was to OleGetproperty() while you get the targeted field then OleSetProperty("action", ...).
for example when I wanted to change the color of the text in a particular cell of my excel document I used:
Variant _excel = Variant::CreateObject("Excel.Application");
Variant _workbook = _excel.OlePropertyGet("WorkBooks").OleFunction("Open", filename);
Variant _worksheet = _workbook.OlePropertyGet("WorkSheets", sheet);
_worksheet.OlePropertyGet("Cells", row, col).OlePropertyGet("Font").OlePropertySet("Color", color);
Here I instanciate an excel object, then I load a file into it (_workbook), then I select the _worksheet from the _workbook and I start my business.
Here comes the interesting part:
It concist of getting to a particular cell, getting the font object from it, and then setting the color of this font object.
Disclaimer: This is an example from my sources for excel, it's not directly related to your example, but maybe you can understand the principe with it. I can't try to figure out what you need because I have no windows right now.
Hope this can help you. Finding ressources for OLE can be fierce if you don't have the good patterns to look for.
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.