Using COM component fails as admin - c#

I have a .NET wrapper over a native dll.
I try to register the component only for current user based on this : link
This runs fine, except if I right click the executable and say "Run as admin.." the tool will fail that it cannot find the class.
This is the code I use, is there something I am missing , I think it might be related to :
link
Thanks!
public int Register(ServerAction Action, string ServerName)
{
int hr = 0;
string szFunction = (Action == ServerAction.Register) ? "DllRegisterServer" : "DllUnregisterServer";
logger.Info("FileReader->Try to " + szFunction + " " + ServerName);
try
{
IntPtr hMod = LoadLibrary(ServerName);
if (hMod.ToInt32() != 0)
{
IntPtr registerDllServer_ProcAddress = GetProcAddress(hMod, szFunction);
DllRegisterServerInvoker pfnDllProc = (DllRegisterServerInvoker)Marshal.GetDelegateForFunctionPointer(registerDllServer_ProcAddress, typeof(DllRegisterServerInvoker));
if (pfnDllProc != null)
{
if (isUserAdminAndProcessElevated())
{
logger.Info("User is admin and process is elevated!");
}
else
{
logger.Info("User is not admin!");
hr = OverrideClassesRoot(HKEY_CURRENT_USER, "Software\\Classes");
}
}
hr = pfnDllProc();
pfnDllProc = null;
FreeLibrary(hMod);
}
else
{
hr = this.GetHresultFromWin32();
}
}
catch
{
Console.WriteLine("FileReader->" + szFunction + " " + ServerName + " FAILED!");
}
string errorMessage = new Win32Exception(hr).Message;
logger.Fatal(errorMessage);
return hr;
}
private Int32 OverrideClassesRoot(UIntPtr hKeyBase, string OverrideKey)
{
UIntPtr hkey = new UIntPtr();
int l = RegOpenKeyA(hKeyBase, OverrideKey, ref hkey);
if (l == 0)
{
l = RegOverridePredefKey(HKEY_CLASSES_ROOT, hkey);
RegCloseKey(hkey);
}
return this.GetHresultFromWin32();
}
Still haven't figured this out but I fixed it with : MSDN link

Related

Multithreaded Selenium Bot does not work correctly

I wrote a bot in C#, I used Selenium.
Problem: When I start more threads at same time, the bot does the work in the first window. All of the e-mail addresses are being added to the "E-mail" textbox in the same window instead of one e-mail address per window.
But it should look like:
Start function: DivisionStart()
private void DivisionStart() {
foreach(var account in BotConfig.AccountList) {
while (CurrentBotThreads >= BotConfig.MaxLoginsAtSameTime) {
Thread.Sleep(1000);
}
StartedBotThreads++;
CurrentBotThreads++;
int startIndex = (StartedBotThreads * BotConfig.AdsPerAccount + 1) - BotConfig.AdsPerAccount - 1;
int stopIndex = BotConfig.AdsPerAccount * CurrentBotThreads;
if (stopIndex > BotConfig.ProductList.Count) {
stopIndex = BotConfig.ProductList.Count;
}
Debug.Print("Thread: " + StartedBotThreads);
var adList = GetAdListBy(startIndex, stopIndex);
foreach(var ad in adList) {
Debug.Print("Für thread: " + StartedBotThreads + " | Anzeige: " + ad.AdTitle);
}
Debug.Print("Parallel");
var ebayBotThread = new Thread(() => {
var botOptions = new IBotOptionsModel() {
CaptchaSolverApiKey = CaptchaSolverApiKey,
ReCaptchaSiteKey = "6LcZlE0UAAAAAFQKM6e6WA2XynMyr6WFd5z1l1Nr",
StartPageUrl = "https://www.ebay-kleinanzeigen.de/m-einloggen.html?targetUrl=/",
EbayLoginEmail = account.AccountEmail,
EbayLoginPassword = account.AccountPassword,
Ads = adList,
};
var ebayBot = new EbayBot(this, botOptions);
ebayBot.Start(StartedBotThreads);
Thread.Sleep(5000);
});
ebayBotThread.Start();
}
}
The class with function which will be executed in each thread:
using OpenQA.Selenium;
using Selenium.WebDriver.UndetectedChromeDriver;
using System.Diagnostics;
using TwoCaptcha.Captcha;
using System.Drawing;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Chrome.ChromeDriverExtensions;
namespace EbayBot
{
class EbayBot
{
public Selenium.Extensions.SlDriver Driver;
private WebDriverHelper DriverHelper;
private Bot Sender;
private bool CaptchaSolved = false;
public IBotOptionsModel Options;
public EbayBot(Bot sender, IBotOptionsModel options)
{
Sender = sender;
Options = options;
}
public void Start(int threadIndex)
{
var chromeOptions = new ChromeOptions();
/*if (Sender.BotConfig.EnableProxy)
{
chromeOptions.AddHttpProxy(
Options.Proxy.IpAddress,
Options.Proxy.Port,
Options.Proxy.Username,
Options.Proxy.Password
);
}*/
Driver = UndetectedChromeDriver.Instance(null, chromeOptions);
DriverHelper = new WebDriverHelper(Driver);
string status = "";
Debug.Print("Bot-Thread: " + threadIndex);
Driver.Url = Options.StartPageUrl + Options.EbayLoginEmail;
PressAcceptCookiesButton();
Login();
if (!CaptchaSolved) return;
Driver.Wait(3);
if (LoginError() || !IsLoggedIn())
{
status = "Login für '" + Options.EbayLoginEmail + "' fehlgeschlagen!";
Debug.Print(status);
Sender.ProcessStatus = new IStatusModel(status, Color.Red);
return;
}
else
{
status = "Login für '" + Options.EbayLoginEmail + "' war erfolgreich!";
Debug.Print(status);
Sender.ProcessStatus = new IStatusModel(status, Color.Green);
}
Driver.Wait(5);
BeginFillFormular();
}
private bool CookiesAccepted()
{
try
{
var btnAcceptCookies = Driver.FindElement(By.Id(Config.PageElements["id_banner"]));
return btnAcceptCookies == null;
}
catch (Exception)
{
return true;
}
}
private void PressAcceptCookiesButton()
{
DriverHelper.WaitForElement(Config.PageElements["id_banner"], "", 10);
if (CookiesAccepted()) return;
var btnAcceptCookies = Driver.FindElement(By.Id(Config.PageElements["id_banner"]));
btnAcceptCookies.Click();
}
private bool IsLoggedIn()
{
Debug.Print("Check if logged in already");
try
{
var userEmail = Driver.FindElement(By.Id("user-email")).Text;
return userEmail.ToLower().Contains(Options.EbayLoginEmail);
}
catch (Exception)
{
return false;
}
}
private bool LoginError()
{
try
{
var loginErrorH1 = Driver.FindElements(By.TagName("h1"));
return loginErrorH1[0].Text.Contains("ungültig");
}
catch (Exception)
{
return false;
}
}
private void Login()
{
if (IsLoggedIn()) return;
string status = "Anmelden bei " + Options.EbayLoginEmail + "...";
Debug.Print(status);
Sender.ProcessStatus = Sender.ProcessStatus = new IStatusModel(status, Color.DimGray);
Driver.Wait(5);
var fieldEmail = Driver.FindElement(By.Id(Config.PageElements["id_login_email"]));
var fieldPassword = Driver.FindElement(By.Id(Config.PageElements["id_login_password"]));
var btnLoginSubmit = Driver.FindElement(By.Id(Config.PageElements["id_login_button"]));
fieldEmail.SendKeys(Options.EbayLoginEmail);
Driver.Wait(4);
fieldPassword.SendKeys(Options.EbayLoginPassword);
SolveCaptcha();
if (!CaptchaSolved)
{
return;
}
Debug.Print("Clicking login button");
btnLoginSubmit.Click();
}
public void BeginFillFormular()
{
Debug.Print("Formular setup, Inserate: " + Options.Ads.Count);
foreach (var adData in Options.Ads)
{
Debug.Print("Setting up formular for " + adData.AdTitle);
var adFormular = new AdFormular(Driver, adData, Options);
adFormular._EbayBot = this;
adFormular.CreateAd(Sender);
// 10 seconds
Debug.Print("Nächstes Insert für " + adData.AdTitle);
}
}
public string GetSolvedCaptchaAnswer(string captchaUrl = "")
{
string code = string.Empty;
var solver = new TwoCaptcha.TwoCaptcha(Options.CaptchaSolverApiKey);
var captcha = new ReCaptcha();
captcha.SetSiteKey(Options.ReCaptchaSiteKey);
captcha.SetUrl(captchaUrl == "" ? Options.StartPageUrl : captchaUrl);
try
{
solver.Solve(captcha).Wait();
code = captcha.Code;
}
catch (AggregateException e)
{
Sender.ProcessStatus = new IStatusModel("Captcha Api-Fehler: " + e.InnerExceptions.First().Message, Color.Red);
Driver.Wait(10);
}
return code;
}
public void SolveCaptcha(string captchaUrl = "")
{
Debug.Print("Solving captcha...");
var solvedCaptchaAnswer = GetSolvedCaptchaAnswer(captchaUrl);
if (solvedCaptchaAnswer == string.Empty)
{
Debug.Print("Captcha konnte nicht gelöst werden");
Sender.ProcessStatus = new IStatusModel("Captcha konnte nicht gelöst werden", Color.Red);
CaptchaSolved = false;
Driver.Wait(10);
return;
}
CaptchaSolved = true;
Debug.Print("Captcha answer: " + solvedCaptchaAnswer);
Driver.ExecuteScript("document.getElementById('g-recaptcha-response').innerHTML = '" + solvedCaptchaAnswer + "'");
Debug.Print("Captcha solved!");
Driver.Wait(2);
}
}
}
If I remove the Thread.Sleep(5000); in the DivisionStart function it will work, but I need it I actually want to wait for a found proxy but I simulated it with Thread.Sleep
How can I solve my problem?
Thanks for any answer!
I fixed it.
I used UndetectedChromeDriver wich does not use different ports.
I use another Undetected driver now.
Thank you all

default class for an outlook item(specificaly a calendar)

Hi have been reading about form regions for the last week.I finally managed to create a new interacting form using windows controls (i deprecated forms with vbscript).In the end though i have to associate the new seperate form with a specific calendar from c# code...
but let's get to code...This is how i did it using outlook-vbscript forms.(using ofts):
private bool CreateCustomCalendar(string registryname, string newCalendarName, string outlookformpathandfilename)
{
app = this.Application;
Outlook.MAPIFolder primaryCalendar = (Outlook.MAPIFolder)
this.Application.ActiveExplorer().Session.GetDefaultFolder
(Outlook.OlDefaultFolders.olFolderCalendar);
bool needFolder = true;
if (debugmode) writer.WriteToLog("RootCalendar :" + primaryCalendar.Name + " found");
Outlook.MAPIFolder personalCalendar = primaryCalendar
.Folders.Add(newCalendarName,
Outlook.OlDefaultFolders.olFolderCalendar);
personalCalendar.Name = newCalendarName;
if (debugmode) writer.WriteToLog("Creating Calendar stage1 complete");
//Access new calendar by its name that has the habit to append this computer only
bool notfound1 = true; bool notfound2 = true;
try
{
string mName = primaryCalendar.Folders[newCalendarName].Name;
if (debugmode) writer.WriteToLog("calendar accesible by name:" + mName);
notfound1 = false;
}
catch (SystemException sex)
{
throw;
}
Outlook.MAPIFolder setcalendar = primaryCalendar.Folders[newCalendarName];
if (debugmode) writer.WriteToLog("calendar is set");
PublishFormToPersonalFormsLibrary(setcalendar, outlookformpathandfilename, registryname, registryname, registryname, registryname + "version 1.0.0.1", "1.0.0.1", Application);
if (debugmode) writer.WriteToLog("Creating Calendar stage2 complete");
SetFolderDefaultForm_forappointments(setcalendar, "IPM.Appointment." + registryname, newCalendarName);
if (debugmode) writer.WriteToLog("Creating Calendar stage3 complete");
return needFolder;
}
void SetFolderDefaultForm_forappointments(Outlook.MAPIFolder fld, string msgClass, string displayname)
{
Outlook.PropertyAccessor objPA = fld.PropertyAccessor;
string strBaseType;
string strMsg;
int intLoc;
bool blnBadForm;
int i;
string PR_DEF_POST_MSGCLASS =
"http://schemas.microsoft.com/mapi/proptag/0x36E5001E";
string PR_DEF_POST_DISPLAYNAME =
"http://schemas.microsoft.com/mapi/proptag/0x36E6001E";
string[] arrSchema = { PR_DEF_POST_MSGCLASS, PR_DEF_POST_DISPLAYNAME };
string[] arrValues = { msgClass, displayname };
string[] arrErrors;
if (debugmode) writer.WriteToLog("prepared for setting default item");
try
{
objPA = fld.PropertyAccessor;
objPA.SetProperty(PR_DEF_POST_MSGCLASS, msgClass);
objPA.SetProperty(PR_DEF_POST_DISPLAYNAME, displayname);
if (debugmode) writer.WriteToLog("default folder set");
// arrErrors = objPA.SetProperties(arrSchema, arrValues);
}
catch (SystemException sex)
{
Console.WriteLine("This is catch with system exception : {0}", sex.ToString());
}
}
public void PublishFormToPersonalFormsLibrary(Outlook.MAPIFolder calendarfolder, string oftFilePath, string messageClass, string name, string displayName, string description, string version, Outlook.Application application)
{
object missing = System.Reflection.Missing.Value;
string existingVersion = "";
// try to create an existing Instance of the Form to check the current installed Version
try
{
// create atemplatefolder object
Outlook.MAPIFolder templateFolder = application.Session.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderDrafts);
if (debugmode) writer.WriteToLog("templateFolder is set");
// we add our new object here
object existingItem = templateFolder.Items.Add(messageClass);
if (debugmode) writer.WriteToLog("added form " + messageClass + " as templates");
// did we installed the form
if (existingItem != null)
{
// yes, we did it before
// get the formdescription with latebinding
Type existingItemType = existingItem.GetType();
Outlook.FormDescription existingFormDescription = (Outlook.FormDescription)existingItemType.InvokeMember("FormDescription", System.Reflection.BindingFlags.GetProperty, null, existingItem, null);
if (debugmode) writer.WriteToLog("formdescription allocated to existingformdescription");
// get the installed version
existingVersion = existingFormDescription.Version;
// discard the temporary item
object[] args = { Outlook.OlInspectorClose.olDiscard };
existingItemType.InvokeMember("Close", System.Reflection.BindingFlags.InvokeMethod, null, existingItem, args);
if (debugmode) writer.WriteToLog("GarbageCollection");
}
}
catch (System.Exception ex)
{
}
// if the existing Version is equal, no need for publishing the form
// if (version == existingVersion) return;
// check, if the templatefile exists
if (!System.IO.File.Exists(oftFilePath)) throw new System.IO.FileNotFoundException("Form template could not be found!", oftFilePath);
// create the item from TemplateFile
object item = application.CreateItemFromTemplate(oftFilePath, missing);
if (debugmode) writer.WriteToLog("created item from template");
// get the FormDescription Property using LateBinding
Type itemType = item.GetType();
Outlook.FormDescription formDescription = (Outlook.FormDescription)itemType.InvokeMember("FormDescription", System.Reflection.BindingFlags.GetProperty, null, item, null);
// Apply some Parameters to the Formdescription
formDescription.Name = name;
formDescription.DisplayName = displayName;
formDescription.Category = "uncategorized";
formDescription.Comment = description;
formDescription.Version = version;
if (debugmode) writer.WriteToLog("Set custom form and its properties");
// Publish Form to Personal Froms Library
//formDescription.PublishForm(Microsoft.Office.Interop.Outlook.OlFormRegistry.olPersonalRegistry );
formDescription.PublishForm(Microsoft.Office.Interop.Outlook.OlFormRegistry.olFolderRegistry, calendarfolder);
if (debugmode) writer.WriteToLog("associating complete");
}
the question is how to do it with form-regions(using .ofs)
any solutions\documentation would be welcomed.
Many thnx to the creators of stack-overflow for this great resource and all developers that altruistically contribute to our problems
I finally did it!!! the replacement code for outlook.addin item goes like this:
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
Outlook.Folder taskList =Application.Session.GetDefaultFolder(
Outlook.OlDefaultFolders.olFolderTasks)
as Outlook.Folder;
Outlook.TaskItem taskItem = taskList.Items.Add(
"IPM.Task.twoformMssges") as Outlook.TaskItem;
taskItem.Subject = "IPM.Task.twoformMssges Created On " +
System.DateTime.Now.ToLongDateString();
taskItem.Save();
Outlook.MAPIFolder primarytaskfolder = (Outlook.MAPIFolder)
this.Application.ActiveExplorer().Session.GetDefaultFolder
(Outlook.OlDefaultFolders.olFolderTasks);
Outlook.MAPIFolder settaskfolder = primarytaskfolder.Folders["testassociation"];
Outlook.Application app = this.Application;
string formpropstring= "twotabs";
// PublishFormToPersonalFormsLibrary(taskItem,settaskfolder, "c:\\" , "IPM.Task.twoformMssges",registryname, registryname,registryname + "version 0.0.0.1", "0.0.0.1", Application);
object missing = System.Reflection.Missing.Value;
string existingVersion = "";
try
{
if (taskItem != null)
{
Type existingItemType = taskItem.GetType();
Outlook.FormDescription existingFormDescription = (Outlook.FormDescription)existingItemType.InvokeMember("FormDescription", System.Reflection.BindingFlags.GetProperty, null, taskItem, null);
//if (debugmode) writer.WriteToLog("formdescription allocated to existingformdescription");
// get the installed version
existingVersion = existingFormDescription.Version;
// discard the temporary item
object[] args = { Outlook.OlInspectorClose.olDiscard };
existingItemType.InvokeMember("Close", System.Reflection.BindingFlags.InvokeMethod, null, taskItem, args);
//if (debugmode) writer.WriteToLog("GarbageCollection");
}
}
catch (System.Exception ex)
{
}
Type itemType = taskItem.GetType();
Outlook.FormDescription formDescription = (Outlook.FormDescription)itemType.InvokeMember("FormDescription", System.Reflection.BindingFlags.GetProperty, null, taskItem, null);
// Apply some Parameters to the Formdescription
formDescription.Name = formpropstring;
formDescription.DisplayName = formpropstring;
formDescription.Category = "uncategorized";
formDescription.Comment = formpropstring;
formDescription.Version = "0.0.0.1";
//formDescription.PublishForm(Microsoft.Office.Interop.Outlook.OlFormRegistry.olPersonalRegistry );
formDescription.PublishForm(Microsoft.Office.Interop.Outlook.OlFormRegistry.olFolderRegistry, settaskfolder);
//if (debugmode) writer.WriteToLog("associating complete");
Outlook.PropertyAccessor objPA = settaskfolder.PropertyAccessor;
string strBaseType;
string strMsg;
int intLoc;
bool blnBadForm;
int i;
string PR_DEF_POST_MSGCLASS =
"http://schemas.microsoft.com/mapi/proptag/0x36E5001E";
string PR_DEF_POST_DISPLAYNAME =
"http://schemas.microsoft.com/mapi/proptag/0x36E6001E";
\\string[] arrSchema = { PR_DEF_POST_MSGCLASS, PR_DEF_POST_DISPLAYNAME };
\\string[] arrValues = { "IPM.Task.twoformMssges" , "testassociation" };
\\string[] arrErrors;
try
{
objPA = settaskfolder.PropertyAccessor;
objPA.SetProperty(PR_DEF_POST_MSGCLASS, "IPM.Task.twoformMssges");
objPA.SetProperty(PR_DEF_POST_DISPLAYNAME, "testassociation");
// if (debugmode) writer.WriteToLog("default folder set");
// arrErrors = objPA.SetProperties(arrSchema, arrValues);
}
catch (SystemException sex)
{
Console.WriteLine("This is catch with system exception : {0}", sex.ToString());
}
}
also required a couple of attributes(code in brackets) needs to be added
[Microsoft.Office.Tools.Outlook.FormRegionMessageClass("IPM.Task.twoformMssges")]
[Microsoft.Office.Tools.Outlook.FormRegionName("FormInVsto20136.msgclassregion1")]
public partial class msgclassregion1Factory{ blah blah blah ...
...and that does the trick
(I now wonder how to differentiate between save and update)

C# - How to Authenticate with server dinamically

I need to check if service "Advice" has its status running on said server. I made a method that does just that:
public static bool CheckServicesFromServer(string pServicos)
{
ServiceController service = new ServiceController();
List<string> Servicos = pServicos.Split(',').Select(p => p.Trim()).ToList();
if (Config.BaseLogin == BasesSistema.QualityLogin)
service.MachineName = "quality";
if (Config.BaseLogin == BasesSistema.TS02Login)
service.MachineName = "ts02";
if (Config.BaseLogin == BasesSistema.TS03Login)
service.MachineName = "ts03";
if (Config.BaseLogin == BasesSistema.LocalHost)
service.MachineName = Environment.MachineName;
try
{
foreach (var item in Servicos)
{
service.ServiceName = item;
if ((service.Status.Equals(ServiceControllerStatus.Stopped)) || (service.Status.Equals(ServiceControllerStatus.StopPending)))
{
File.AppendAllText(StatusLog.StatusLocation, "O servico " + service.ServiceName + " está parado. a Regra não será gerada.");
throw new Exception();
}
if (service.Status.Equals(ServiceControllerStatus.Running))
{
File.AppendAllText(StatusLog.StatusLocation, "O serviço " + service.ServiceName + "está rodando perfeitamente.");
}
}
}
catch (Exception e)
{
Log.WriteErrorLog(e.Message);
throw new Exception(e.Message);
}
return true;
}
The thing is, when I run the test, it says "Access Denied", and throws an exception. When I add my user (The user from the computer which is running the application) as an Adm at the server, it runs fine.
Is there a way to authenticate my computer so it can have permission to access the server and check its service status?
Thanks to Krik, I found the solution. It's as simple as addind this class:
using System;
using System.Security.Principal;
using System.Runtime.InteropServices;
using System.Security.Permissions;
public class ImpersonateUser
{
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(
String lpszUsername,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public extern static bool CloseHandle(IntPtr handle);
private static IntPtr tokenHandle = new IntPtr(0);
private static WindowsImpersonationContext impersonatedUser;
// If you incorporate this code into a DLL, be sure to demand that it
// runs with FullTrust.
[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
public void Impersonate(string domainName, string userName, string password)
{
//try
{
// Use the unmanaged LogonUser function to get the user token for
// the specified user, domain, and password.
const int LOGON32_PROVIDER_DEFAULT = 0;
// Passing this parameter causes LogonUser to create a primary token.
const int LOGON32_LOGON_INTERACTIVE = 2;
tokenHandle = IntPtr.Zero;
// ---- Step - 1
// Call LogonUser to obtain a handle to an access token.
bool returnValue = LogonUser(
userName,
domainName,
password,
LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT,
ref tokenHandle); // tokenHandle - new security token
if (false == returnValue)
{
int ret = Marshal.GetLastWin32Error();
throw new System.ComponentModel.Win32Exception(ret);
}
// ---- Step - 2
WindowsIdentity newId = new WindowsIdentity(tokenHandle);
// ---- Step - 3
{
impersonatedUser = newId.Impersonate();
}
}
}
// Stops impersonation
public void Undo()
{
impersonatedUser.Undo();
// Free the tokens.
if (tokenHandle != IntPtr.Zero)
{
CloseHandle(tokenHandle);
}
}
internal void Impersonate()
{
throw new NotImplementedException();
}
}
And I Just had to call it like this:
public static bool CheckServicesFromServer(string pServicos)
{
ImpersonateUser Iu = new ImpersonateUser();
ServiceController service = new ServiceController();
List<string> Servicos = pServicos.Split(',').Select(p => p.Trim()).ToList();
if (Config.BaseLogin == BasesSistema.QualityLogin)
service.MachineName = "quality";
if (Config.BaseLogin == BasesSistema.TS02Login)
service.MachineName = "ts02";
if (Config.BaseLogin == BasesSistema.TS03Login)
service.MachineName = "ts03";
if (Config.BaseLogin == BasesSistema.LocalHost)
service.MachineName = Environment.MachineName;
Iu.Impersonate(Config.Dominio, Config.LoginMaster, Config.SenhaMaster);
try
{
foreach (var item in Servicos)
{
service.ServiceName = item;
if ((service.Status.Equals(ServiceControllerStatus.Stopped)) || (service.Status.Equals(ServiceControllerStatus.StopPending)))
{
Flag = true;
File.AppendAllText(StatusLog.StatusLocation, "O servico " + service.ServiceName + " está parado. a Regra não será gerada. <br />");
throw new Exception();
}
if (service.Status.Equals(ServiceControllerStatus.Running))
{
File.AppendAllText(StatusLog.StatusLocation, "O serviço " + service.ServiceName + " está rodando perfeitamente. <br />");
}
}
Iu.Undo();
}
catch
{
Iu.Undo();
Log.WriteErrorLog("Não é possível abrir o Gerenciador de Controle de Serviços no Computador '" + service.MachineName + "'. <br />");
return false;
}
return true;
}
My Config Class holds the information of the Domain, User and PassWord, and it worked perfectly.

Does Marshal.PtrToStringAnsi not working in windows service?

I have written a dll which call windows spooler api to get printer name and printer driver name, it works fine in console application. However, I got nothing when I call the dll in windows services application.
Here is my dll source code(i.e. printerUtility):
PRINTER_ENUM_LOCAL = 0x00000002,
PRINTER_ENUM_CONNECTIONS = 0x00000004,
public ArrayList getAllLocalPrinterInfo(LogWriter logger)
{
ArrayList printerInfoList = getAllLocalPrinterInfoV2(PrinterEnumFlags.PRINTER_ENUM_LOCAL | PrinterEnumFlags.PRINTER_ENUM_CONNECTIONS);
foreach (PrinterInfoV2 printerInfo in printerInfoList)
{
logger.write("In dll Printer Name pointer:" + printerInfo.pPrinterName+"\nIn dll Printer Name:" + Marshal.PtrToStringAnsi(printerInfo.pPrinterName));
logger.write("In dll Driver Name pointer:" + printerInfo.pDriverName+"\nIn dll Driver Name:" + Marshal.PtrToStringAnsi(printerInfo.pDriverName));
}
//return allLocalPrinterInfo;
return printerInfoList;
}
public ArrayList getAllLocalPrinterInfoV2(PrinterEnumFlags Flags)
{
return enumPrinters(Flags, 2);
}
private ArrayList enumPrinters(PrinterEnumFlags Flags, UInt32 level)
{
bool result;
ArrayList printerInfo = new ArrayList();
UInt32 returned, needed = 0;
UInt32 flags = Convert.ToUInt32(Flags);
//find required size for the buffer
result = EnumPrinters(flags, null, level, IntPtr.Zero, 0, out needed, out returned);
if (Marshal.GetLastWin32Error() != Convert.ToUInt32(CredUIReturnCodes.ERROR_INSUFFICIENT_BUFFER))
{
throw new Exception("EnumPrinters 1 failure, error code=" + Marshal.GetLastWin32Error());
}
else
{
IntPtr buffer = Marshal.AllocHGlobal((int)needed);
result = EnumPrinters(flags, null, level, buffer, needed, out needed, out returned);
if (result)
{
if ((level > 0) || (level < 5))
{
Type type = typeof(PrinterInfoV1);
switch (level)
{
case 1:
type = typeof(PrinterInfoV1);
break;
case 2:
type = typeof(PrinterInfoV2);
break;
case 3:
type = typeof(PrinterInfoV3);
break;
case 4:
type = typeof(PrinterInfoV4);
break;
}
int offset = buffer.ToInt32();
int increment = Marshal.SizeOf(type);
for (int i = 0; i < returned; i++)
{
printerInfo.Add(Marshal.PtrToStructure(new IntPtr(offset), type));
offset += increment;
}
Marshal.FreeHGlobal(buffer);
return printerInfo;
}
else
{
Marshal.FreeHGlobal(buffer);
throw new Exception("The value of level is out of range");
}
}
else
{
Marshal.FreeHGlobal(buffer);
throw new Exception("EnumPrinters 2 failure, error code=" + Marshal.GetLastWin32Error());
}
}
}
[DllImport("winspool.drv", SetLastError = true)]
static extern bool EnumPrinters([InAttribute()] UInt32 Flags,
[InAttribute()] string pPrinterName,
[InAttribute()] UInt32 Level,
[OutAttribute()] IntPtr pPrinter,
[InAttribute()] UInt32 cbBuf,
[OutAttribute()] out UInt32 pcbNeeded,
[OutAttribute()] out UInt32 pcReturned);
The LogWriter Source code:
public class LogWriter
{
EventLog eventLog = null;
public LogWriter(System.Diagnostics.EventLog elog)
{
this.eventLog = elog;
}
public void write(String msg)
{
if (eventLog != null)
{
eventLog.WriteEntry(msg);
}
}
}
Here is services source code:
protected override void OnStart(string[] args)
{
serviceStatus.dwWaitHint = 100000;
serviceStatus.dwCurrentState = ServiceState.SERVICE_START_PENDING;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
printerMonitorList = new ArrayList();
try
{
ArrayList printerInfoList = printerUtility.getAllLocalPrinterInfo(logger);
foreach (PrinterInfoV2 printerInfo in printerInfoList)
{
logger.write("In service Printer Name pointer:" + printerInfo.pPrinterName+"\nIn service Printer Name:" + Marshal.PtrToStringAnsi(printerInfo.pPrinterName));
logger.write("In service Driver Name pointer:" + printerInfo.pDriverName+"\nIn service Driver Name:" + Marshal.PtrToStringAnsi(printerInfo.pDriverName));
}
serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
logger.write(this.ServiceName + " Has Been Started");
}
catch (Exception err)
{
logger.write("Print Alert Service cannot be started:"+err.Message);
}
In event viewer, I got an empty string for both printer name and printer driver name.
However, I found that the dll return a pointer for both printer name and printer driver name. Therefore, I suspect whether the Marshal.PtrToStringAnsi function not working in window services environment.

Check if COM+ application is already running?

Is it possible in C# (4.0) to get the list of installed Com+ applications on the same box and then retrieve the status (Running/Shut down) of each of them?
I can find methods to start/stop, but not retrieve status.
I think the COM+ Administrative components only lets you query the "static" configuration properties (e.g. Identity, IsEnabled) and doesn't let you query the dynamic properties of COM+ (e.g. PID).
The only way I found to do what you want is using the COMSVCSLib (COM+ Services Type Library).
UPDATE: Based on #Vagaus's comment, we can use either COM+ Administrative components or COM+ Services Type Library!
With quite a bit of help from the article Comonitor - A COM+ Monitor. I've cobbled together some code that uses COM+ Services Type Library:
public static bool IsComPlusApplicationRunning(string appName)
{
int appDataSize = Marshal.SizeOf(typeof(COMSVCSLib.appData));
Type appDataType = typeof(COMSVCSLib.appData);
uint appCount;
IntPtr appDataPtr = IntPtr.Zero;
GCHandle gh = GCHandle.Alloc(appDataPtr, GCHandleType.Pinned);
IntPtr addressOfAppDataPtr = gh.AddrOfPinnedObject();
COMSVCSLib.IGetAppData getAppData = null;
COMSVCSLib.TrackerServer tracker = null;
try
{
tracker = new COMSVCSLib.TrackerServerClass();
getAppData = (COMSVCSLib.IGetAppData)tracker;
getAppData.GetApps(out appCount, addressOfAppDataPtr);
appDataPtr = new IntPtr(Marshal.ReadInt32(addressOfAppDataPtr));
for (int appIndex = 0; appIndex < appCount; appIndex++)
{
COMSVCSLib.appData appData = (COMSVCSLib.appData)Marshal.PtrToStructure(
new IntPtr(appDataPtr.ToInt32() + (appIndex * appDataSize)),
appDataType);
string currentAppName = GetPackageNameByPID(appData.m_dwAppProcessId);
if (string.Compare(currentAppName, appName, StringComparison.OrdinalIgnoreCase) == 0)
{
Console.WriteLine("Application " + appName + " is running with PID " + appData.m_dwAppProcessId);
return true;
}
}
}
finally
{
Marshal.FreeCoTaskMem(appDataPtr);
if (tracker != null)
{
Marshal.ReleaseComObject(tracker);
}
gh.Free();
}
return false;
}
private static string GetPackageNameByPID(uint PID)
{
COMSVCSLib.MtsGrp grpObj = new COMSVCSLib.MtsGrpClass();
try
{
object obj = null;
COMSVCSLib.COMEvents eventObj = null;
for (int i = 0; i < grpObj.Count; i++)
{
try
{
grpObj.Item(i, out obj);
eventObj = (COMSVCSLib.COMEvents)obj;
if (eventObj.GetProcessID() == PID)
{
return eventObj.PackageName;
}
}
finally
{
if (obj != null)
{
Marshal.ReleaseComObject(obj);
}
}
}
}
finally
{
if (grpObj != null)
{
Marshal.ReleaseComObject(grpObj);
}
}
return null;
}
But we can also use the COM+ Administrative components (which seems simpler) to do the same thing:
public static bool IsComPlusApplicationRunning(string appName)
{
COMAdmin.COMAdminCatalog catalog = new COMAdmin.COMAdminCatalogClass();
COMAdmin.ICatalogCollection appCollection = (COMAdmin.ICatalogCollection)catalog.GetCollection("Applications");
appCollection.Populate();
Dictionary<string, string> apps = new Dictionary<string, string>();
COMAdmin.ICatalogObject catalogObject = null;
// Get the names of the applications with their ID and store for later
for (int i = 0; i < appCollection.Count; i++)
{
catalogObject = (COMAdmin.ICatalogObject)appCollection.get_Item(i);
apps.Add(catalogObject.get_Value("ID").ToString(), catalogObject.Name.ToString());
}
appCollection = (COMAdmin.ICatalogCollection)catalog.GetCollection("ApplicationInstances");
appCollection.Populate();
for (int i = 0; i < appCollection.Count; i++)
{
catalogObject = (COMAdmin.ICatalogObject)appCollection.get_Item(i);
if (string.Compare(appName, apps[catalogObject.get_Value("Application").ToString()], StringComparison.OrdinalIgnoreCase) == 0)
{
Console.WriteLine(appName + " is running with PID: " + catalogObject.get_Value("ProcessID").ToString());
return true;
}
}
return false;
}
Have you checked the COM+ administration components? I'd bet that you can find this information using these interfaces.
Best

Categories