I'm trying to get the flash object with ShockwaveFlashObjects component. I get the browser object successfully, but I'm wondering how to get the Flash object through the browser object in IWebBrowser2 type. The code below shows the interface I defined. Has anyone some ideas for me? Thanks.
interface IGetObjects
{
SHDocVw.IWebBrowser2 GetBrowserObject();
ShockwaveFlashObjects.ShockwaveFlashClass GetFlashObject(IWebBrowser2 browserObject);
}
And this is the way, I get the browser object. #caution# Flash is used for test, so it is located in local.
public IWebBrowser2 GetBrowserObject()
{
InternetExplorerClass browser = null;
var shellWindows = new ShellWindowsClass();
const string explorFullName = "C:\\Program Files (x86)\\Internet Explorer\\IEXPLORE.EXE";
IWebBrowser2 iwb2 = null;
for (int i = 0; i < shellWindows.Count; i++)
{
iwb2 = shellWindows.Item(i) as IWebBrowser2;
if (iwb2 != null && Equals(iwb2.FullName , explorFullName))
{
break;
}
}
return iwb2;
}
And now I have no idea how to completed the second method ShockwaveFlashClass GetFlashObject(IWebBrowser2 browserObject).
Related
I'm working on an application that downloads images from the internet in Selenium. However, I get the same error in the code seen in the picture and I cannot continue the process. This code, you can see the error in the image below.
IWebDriver driver;
int PictureID = 0;
private void button1_Click(object sender, EventArgs e)
{
var ChromeService = ChromeDriverService.CreateDefaultService();
driver = new ChromeDriver(ChromeService);
driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(30);
driver.Navigate().GoToUrl("https://oblivious212.artstation.com/");
var Projects = driver.FindElements(By.ClassName("album-grid-item"));
for(int i = 0; i < Projects.Count(); i++)
{
if (Projects.ElementAt(i) == null)
{
continue;
}
Projects[i].Click();
var Images = driver.FindElements(By.TagName("img"));
for(int x = 0; x < Images.Count(); x++)
{
PictureID++;
WebClient Downloader = new WebClient();
var ImageUrl = Images[x].GetAttribute("src");
var ImageName = Images[x].GetAttribute("alt");
Downloader.DownloadFile(ImageUrl, "C:\\Users\\DeLL\\Pictures\\Images\\" + ImageName + PictureID + ".jpg");
}
driver.Navigate().Back();
}
Screenshot of exception when running in debug mode:
How do I solve this?
As soon as you navigate to a new page, which I guess is what your Projects[i].Click(); call does, any IWebElement objects you saved from an earlier page (oblivious212.artstation.com/) become "stale" and you can no longer use them. You must design your code around this fact; there are several ways you might do this.
Basically, while you're still on page oblivious212.artstation.com/, you need to save off any data you need from the IWebElement objects returned by your driver.FindElements(By.ClassName("album-grid-item")) call, into a local object, rather than saving the IWebElement objects themselves. Then, replace your Projects[i].Click(); call with code which uses your saved local data, rather than using the IWebElement objects themselves.
I'm writing a utility that allows end users to perform some Selenium tests against my company's web app, so far so good. Here's the issue: I want to allow users to choose the type of selenum.webdriver object they are going to implement, based on whether they have chrome or firefox installed on their system.
so, I initialize a list of objects to let us know what the user has selected
public List<object> BuildBrowserAccess(string browserEngine)
{
OpenQA.Selenium.Chrome.ChromeDriver driverC = null;
OpenQA.Selenium.Firefox.FirefoxDriver driverF = null;
if (browserEngine == "Firefox")
{
driverF = new OpenQA.Selenium.Firefox.FirefoxDriver();
}
else if (browserEngine == "Chrome\t")
{
driverC = new OpenQA.Selenium.Chrome.ChromeDriver();
}
List<object> browserEngines = new List<object>();
browserEngines.Add(driverC);
browserEngines.Add(driverF);
return browserEngines;
}
Then back in the main routine, assign whichever is selected (i.e. not null) to a dynamic object then convert the object to static using "as":
List<object> browserEngines = mainActions.BuildBrowserAccess(browserEngine);
if (browserEngines[0] != null )
{
driver = browserEngines[0];
finDriver = driver as OpenQA.Selenium.Chrome.ChromeDriver;
}
else
{
driver = browserEngines[1];
finDriver = driver as OpenQA.Selenium.Firefox.FirefoxDriver;
}
Even at runtime, the conversion looks successful, and I'm able to use some methods of the FirefoxDriver namespace, but many other methods that work just fine with a statically typed object throw a RuntimeBinderException... I'm just about stumped, and any help is appreciated!
Why not create only one driver variable of type IWebDriver of it doesn't have to be specifically initialized, use var?
And in case you need to check the specific type of driver you could do
if(driver.GetType() == typeof(FirefoxDriver))
{
//do your Firefox stuff
}
else
{
//do another browser stuff
}
I have a code which gives back the UITechnologyElement by Name.
My purpose is to be able to call the "Mouse.Click()" method on this element, but for this I have to convert it to UITestControl, or get it from it, i don't know.
I haven't found any explanation about UITechnologyElement, or any correspondence between them.
So my question is, how I could click on this Element or maybe convert it to UITestControl for the same purpose?
private static UITechnologyElement IterateOnControl(UITechnologyElement parent, string name)
{
UITechnologyElement te = null;
UITechnologyManager TM = Playback.GetCoreTechnologyManager("MSAA");
IEnumerator windowEnumerator = TM.GetChildren(parent, null);
windowEnumerator.Reset();
while (windowEnumerator.MoveNext())
{
UITechnologyElement current = windowEnumerator.Current as UITechnologyElement;
if (current.Name == name)
{
te = current;
break;
}
}
return te;
}
As I have tested it, I found the answer...
//When you have the UITechnologyElement, you can create a WinControl from it by using this methode
WinControl result = (WinControl)UITestControlFactory.FromNativeElement(control.NativeElement, "MSAA");
//Now you have the WinControl so you can convert it into a special Type, eg. WinButton
WinButton wb = (WinButton)result;
//And invoke the Mouse.Click methode
Mouse.Click(wb, MouseButtons.Left);
That's all what I was needed. :)
I'm using the WebBrowser class to open document, change values, save and print. The problem is, that it prints the document including the header("Page 1 of 1") and footer(root of the document + date)
I looked at the documentation and didn't find a way to remove them. Is it even possible using WebBrowser or should I look for alternatives?
There is a solution, probably not as cleaner as it could have been. Since WebBrowser inhertis it's settings from Internet Explorer it is possible to change the values in the registry. Luckily the values are under HKCU so no administration permissions are needed.
Take a look at https://stackoverflow.com/a/1321314/1630928
The trick to doing this is to pass a Variant containing a ByRef SafeArray of Variants to the WebBrowser control. I haven't figured out how to do it from C#. Here's someone else who was working on the same problem who resorted to using managed C++
http://www.limilabs.com/blog/printing-in-webbrowser-control-custom-header-and-footer
Not a C#, but here's C++ code that I came up with based on a now defunct KB267240. It will remove the header and the footer while printing:
BOOL bRes = FALSE;
//Get IWebBrowser2 from your IE control
CComPtr<IWebBrowser2> pWebBrowser = this->GetIWebBrowser2();
if(pWebBrowser)
{
HRESULT hr;
COleVariant varNull;
SAFEARRAYBOUND psabBounds[1];
SAFEARRAY *psaHeadFoot;
hr = S_OK;
VARIANT vArg;
BOOL bGot_vArg = FALSE;
VARIANT vHeadStr, vFootStr;
long rgIndices;
VariantInit(&vHeadStr);
VariantInit(&vFootStr);
// Initialize header and footer parameters to send to ExecWB().
psabBounds[0].lLbound = 0;
psabBounds[0].cElements = 3;
psaHeadFoot = SafeArrayCreate(VT_VARIANT, 1, psabBounds);
if(psaHeadFoot)
{
// Argument 1: Header
vHeadStr.vt = VT_BSTR;
vHeadStr.bstrVal = SysAllocString(L" "); //Must be at least one space
if (vHeadStr.bstrVal)
{
// Argument 2: Footer
vFootStr.vt = VT_BSTR;
vFootStr.bstrVal = SysAllocString(L" "); //Must be at least one space
if(vFootStr.bstrVal)
{
rgIndices = 0;
SafeArrayPutElement(psaHeadFoot, &rgIndices, static_cast<void *>(&vHeadStr));
rgIndices = 1;
SafeArrayPutElement(psaHeadFoot, &rgIndices, static_cast<void *>(&vFootStr));
rgIndices = 2;
SafeArrayPutElement(psaHeadFoot, &rgIndices, static_cast<void *>(&varNull)); //Set stream to NULL as we don't need it
//NOTE: Currently, the SAFEARRAY variant must be passed by using
// the VT_BYREF vartype when you call the ExecWeb method.
VariantInit(&vArg);
vArg.vt = VT_ARRAY | VT_BYREF;
vArg.parray = psaHeadFoot;
//Got it
bGot_vArg = TRUE;
}
}
}
//Did we get all the vars?
if(bGot_vArg)
{
if(SUCCEEDED(hr = pWebBrowser->ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_PROMPTUSER, &vArg, NULL)))
{
//All good
bRes = TRUE;
}
}
else
{
//Use fallback (that will keep the footer & header)
if(SUCCEEDED(hr = pWebBrowser->ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_PROMPTUSER, varNull, varNull)))
{
//Printed via fallback
bRes = TRUE;
}
}
//Clean up
VariantClear(&vHeadStr);
VariantClear(&vFootStr);
if(psaHeadFoot)
{
SafeArrayDestroy(psaHeadFoot);
psaHeadFoot = NULL;
}
}
I created a program a while ago using C# that does some automation for a completely different program, but found that I need to access data from a Lotus Notes database. The only problem is, I can only seem to figure out how to open the database by the server's name (using session.GetDatabase())... I can't figure out how to open it by Replica ID. Does anyone know how I would go about that? (I don't want my program going down every time the server changes.)
public static string[] GetLotusNotesHelpTickets()
{
NotesSession session = new NotesSession();
session.Initialize(Password);
// 85256B45:000EE057 = NTNOTES1A Server Replica ID
NotesDatabase database = session.GetDatabase("NTNOTES1A", "is/gs/gshd.nsf", false);
string SearchFormula = string.Concat("Form = \"Call Ticket\""
, " & GroupAssignedTo = \"Business Systems\""
, " & CallStatus = \"Open\"");
NotesDocumentCollection collection = database.Search(SearchFormula, null, 0);
NotesDocument document = collection.GetFirstDocument();
string[] ticketList = new string[collection.Count];
for (int i = 0; i < collection.Count; ++i)
{
ticketList[i] = ((object[])(document.GetItemValue("TicketNumber")))[0].ToString();
document = collection.GetNextDocument(document);
}
document = null;
collection = null;
database = null;
session = null;
return ticketList;
}
This code is working fine, but if the server changed from NTNOTES1A, then nothing is going to work anymore.
you'll need to use the notesDbDirectory.OpenDatabaseByReplicaID(rid$) method. To get the NotesDbDirectory, you can use the getDbDirectory method of the session
Set notesDbDirectory = notesSession.GetDbDirectory( serverName$ )
So you can use the code below to get a database by replicaID.
public static string[] GetLotusNotesHelpTickets()
{
NotesSession session = new NotesSession();
session.Initialize(Password);
Set notesDBDirectory = session.GetDbDirectory("NTNOTES1A")
// 85256B45:000EE057 = NTNOTES1A Server Replica ID
NotesDatabase database = notesDBDirectory.OpenDatabaseByReplicaID("85256B45:000EE057")
string SearchFormula = string.Concat("Form = \"Call Ticket\""
, " & GroupAssignedTo = \"Business Systems\""
, " & CallStatus = \"Open\"");
NotesDocumentCollection collection = database.Search(SearchFormula, null, 0);
NotesDocument document = collection.GetFirstDocument();
string[] ticketList = new string[collection.Count];
for (int i = 0; i < collection.Count; ++i)
{
ticketList[i] = ((object[])(document.GetItemValue("TicketNumber")))[0].ToString();
document = collection.GetNextDocument(document);
}
document = null;
collection = null;
database = null;
session = null;
return ticketList;
}
Unfortunately, this only solves half of your problem. I know you'd rather just tell Notes to fetch the database with a particular replicaID from the server closest to the client, just like the Notes Client does when you click on a DBLink or Bookmark. However, there is (or appears to be) no way to do that using the Notes APIs.
My suggestion is to either loop through a hard-coded list of potential servers by name, and check to see if the database is found (the OpenDatabaseByReplicaID method returns ERR_SYS_FILE_NOT_FOUND (error 0FA3) if the database is not found). If that's not a good option, perhaps you can easily expose the servername in an admin menu of your app so it can be changed easily if the server name changes at some point.
set database = new NotesDatabase("")
call database.OpenByReplicaID("repid")